diff --git a/include/config.h b/include/config.h index 3c086d0..500f248 100644 --- a/include/config.h +++ b/include/config.h @@ -22,4 +22,16 @@ #define MAX_MILLIAMPS 1000 +#define WIFI_SSID "..." +#define WIFI_PASS "..." + +#define MQTT_CLIENT_ID "espleaf" +#define MQTT_USER "..." +#define MQTT_PASS "..." +#define MQTT_SERVER "..." +#define MQTT_SERVER_PORT 1883 +#define MQTT_TOPIC_STATE "espleaf/state" +#define MQTT_TOPIC_STATE_LONG "espleaf/state_long" +#define MQTT_TOPIC_COMMANDS "esplead/cmnd" + //#define TEST_MODE \ No newline at end of file diff --git a/include/config.sample.h b/include/config.sample.h new file mode 100644 index 0000000..500f248 --- /dev/null +++ b/include/config.sample.h @@ -0,0 +1,37 @@ +#pragma once + +#define CORNERS_PER_PART 3 +#define LEDS_PER_CORNER 2 + +// Layout definition +// Every node has EDGES_PER_PART corners and edges. +// The edge the signal comes in is edge number 0. +// All other edges are numbered counter-clockwise. +// LAYOUT contains a list of edges the signal takes. +// First node is implied. + +// Examples, assuming EDGES_PER_PART == 3: +// Example: Nodes arranged in a circle: {1, 2, 2, 2, 2} +// Example: Nodes arranged in a line: {1, 2, 1, 2, 1, 2} +#define NODE_COUNT 5 +#define LAYOUT {2, 1, 1, 2} + +#define LED_COUNT NODE_COUNT * CORNERS_PER_PART * LEDS_PER_CORNER + +#define SPEEDUP 1 + +#define MAX_MILLIAMPS 1000 + +#define WIFI_SSID "..." +#define WIFI_PASS "..." + +#define MQTT_CLIENT_ID "espleaf" +#define MQTT_USER "..." +#define MQTT_PASS "..." +#define MQTT_SERVER "..." +#define MQTT_SERVER_PORT 1883 +#define MQTT_TOPIC_STATE "espleaf/state" +#define MQTT_TOPIC_STATE_LONG "espleaf/state_long" +#define MQTT_TOPIC_COMMANDS "esplead/cmnd" + +//#define TEST_MODE \ No newline at end of file diff --git a/include/mqtt.h b/include/mqtt.h new file mode 100644 index 0000000..3d298d0 --- /dev/null +++ b/include/mqtt.h @@ -0,0 +1,10 @@ +#pragma once + +#include "wifi.h" +#include "config.h" +#include + +static PubSubClient mqtt(wifi); + +void mqtt_setup(); +void mqtt_loop(); \ No newline at end of file diff --git a/include/prototypes.h b/include/prototypes.h index 06919f8..e77fbec 100644 --- a/include/prototypes.h +++ b/include/prototypes.h @@ -20,4 +20,9 @@ enum AnimationMode { AM_NODES, AM_FIRST_NODE, AM_FLASH -}; \ No newline at end of file +}; + +extern AnimationMode mode; +extern AnimationMode temp_mode; +extern unsigned long temp_mode_until; + diff --git a/include/wifi.h b/include/wifi.h new file mode 100644 index 0000000..44632dc --- /dev/null +++ b/include/wifi.h @@ -0,0 +1,8 @@ +#pragma once + +#include +#include "config.h" + +static WiFiClient wifi; + +void wifi_setup(); \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index fb83f2c..e6fbced 100644 --- a/platformio.ini +++ b/platformio.ini @@ -17,4 +17,5 @@ upload_speed = 921600 monitor_port = /dev/cu.wchusbserial* monitor_speed = 74880 monitor_filters = default, time, send_on_enter, esp8266_exception_decoder -lib_deps = FastLED \ No newline at end of file +lib_deps = fastled/FastLED @ 3.4.0 + PubSubClient \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 6c9d030..e5d312e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7,6 +7,7 @@ #include "edge.h" #include "corner.h" #include "prototypes.h" +#include "mqtt.h" std::vector nodes; std::list edges; @@ -15,6 +16,8 @@ std::vector corners; CRGB leds[LED_COUNT]; AnimationMode mode = AM_CORNERS; +AnimationMode temp_mode; +unsigned long temp_mode_until; unsigned long last_loop = 0; @@ -76,7 +79,7 @@ void setup_fastled() { set_all_leds(CRGB::Black); } -void setup_wifi() { +void setup_rng() { LOGln("Starting WiFi scan for RNG initialization..."); WiFi.mode(WIFI_STA); WiFi.disconnect(); @@ -97,11 +100,15 @@ void setup() { setup_layout(); setup_fastled(); - setup_wifi(); - #ifdef TEST_MODE LOGln("TEST_MODE is active!"); + #else + setup_rng(); + + wifi_setup(); + mqtt_setup(); #endif + } void loop() { @@ -119,13 +126,23 @@ void loop() { } #else // Normal mode + mqtt_loop(); EVERY_N_MILLISECONDS(20 / SPEEDUP) { looping = false; - if (mode == AM_CORNERS || mode == AM_FIRST_CORNER) { + AnimationMode active_mode = mode; + if (temp_mode_until > 0) { + if (temp_mode_until>millis()) { + active_mode = temp_mode; + } else { + temp_mode_until = 0; + } + } + + if (active_mode == AM_CORNERS || active_mode == AM_FIRST_CORNER) { for(Corner* corner: corners) { corner->step(); - if (mode == AM_FIRST_CORNER) { + if (active_mode == AM_FIRST_CORNER) { corner->infect(512, 512); } else { corner->infect(300, 600); @@ -135,13 +152,13 @@ void loop() { } if (random8(128)==0) { - if (mode == AM_FIRST_CORNER) { + if (active_mode == AM_FIRST_CORNER) { corners[0]->blend_to(CHSV(random8(), 255, 255)); } else { corners[random16(corners.size())]->blend_to(CHSV(random8(), 255, 255)); } } - } else if (mode == AM_NODES || mode == AM_FIRST_NODE) { + } else if (active_mode == AM_NODES || active_mode == AM_FIRST_NODE) { for(Node* node : nodes) { node->step(); node->infect(512); @@ -149,13 +166,13 @@ void loop() { } if (random8(128)==0) { - if (mode == AM_FIRST_NODE) { + if (active_mode == AM_FIRST_NODE) { nodes[0]->blend_to(CHSV(random8(), 255, 255)); } else { nodes[random8(nodes.size())]->blend_to(CHSV(random8(), 255, 255)); } } - } else if (mode == AM_FLASH) { + } else if (active_mode == AM_FLASH) { for (Node* node : nodes) { node->step(); node->infect(512); diff --git a/src/mqtt.cpp b/src/mqtt.cpp new file mode 100644 index 0000000..2fcc05f --- /dev/null +++ b/src/mqtt.cpp @@ -0,0 +1,53 @@ +#include "mqtt.h" +#include "tools.h" +#include "prototypes.h" + +void connect() { +LOGln("Connecting to MQTT broker..."); + if (mqtt.connect(MQTT_CLIENT_ID, MQTT_USER, MQTT_PASS, MQTT_TOPIC_STATE, 0, true, "OFFLINE")) { + LOGln("Connected."); + mqtt.publish(MQTT_TOPIC_STATE, "ONLINE", true); + char buffer[40]; + snprintf(buffer, 40, "ONLINE %s", wifi.localIP().toString().c_str()); + mqtt.publish(MQTT_TOPIC_STATE_LONG, buffer, true); + mqtt.subscribe(MQTT_TOPIC_COMMANDS); + } else { + LOGln("Connection failed. Reason: %d", mqtt.state()); + delay(1000); + } +} + +void callback(char* topic, byte* pl, unsigned int length) { + pl[length] = 0; + String payload((char*)pl); + uint16_t duration = 0; + int cp = payload.indexOf(","); + if (cp != -1) { + duration = payload.substring(cp+1).toInt(); + payload = payload.substring(0, cp); + } + AnimationMode am; + if (payload.equals("corners")) am = AM_CORNERS; + else if (payload.equals("nodes")) am = AM_NODES; + + if (duration > 0) { + temp_mode = am; + temp_mode_until = millis() + duration*1000; + } else { + mode = am; + } +} + +void mqtt_setup() { + mqtt.setServer(MQTT_SERVER, MQTT_SERVER_PORT); + mqtt.setCallback(callback); + mqtt.setSocketTimeout(1); + connect(); +} + +void mqtt_loop() { + if (!mqtt.connected()) { + connect(); + } + mqtt.loop(); +} \ No newline at end of file diff --git a/src/wifi.cpp b/src/wifi.cpp new file mode 100644 index 0000000..52b6012 --- /dev/null +++ b/src/wifi.cpp @@ -0,0 +1,13 @@ +#include "wifi.h" +#include "tools.h" + +void wifi_setup() { + LOG("Connecting to WiFi %s...", WIFI_SSID); + WiFi.mode(WIFI_STA); + WiFi.begin(WIFI_SSID, WIFI_PASS); + while (WiFi.status() != WL_CONNECTED) { + LOG("."); + delay(300); + } + LOGln(" Connected as %s", WiFi.localIP().toString().c_str()); +} \ No newline at end of file