diff --git a/Arduino/McLighting/McLighting.ino b/Arduino/McLighting/McLighting.ino index 432e395..0b877de 100644 --- a/Arduino/McLighting/McLighting.ino +++ b/Arduino/McLighting/McLighting.ino @@ -13,6 +13,7 @@ #include #include #include +#include #include //https://github.com/Links2004/arduinoWebSockets #include @@ -23,10 +24,19 @@ #include #endif +// MQTT +#ifdef ENABLE_MQTT + #include + + WiFiClient espClient; + PubSubClient mqtt_client(espClient); +#endif + + // *************************************************************************** // Instanciate HTTP(80) / WebSockets(81) Server // *************************************************************************** -ESP8266WebServer server ( 80 ); +ESP8266WebServer server(80); WebSocketsServer webSocket = WebSocketsServer(81); @@ -65,6 +75,38 @@ void tick() } +// *************************************************************************** +// EEPROM helper +// *************************************************************************** +String readEEPROM(int offset, int len) { + String res = ""; + for (int i = 0; i < len; ++i) + { + res += char(EEPROM.read(i + offset)); + //DBG_OUTPUT_PORT.println(char(EEPROM.read(i + offset))); + } + + //DBG_OUTPUT_PORT.print("Read EEPROM: ["); + //DBG_OUTPUT_PORT.print(res); + //DBG_OUTPUT_PORT.println("]"); + return res; +} + +void writeEEPROM(int offset, int len, String value) { + for (int i = 0; i < len; ++i) + { + if (i < value.length()) { + EEPROM.write(i + offset, value[i]); + } else { + EEPROM.write(i + offset, NULL); + } + + DBG_OUTPUT_PORT.print("Wrote EEPROM: "); + DBG_OUTPUT_PORT.println(value[i]); + } +} + + // *************************************************************************** // Callback for WiFiManager library when config mode is entered // *************************************************************************** @@ -84,7 +126,11 @@ void configModeCallback (WiFiManager *myWiFiManager) { strip.show(); } - +//callback notifying us of the need to save config +void saveConfigCallback () { + DBG_OUTPUT_PORT.println("Should save config"); + shouldSaveConfig = true; +} // *************************************************************************** // Include: Webserver @@ -108,11 +154,12 @@ void configModeCallback (WiFiManager *myWiFiManager) { // *************************************************************************** void setup() { DBG_OUTPUT_PORT.begin(115200); + EEPROM.begin(512); // set builtin led pin as output pinMode(BUILTIN_LED, OUTPUT); // start ticker with 0.5 because we start in AP mode and try to connect - ticker.attach(0.6, tick); + ticker.attach(0.5, tick); // *************************************************************************** // Setup: Neopixel @@ -127,6 +174,28 @@ void setup() { // *************************************************************************** // Setup: WiFiManager // *************************************************************************** + // The extra parameters to be configured (can be either global or just in the setup) + // After connecting, parameter.getValue() will get you the configured value + // id/name placeholder/prompt default length + #ifdef ENABLE_MQTT + String settings_available = readEEPROM(134, 1); + if (settings_available == "1") { + readEEPROM(0, 64).toCharArray(mqtt_host, 64); // 0-63 + readEEPROM(64, 6).toCharArray(mqtt_port, 6); // 64-69 + readEEPROM(70, 32).toCharArray(mqtt_user, 32); // 70-101 + readEEPROM(102, 32).toCharArray(mqtt_pass, 32); // 102-133 + DBG_OUTPUT_PORT.printf("MQTT host: %s\n", mqtt_host); + DBG_OUTPUT_PORT.printf("MQTT port: %s\n", mqtt_port); + DBG_OUTPUT_PORT.printf("MQTT user: %s\n", mqtt_user); + DBG_OUTPUT_PORT.printf("MQTT pass: %s\n", mqtt_pass); + } + + WiFiManagerParameter custom_mqtt_host("host", "MQTT hostname", mqtt_host, 64); + WiFiManagerParameter custom_mqtt_port("port", "MQTT port", mqtt_port, 6); + WiFiManagerParameter custom_mqtt_user("user", "MQTT user", mqtt_user, 32); + WiFiManagerParameter custom_mqtt_pass("pass", "MQTT pass", mqtt_pass, 32); + #endif + //Local intialization. Once its business is done, there is no need to keep it around WiFiManager wifiManager; //reset settings - for testing @@ -135,6 +204,17 @@ void setup() { //set callback that gets called when connecting to previous WiFi fails, and enters Access Point mode wifiManager.setAPCallback(configModeCallback); + #ifdef ENABLE_MQTT + //set config save notify callback + wifiManager.setSaveConfigCallback(saveConfigCallback); + + //add all your parameters here + wifiManager.addParameter(&custom_mqtt_host); + wifiManager.addParameter(&custom_mqtt_port); + wifiManager.addParameter(&custom_mqtt_user); + wifiManager.addParameter(&custom_mqtt_pass); + #endif + //fetches ssid and pass and tries to connect //if it does not connect it starts an access point with the specified name //here "AutoConnectAP" @@ -146,6 +226,26 @@ void setup() { delay(1000); } + #ifdef ENABLE_MQTT + //read updated parameters + strcpy(mqtt_host, custom_mqtt_host.getValue()); + strcpy(mqtt_port, custom_mqtt_port.getValue()); + strcpy(mqtt_user, custom_mqtt_user.getValue()); + strcpy(mqtt_pass, custom_mqtt_pass.getValue()); + + //save the custom parameters to FS + if (shouldSaveConfig) { + DBG_OUTPUT_PORT.println("Saving WiFiManager config"); + + writeEEPROM(0, 64, mqtt_host); // 0-63 + writeEEPROM(64, 6, mqtt_port); // 64-69 + writeEEPROM(70, 32, mqtt_user); // 70-101 + writeEEPROM(102, 32, mqtt_pass); // 102-133 + writeEEPROM(134, 1, "1"); // 134 --> alwasy "1" + EEPROM.commit(); + } + #endif + //if you get here you have connected to the WiFi DBG_OUTPUT_PORT.println("connected...yeey :)"); ticker.detach(); @@ -195,6 +295,20 @@ void setup() { #endif + // *************************************************************************** + // Configure MQTT + // *************************************************************************** + #ifdef ENABLE_MQTT + String(String(HOSTNAME) + "/in").toCharArray(mqtt_intopic, strlen(HOSTNAME) + 3); + String(String(HOSTNAME) + "/out").toCharArray(mqtt_outtopic, strlen(HOSTNAME) + 4); + + DBG_OUTPUT_PORT.printf("Connect %s %d\n", mqtt_host, String(mqtt_port).toInt()); + + mqtt_client.setServer(mqtt_host, String(mqtt_port).toInt()); + mqtt_client.setCallback(mqtt_callback); + #endif + + // *************************************************************************** // Setup: MDNS responder // *************************************************************************** @@ -205,13 +319,14 @@ void setup() { DBG_OUTPUT_PORT.print("Use http://"); DBG_OUTPUT_PORT.print(HOSTNAME); - DBG_OUTPUT_PORT.println(".local/ when you have Bobjour installed."); + DBG_OUTPUT_PORT.println(".local/ when you have Bonjour installed."); DBG_OUTPUT_PORT.print("New users: Open http://"); DBG_OUTPUT_PORT.print(WiFi.localIP()); DBG_OUTPUT_PORT.println("/upload to upload the webpages first."); DBG_OUTPUT_PORT.println(""); + // *************************************************************************** // Setup: WebSocket server @@ -412,6 +527,13 @@ void loop() { ArduinoOTA.handle(); #endif + #ifdef ENABLE_MQTT + if (!mqtt_client.connected()) { + mqtt_reconnect(); + } + mqtt_client.loop(); + #endif + // Simple statemachine that handles the different modes if (mode == SET_MODE) { DBG_OUTPUT_PORT.printf("SET_MODE: %d %d\n", ws2812fx_mode, mode); diff --git a/Arduino/McLighting/colormodes.h b/Arduino/McLighting/colormodes.h index 33d7bf9..aa7c48b 100644 --- a/Arduino/McLighting/colormodes.h +++ b/Arduino/McLighting/colormodes.h @@ -17,12 +17,13 @@ int analogLevel = 100; boolean timeToDip = false; int ledStates[NUMLEDS]; + void hsb2rgbAN1(uint16_t index, uint8_t sat, uint8_t bright, uint8_t myled) { // Source: https://blog.adafruit.com/2012/03/14/constant-brightness-hsb-to-rgb-algorithm/ uint8_t temp[5], n = (index >> 8) % 3; - temp[0] = temp[3] = (uint8_t)(( (sat ^ 255) * bright) / 255); + temp[0] = temp[3] = (uint8_t)(( (sat ^ 255) * bright) / 255); temp[1] = temp[4] = (uint8_t)((((( (index & 255) * sat) / 255) + (sat ^ 255)) * bright) / 255); - temp[2] = (uint8_t)(((((((index & 255) ^ 255) * sat) / 255) + (sat ^ 255)) * bright) / 255); + temp[2] = (uint8_t)(((((((index & 255) ^ 255) * sat) / 255) + (sat ^ 255)) * bright) / 255); strip.setPixelColor(myled, temp[n + 2], temp[n + 1], temp[n]); } diff --git a/Arduino/McLighting/definitions.h b/Arduino/McLighting/definitions.h index 8481c9a..97c6cdd 100644 --- a/Arduino/McLighting/definitions.h +++ b/Arduino/McLighting/definitions.h @@ -1,11 +1,25 @@ // Neopixel #define PIN 5 // PIN where neopixel / WS2811 strip is attached -#define NUMLEDS 60 // Number of leds in the strip +#define NUMLEDS 24 // Number of leds in the strip -#define HOSTNAME "ESP8266_02" // Friedly hostname +const char HOSTNAME[] = "ESP8266_VORONOI"; // Friedly hostname -// #define ENABLE_OTA // If defined, enable Arduino OTA code. +#define ENABLE_OTA // If defined, enable Arduino OTA code. + +#define ENABLE_MQTT // If defined, enable MQTT client code. +#ifdef ENABLE_MQTT + #define MQTT_MAX_PACKET_SIZE 256 + char mqtt_intopic[strlen(HOSTNAME) + 3]; // Topic in will be: /in + char mqtt_outtopic[strlen(HOSTNAME) + 4]; // Topic out will be: /out + + const char mqtt_clientid[] = "ESP8266Client"; // MQTT ClientID + + char mqtt_host[64] = ""; + char mqtt_port[6] = ""; + char mqtt_user[32] = ""; + char mqtt_pass[32] = ""; +#endif // *************************************************************************** @@ -16,15 +30,17 @@ // List of all color modes enum MODE { SET_MODE, HOLD, OFF, ALL, WIPE, RAINBOW, RAINBOWCYCLE, THEATERCHASE, THEATERCHASERAINBOW, TV }; -MODE mode = RAINBOW; // Standard mode that is active when software starts +MODE mode = RAINBOW; // Standard mode that is active when software starts -int ws2812fx_speed = 10; // Global variable for storing the delay between color changes --> smaller == faster +int ws2812fx_speed = 10; // Global variable for storing the delay between color changes --> smaller == faster int brightness = 192; // Global variable for storing the brightness (255 == 100%) int ws2812fx_mode = 0; // Helper variable to set WS2812FX modes bool exit_func = false; // Global helper variable to get out of the color modes when mode changes +bool shouldSaveConfig = false; // For WiFiManger custom config + struct ledstate // Data structure to store a state of a single led { uint8_t red; diff --git a/Arduino/McLighting/request_handlers.h b/Arduino/McLighting/request_handlers.h index 86a511f..eb399ab 100644 --- a/Arduino/McLighting/request_handlers.h +++ b/Arduino/McLighting/request_handlers.h @@ -37,47 +37,92 @@ void getArgs() { DBG_OUTPUT_PORT.println(brightness); } -void handleMinimalUpload() { - char temp[1500]; - int sec = millis() / 1000; - int min = sec / 60; - int hr = min / 60; - snprintf ( temp, 1500, - "\ - \ - \ - ESP8266 Upload\ - \ - \ - \ - \ - \ -
\ - \ - \ - \ -
\ - \ - ", - hr, min % 60, sec % 60 - ); - server.send ( 200, "text/html", temp ); +// *************************************************************************** +// Handler functions for WS and MQTT +// *************************************************************************** +void handleSetMainColor(uint8_t * mypayload) { + // decode rgb data + uint32_t rgb = (uint32_t) strtol((const char *) &mypayload[1], NULL, 16); + main_color.red = ((rgb >> 16) & 0xFF); + main_color.green = ((rgb >> 8) & 0xFF); + main_color.blue = ((rgb >> 0) & 0xFF); + strip.setColor(main_color.red, main_color.green, main_color.blue); } -void handleNotFound() { - String message = "File Not Found\n\n"; - message += "URI: "; - message += server.uri(); - message += "\nMethod: "; - message += ( server.method() == HTTP_GET ) ? "GET" : "POST"; - message += "\nArguments: "; - message += server.args(); - message += "\n"; - for ( uint8_t i = 0; i < server.args(); i++ ) { - message += " " + server.argName ( i ) + ": " + server.arg ( i ) + "\n"; +void handleSetAllMode(uint8_t * mypayload) { + // decode rgb data + uint32_t rgb = (uint32_t) strtol((const char *) &mypayload[1], NULL, 16); + + main_color.red = ((rgb >> 16) & 0xFF); + main_color.green = ((rgb >> 8) & 0xFF); + main_color.blue = ((rgb >> 0) & 0xFF); + + for (int i = 0; i < strip.numPixels(); i++) { + strip.setPixelColor(i, main_color.red, main_color.green, main_color.blue); } - server.send ( 404, "text/plain", message ); + strip.show(); + DBG_OUTPUT_PORT.printf("WS: Set all leds to main color: [%u] [%u] [%u]\n", main_color.red, main_color.green, main_color.blue); + exit_func = true; + mode = ALL; +} + +void handleSetSingleLED(uint8_t * mypayload) { + // decode led index + uint64_t rgb = (uint64_t) strtol((const char *) &mypayload[1], NULL, 16); + + uint8_t led = ((rgb >> 24) & 0xFF); + if (led < strip.numPixels()) { + ledstates[led].red = ((rgb >> 16) & 0xFF); + ledstates[led].green = ((rgb >> 8) & 0xFF); + ledstates[led].blue = ((rgb >> 0) & 0xFF); + DBG_OUTPUT_PORT.printf("WS: Set single led [%u] to [%u] [%u] [%u]!\n", led, ledstates[led].red, ledstates[led].green, ledstates[led].blue); + + for (uint8_t i = 0; i < strip.numPixels(); i++) { + strip.setPixelColor(i, ledstates[i].red, ledstates[i].green, ledstates[i].blue); + //DBG_OUTPUT_PORT.printf("[%u]--[%u] [%u] [%u] [%u] LED index!\n", rgb, i, ledstates[i].red, ledstates[i].green, ledstates[i].blue); + } + strip.show(); + } + exit_func = true; + mode = ALL; +} + +void handleSetNamedMode(String str_mode) { + exit_func = true; + + if (str_mode.startsWith("=off")) { + mode = OFF; + } + if (str_mode.startsWith("=all")) { + mode = ALL; + } + if (str_mode.startsWith("=wipe")) { + mode = WIPE; + } + if (str_mode.startsWith("=rainbow")) { + mode = RAINBOW; + } + if (str_mode.startsWith("=rainbowCycle")) { + mode = RAINBOWCYCLE; + } + if (str_mode.startsWith("=theaterchase")) { + mode = THEATERCHASE; + } + if (str_mode.startsWith("=theaterchaseRainbow")) { + mode = THEATERCHASERAINBOW; + } + if (str_mode.startsWith("=tv")) { + mode = TV; + } +} + +void handleSetWS2812FXMode(uint8_t * mypayload) { + mode = HOLD; + uint8_t ws2812fx_mode = (uint8_t) strtol((const char *) &mypayload[1], NULL, 10); + ws2812fx_mode = constrain(ws2812fx_mode, 0, 255); + strip.setColor(main_color.red, main_color.green, main_color.blue); + strip.setMode(ws2812fx_mode); } char* listStatusJSON() { @@ -107,6 +152,57 @@ void getModesJSON() { server.send ( 200, "application/json", listModesJSON() ); } + +// *************************************************************************** +// HTTP request handlers +// *************************************************************************** +void handleMinimalUpload() { + char temp[1500]; + int sec = millis() / 1000; + int min = sec / 60; + int hr = min / 60; + + snprintf ( temp, 1500, + "\ + \ + \ + ESP8266 Upload\ + \ + \ + \ + \ + \ +
\ + \ + \ + \ +
\ + \ + ", + hr, min % 60, sec % 60 + ); + server.send ( 200, "text/html", temp ); +} + +void handleNotFound() { + String message = "File Not Found\n\n"; + message += "URI: "; + message += server.uri(); + message += "\nMethod: "; + message += ( server.method() == HTTP_GET ) ? "GET" : "POST"; + message += "\nArguments: "; + message += server.args(); + message += "\n"; + for ( uint8_t i = 0; i < server.args(); i++ ) { + message += " " + server.argName ( i ) + ": " + server.arg ( i ) + "\n"; + } + server.send ( 404, "text/plain", message ); +} + + +// *************************************************************************** +// WS request handlers +// *************************************************************************** void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t lenght) { switch (type) { case WStype_DISCONNECTED: @@ -127,17 +223,12 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t lenght // # ==> Set main color if (payload[0] == '#') { - // decode rgb data - uint32_t rgb = (uint32_t) strtol((const char *) &payload[1], NULL, 16); - main_color.red = ((rgb >> 16) & 0xFF); - main_color.green = ((rgb >> 8) & 0xFF); - main_color.blue = ((rgb >> 0) & 0xFF); - strip.setColor(main_color.red, main_color.green, main_color.blue); + handleSetMainColor(payload); DBG_OUTPUT_PORT.printf("Set main color to: [%u] [%u] [%u]\n", main_color.red, main_color.green, main_color.blue); webSocket.sendTXT(num, "OK"); } - // # ==> Set speed + // ? ==> Set speed if (payload[0] == '?') { uint8_t d = (uint8_t) strtol((const char *) &payload[1], NULL, 10); ws2812fx_speed = constrain(d, 0, 255); @@ -146,7 +237,7 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t lenght webSocket.sendTXT(num, "OK"); } - // # ==> Set brightness + // % ==> Set brightness if (payload[0] == '%') { uint8_t b = (uint8_t) strtol((const char *) &payload[1], NULL, 10); brightness = ((b >> 0) & 0xFF); @@ -155,79 +246,24 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t lenght webSocket.sendTXT(num, "OK"); } - // * ==> Set main color and light all LEDs (Shortcut) if (payload[0] == '*') { - // decode rgb data - uint32_t rgb = (uint32_t) strtol((const char *) &payload[1], NULL, 16); - - main_color.red = ((rgb >> 16) & 0xFF); - main_color.green = ((rgb >> 8) & 0xFF); - main_color.blue = ((rgb >> 0) & 0xFF); - - for (int i = 0; i < strip.numPixels(); i++) { - strip.setPixelColor(i, main_color.red, main_color.green, main_color.blue); - } - strip.show(); - DBG_OUTPUT_PORT.printf("WS: Set all leds to main color: [%u] [%u] [%u]\n", main_color.red, main_color.green, main_color.blue); - exit_func = true; - mode = ALL; + handleSetAllMode(payload); webSocket.sendTXT(num, "OK"); } // ! ==> Set single LED in given color if (payload[0] == '!') { - // decode led index - uint64_t rgb = (uint64_t) strtol((const char *) &payload[1], NULL, 16); - - uint8_t led = ((rgb >> 24) & 0xFF); - if (led < strip.numPixels()) { - ledstates[led].red = ((rgb >> 16) & 0xFF); - ledstates[led].green = ((rgb >> 8) & 0xFF); - ledstates[led].blue = ((rgb >> 0) & 0xFF); - DBG_OUTPUT_PORT.printf("WS: Set single led [%u] to [%u] [%u] [%u]!\n", led, ledstates[led].red, ledstates[led].green, ledstates[led].blue); - - for (uint8_t i = 0; i < strip.numPixels(); i++) { - strip.setPixelColor(i, ledstates[i].red, ledstates[i].green, ledstates[i].blue); - //DBG_OUTPUT_PORT.printf("[%u]--[%u] [%u] [%u] [%u] LED index!\n", rgb, i, ledstates[i].red, ledstates[i].green, ledstates[i].blue); - } - strip.show(); - } - exit_func = true; - mode = ALL; + handleSetSingleLED(payload); webSocket.sendTXT(num, "OK"); } - // ! ==> Activate mode + // = ==> Activate named mode if (payload[0] == '=') { // we get mode data String str_mode = String((char *) &payload[0]); - exit_func = true; - if (str_mode.startsWith("=off")) { - mode = OFF; - } - if (str_mode.startsWith("=all")) { - mode = ALL; - } - if (str_mode.startsWith("=wipe")) { - mode = WIPE; - } - if (str_mode.startsWith("=rainbow")) { - mode = RAINBOW; - } - if (str_mode.startsWith("=rainbowCycle")) { - mode = RAINBOWCYCLE; - } - if (str_mode.startsWith("=theaterchase")) { - mode = THEATERCHASE; - } - if (str_mode.startsWith("=theaterchaseRainbow")) { - mode = THEATERCHASERAINBOW; - } - if (str_mode.startsWith("=tv")) { - mode = TV; - } + handleSetNamedMode(str_mode); DBG_OUTPUT_PORT.printf("Activated mode [%u]!\n", mode); webSocket.sendTXT(num, "OK"); @@ -242,7 +278,7 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t lenght webSocket.sendTXT(num, json); } - // $ ==> Get WS2812 modes. + // ~ ==> Get WS2812 modes. if (payload[0] == '~') { DBG_OUTPUT_PORT.printf("Get WS2812 modes."); @@ -251,16 +287,9 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t lenght webSocket.sendTXT(num, json); } - // $ ==> Set WS2812 mode. + // / ==> Set WS2812 mode. if (payload[0] == '/') { - mode = HOLD; - uint8_t ws2812fx_mode = (uint8_t) strtol((const char *) &payload[1], NULL, 10); - ws2812fx_mode = constrain(ws2812fx_mode, 0, 255); - strip.setColor(main_color.red, main_color.green, main_color.blue); - strip.setMode(ws2812fx_mode); - - //String json = listStatusJSON(); - //DBG_OUTPUT_PORT.println(json); + handleSetWS2812FXMode(payload); webSocket.sendTXT(num, "OK"); } break; @@ -271,3 +300,116 @@ void checkForRequests() { webSocket.loop(); server.handleClient(); } + + +// *************************************************************************** +// MQTT callback / connection handler +// *************************************************************************** +#ifdef ENABLE_MQTT + void mqtt_callback(char* topic, byte* payload_in, unsigned int length) { + uint8_t * payload = (uint8_t *)malloc(length + 1); + memcpy(payload, payload_in, length); + payload[length] = NULL; + DBG_OUTPUT_PORT.printf("MQTT: Message arrived [%s]\n", payload); + + // # ==> Set main color + if (payload[0] == '#') { + handleSetMainColor(payload); + DBG_OUTPUT_PORT.printf("MQTT: Set main color to [%u] [%u] [%u]\n", main_color.red, main_color.green, main_color.blue); + mqtt_client.publish(mqtt_outtopic, String(String("OK ") + String((char *)payload)).c_str()); + } + + // ? ==> Set speed + if (payload[0] == '?') { + uint8_t d = (uint8_t) strtol((const char *) &payload[1], NULL, 10); + ws2812fx_speed = constrain(d, 0, 255); + strip.setSpeed(ws2812fx_speed); + DBG_OUTPUT_PORT.printf("MQTT: Set speed to [%u]\n", ws2812fx_speed); + mqtt_client.publish(mqtt_outtopic, String(String("OK ") + String((char *)payload)).c_str()); + } + + // % ==> Set brightness + if (payload[0] == '%') { + uint8_t b = (uint8_t) strtol((const char *) &payload[1], NULL, 10); + brightness = constrain(b, 0, 255); + strip.setBrightness(brightness); + DBG_OUTPUT_PORT.printf("MQTT: Set brightness to [%u]\n", brightness); + mqtt_client.publish(mqtt_outtopic, String(String("OK ") + String((char *)payload)).c_str()); + } + + // * ==> Set main color and light all LEDs (Shortcut) + if (payload[0] == '*') { + handleSetAllMode(payload); + DBG_OUTPUT_PORT.printf("MQTT: Set main color and light all LEDs [%s]\n", payload); + mqtt_client.publish(mqtt_outtopic, String(String("OK ") + String((char *)payload)).c_str()); + } + + // ! ==> Set single LED in given color + if (payload[0] == '!') { + handleSetSingleLED(payload); + DBG_OUTPUT_PORT.printf("MQTT: Set single LED in given color [%s]\n", payload); + mqtt_client.publish(mqtt_outtopic, String(String("OK ") + String((char *)payload)).c_str()); + } + + // = ==> Activate named mode + if (payload[0] == '=') { + String str_mode = String((char *) &payload[0]); + handleSetNamedMode(str_mode); + DBG_OUTPUT_PORT.printf("MQTT: Activate named mode [%s]\n", payload); + mqtt_client.publish(mqtt_outtopic, String(String("OK ") + String((char *)payload)).c_str()); + } + + // $ ==> Get status Info. + if (payload[0] == '$') { + DBG_OUTPUT_PORT.printf("MQTT: Get status info.\n"); + mqtt_client.publish(mqtt_outtopic, listStatusJSON()); + } + + // ~ ==> Get WS2812 modes. + // TODO: Fix this, doesn't return anything. Too long? + if (payload[0] == '~') { + DBG_OUTPUT_PORT.printf("MQTT: Get WS2812 modes.\n"); + DBG_OUTPUT_PORT.printf("Error: Not implemented. Message too large for pubsubclient."); + mqtt_client.publish(mqtt_outtopic, "ERROR: Not implemented. Message too large for pubsubclient."); + //String json_modes = listModesJSON(); + //DBG_OUTPUT_PORT.printf(json_modes.c_str()); + + //int res = mqtt_client.publish(mqtt_outtopic, json_modes.c_str(), json_modes.length()); + //DBG_OUTPUT_PORT.printf("Result: %d / %d", res, json_modes.length()); + } + + // / ==> Set WS2812 mode. + if (payload[0] == '/') { + handleSetWS2812FXMode(payload); + DBG_OUTPUT_PORT.printf("MQTT: Set WS2812 mode [%s]\n", payload); + mqtt_client.publish(mqtt_outtopic, String(String("OK ") + String((char *)payload)).c_str()); + } + } + + void mqtt_reconnect() { + // Loop until we're reconnected + while (!mqtt_client.connected()) { + DBG_OUTPUT_PORT.print("Attempting MQTT connection... "); + // Attempt to connect + if (mqtt_client.connect(mqtt_clientid, mqtt_user, mqtt_pass)) { + DBG_OUTPUT_PORT.println("connected!"); + // Once connected, publish an announcement... + char * message = new char[18 + strlen(HOSTNAME) + 1]; + strcpy(message, "McLighting ready: "); + strcat(message, HOSTNAME); + mqtt_client.publish(mqtt_outtopic, message); + // ... and resubscribe + mqtt_client.subscribe(mqtt_intopic); + + DBG_OUTPUT_PORT.printf("MQTT topic in: %s\n", mqtt_intopic); + DBG_OUTPUT_PORT.printf("MQTT topic out: %s\n", mqtt_outtopic); + } else { + DBG_OUTPUT_PORT.print("failed, rc="); + DBG_OUTPUT_PORT.print(mqtt_client.state()); + DBG_OUTPUT_PORT.println(" try again in 5 seconds"); + // Wait 5 seconds before retrying + delay(5000); + } + } + } +#endif