diff --git a/Arduino/McLighting/McLighting.ino b/Arduino/McLighting/McLighting.ino index 9e18eff..13b20c5 100644 --- a/Arduino/McLighting/McLighting.ino +++ b/Arduino/McLighting/McLighting.ino @@ -175,6 +175,10 @@ void setup() { // set builtin led pin as output pinMode(BUILTIN_LED, OUTPUT); + // button pin setup +#ifdef ENABLE_BUTTON + pinMode(BUTTON,INPUT_PULLUP); +#endif // start ticker with 0.5 because we start in AP mode and try to connect ticker.attach(0.5, tick); @@ -184,7 +188,6 @@ void setup() { // Setup: Neopixel // *************************************************************************** strip.init(); - strip.setBrightness(brightness); strip.setSpeed(convertSpeed(ws2812fx_speed)); //strip.setMode(FX_MODE_RAINBOW_CYCLE); strip.setColor(main_color.red, main_color.green, main_color.blue); @@ -578,32 +581,7 @@ void setup() { String chk = getValue(saved_state_string, '|', 0); if (chk == "STA") { DBG_OUTPUT_PORT.printf("Found saved state: %s\n", saved_state_string.c_str()); - String str_mode = getValue(saved_state_string, '|', 1); - mode = static_cast(str_mode.toInt()); - String str_ws2812fx_mode = getValue(saved_state_string, '|', 2); - ws2812fx_mode = str_ws2812fx_mode.toInt(); - String str_ws2812fx_speed = getValue(saved_state_string, '|', 3); - ws2812fx_speed = str_ws2812fx_speed.toInt(); - String str_brightness = getValue(saved_state_string, '|', 4); - brightness = str_brightness.toInt(); - String str_red = getValue(saved_state_string, '|', 5); - main_color.red = str_red.toInt(); - String str_green = getValue(saved_state_string, '|', 6); - main_color.green = str_green.toInt(); - String str_blue = getValue(saved_state_string, '|', 7); - main_color.blue = str_blue.toInt(); - - DBG_OUTPUT_PORT.printf("ws2812fx_mode: %d\n", ws2812fx_mode); - DBG_OUTPUT_PORT.printf("ws2812fx_speed: %d\n", ws2812fx_speed); - DBG_OUTPUT_PORT.printf("brightness: %d\n", brightness); - DBG_OUTPUT_PORT.printf("main_color.red: %d\n", main_color.red); - DBG_OUTPUT_PORT.printf("main_color.green: %d\n", main_color.green); - DBG_OUTPUT_PORT.printf("main_color.blue: %d\n", main_color.blue); - - strip.setMode(ws2812fx_mode); - strip.setSpeed(convertSpeed(ws2812fx_speed)); - strip.setBrightness(brightness); - strip.setColor(main_color.red, main_color.green, main_color.blue); + setModeByStateString(saved_state_string); } sprintf(last_state, "STA|%2d|%3d|%3d|%3d|%3d|%3d|%3d", mode, ws2812fx_mode, ws2812fx_speed, brightness, main_color.red, main_color.green, main_color.blue); #endif @@ -611,6 +589,9 @@ void setup() { void loop() { + #ifdef ENABLE_BUTTON + button(); + #endif server.handleClient(); webSocket.loop(); @@ -662,6 +643,11 @@ void loop() { strip.setMode(FX_MODE_THEATER_CHASE); mode = HOLD; } + if (mode == TWINKLERANDOM) { + strip.setColor(main_color.red, main_color.green, main_color.blue); + strip.setMode(FX_MODE_TWINKLE_RANDOM); + mode = HOLD; + } if (mode == THEATERCHASERAINBOW) { strip.setMode(FX_MODE_THEATER_CHASE_RAINBOW); mode = HOLD; @@ -698,4 +684,4 @@ void loop() { EEPROM.commit(); } #endif -} +} diff --git a/Arduino/McLighting/colormodes.h b/Arduino/McLighting/colormodes.h index aa7c48b..ca57220 100644 --- a/Arduino/McLighting/colormodes.h +++ b/Arduino/McLighting/colormodes.h @@ -2,6 +2,8 @@ // Color modes // *************************************************************************** +/////////////////////// + int dipInterval = 10; int darkTime = 250; unsigned long currentDipTime; @@ -100,4 +102,4 @@ void tv() { - + diff --git a/Arduino/McLighting/definitions.h b/Arduino/McLighting/definitions.h index 56e3f10..ba06789 100644 --- a/Arduino/McLighting/definitions.h +++ b/Arduino/McLighting/definitions.h @@ -1,33 +1,33 @@ // Neopixel -#define PIN 5 // PIN where neopixel / WS2811 strip is attached -#define NUMLEDS 24 // Number of leds in the strip +#define PIN D1 // PIN where neopixel / WS2811 strip is attached +#define NUMLEDS 7 // Number of leds in the strip //#define BUILTIN_LED 2 // ESP-12F has the built in LED on GPIO2, see https://github.com/esp8266/Arduino/issues/2192 +#define BUTTON D2 // Input pin for switching the LED strip on / off, connect this PIN to ground to trigger button. -const char HOSTNAME[] = "ESP8266_01"; // Friedly hostname +const char HOSTNAME[] = "ESP8266_VORONOI"; // Friedly hostname #define ENABLE_OTA // If defined, enable Arduino OTA code. - #define ENABLE_MQTT // If defined, enable MQTT client code. +#define ENABLE_BUTTON // If defined, enable button handling code. // parameters for automatically cycling favorite patterns uint32_t autoParams[][4] = { // color, speed, mode, duration (seconds) - {0xff0000, 200, 1, 5.0}, // blink red for 5 seconds - {0x00ff00, 200, 3, 10.0}, // wipe green for 10 seconds - {0x0000ff, 200, 11, 5.0}, // dual scan blue for 5 seconds - {0x0000ff, 200, 42, 15.0} // fireworks for 15 seconds + {0xff0000, 200, 1, 5.0}, // blink red for 5 seconds + {0x00ff00, 200, 3, 10.0}, // wipe green for 10 seconds + {0x0000ff, 200, 11, 5.0}, // dual scan blue for 5 seconds + {0x0000ff, 200, 42, 15.0} // fireworks for 15 seconds }; #ifdef ENABLE_MQTT #define MQTT_MAX_PACKET_SIZE 256 #define MQTT_MAX_RECONNECT_TRIES 4 - - int mqtt_reconnect_retries = 0; + int mqtt_reconnect_retries = 0; char mqtt_intopic[strlen(HOSTNAME) + 4]; // Topic in will be: /in char mqtt_outtopic[strlen(HOSTNAME) + 5]; // Topic out will be: /out - const char mqtt_clientid[] = "ESP8266Client"; // MQTT ClientID - + const char mqtt_clientid[] = "McLighting"; // MQTT ClientID + char mqtt_host[64] = ""; char mqtt_port[6] = ""; char mqtt_user[32] = ""; @@ -41,7 +41,7 @@ uint32_t autoParams[][4] = { // color, speed, mode, duration (seconds) #define DBG_OUTPUT_PORT Serial // Set debug output port // List of all color modes -enum MODE { SET_MODE, HOLD, OFF, ALL, WIPE, RAINBOW, RAINBOWCYCLE, THEATERCHASE, THEATERCHASERAINBOW, TV, CUSTOM }; +enum MODE { SET_MODE, HOLD, OFF, ALL, WIPE, RAINBOW, RAINBOWCYCLE, THEATERCHASE, TWINKLERANDOM, THEATERCHASERAINBOW, TV, CUSTOM }; MODE mode = RAINBOW; // Standard mode that is active when software starts @@ -56,14 +56,14 @@ bool shouldSaveConfig = false; // For WiFiManger custom config struct ledstate // Data structure to store a state of a single led { - uint8_t red; - uint8_t green; - uint8_t blue; + uint8_t red; + uint8_t green; + uint8_t blue; }; typedef struct ledstate LEDState; // Define the datatype LEDState LEDState ledstates[NUMLEDS]; // Get an array of led states to store the state of the whole strip -LEDState main_color = { 255, 0, 0 }; // Store the "main color" of the strip used in single color modes +LEDState main_color = { 255, 0, 0 }; // Store the "main color" of the strip used in single color modes #define ENABLE_STATE_SAVE // If defined, save state on reboot #ifdef ENABLE_STATE_SAVE @@ -73,3 +73,18 @@ LEDState main_color = { 255, 0, 0 }; // Store the "main color" of the strip use int timeout_statechange_save = 5000; // Timeout in ms to wait before state is saved bool state_save_requested = false; // State has to be saved after timeout #endif + +// Button handling +#ifdef ENABLE_BUTTON + #define BTN_MODE_SHORT "STA| 1| 0|245|196|255|255|255" // Static white + #define BTN_MODE_MEDIUM "STA| 1| 48|245|196|255|102| 0" // Fire flicker + #define BTN_MODE_LONG "STA| 1| 46|253|196|255|102| 0" // Fireworks random + + unsigned long keyPrevMillis = 0; + const unsigned long keySampleIntervalMs = 25; + byte longKeyPressCountMax = 80; // 80 * 25 = 2000 ms + byte mediumKeyPressCountMin = 20; // 20 * 25 = 500 ms + byte KeyPressCount = 0; + byte prevKeyState = HIGH; // button is active low + boolean buttonState = false; +#endif diff --git a/Arduino/McLighting/request_handlers.h b/Arduino/McLighting/request_handlers.h index f06a451..28fe288 100644 --- a/Arduino/McLighting/request_handlers.h +++ b/Arduino/McLighting/request_handlers.h @@ -1,6 +1,7 @@ // *************************************************************************** // Request handlers // *************************************************************************** + void getArgs() { if (server.arg("rgb") != "") { uint32_t rgb = (uint32_t) strtol(server.arg("rgb").c_str(), NULL, 16); @@ -18,7 +19,7 @@ void getArgs() { } if (server.arg("m") != "") { - ws2812fx_mode = constrain(server.arg("m").toInt(), 0, strip.getModeCount()-1); + ws2812fx_mode = constrain(server.arg("m").toInt(), 0, strip.getModeCount() - 1); } main_color.red = constrain(main_color.red, 0, 255); @@ -89,13 +90,13 @@ void handleSetSingleLED(uint8_t * mypayload, uint8_t firstChar = 0) { uint8_t led = atoi(templed); DBG_OUTPUT_PORT.printf("led value: [%i]. Entry threshold: <= [%i] (=> %s)\n", led, strip.numPixels(), mypayload ); - if (led <= strip.numPixels()) { + if (led <= strip.numPixels()) { char redhex[3]; char greenhex[3]; char bluehex[3]; - strncpy (redhex, (const char *) &mypayload[2+firstChar], 2 ); - strncpy (greenhex, (const char *) &mypayload[4+firstChar], 2 ); - strncpy (bluehex, (const char *) &mypayload[6+firstChar], 2 ); + strncpy (redhex, (const char *) &mypayload[2 + firstChar], 2 ); + strncpy (greenhex, (const char *) &mypayload[4 + firstChar], 2 ); + strncpy (bluehex, (const char *) &mypayload[6 + firstChar], 2 ); ledstates[led].red = strtol(redhex, NULL, 16); ledstates[led].green = strtol(greenhex, NULL, 16); ledstates[led].blue = strtol(bluehex, NULL, 16); @@ -103,7 +104,7 @@ void handleSetSingleLED(uint8_t * mypayload, uint8_t firstChar = 0) { DBG_OUTPUT_PORT.printf("rgb.red: [%i] rgb.green: [%i] rgb.blue: [%i]\n", strtol(redhex, NULL, 16), strtol(greenhex, NULL, 16), strtol(bluehex, NULL, 16)); DBG_OUTPUT_PORT.printf("WS: Set single led [%i] to [%i] [%i] [%i] (%s)!\n", led, ledstates[led].red, ledstates[led].green, ledstates[led].blue, mypayload); - + strip.setPixelColor(led, ledstates[led].red, ledstates[led].green, ledstates[led].blue); strip.show(); } @@ -126,37 +127,66 @@ void handleRangeDifferentColors(uint8_t * mypayload) { //While there is a range to process R0110<00ff00> while (nextCommand) { - //Loop for each LED. - char startled[3] = { 0,0,0 }; - char endled[3] = { 0,0,0 }; - char colorval[7] = { 0,0,0,0,0,0,0 }; - strncpy ( startled, (const char *) &nextCommand[0], 2 ); - strncpy ( endled, (const char *) &nextCommand[2], 2 ); - strncpy ( colorval, (const char *) &nextCommand[4], 6 ); - int rangebegin = atoi(startled); - int rangeend = atoi(endled); - DBG_OUTPUT_PORT.printf("Setting RANGE from [%i] to [%i] as color [%s] \n", rangebegin, rangeend, colorval); + //Loop for each LED. + char startled[3] = { 0, 0, 0 }; + char endled[3] = { 0, 0, 0 }; + char colorval[7] = { 0, 0, 0, 0, 0, 0, 0 }; + strncpy ( startled, (const char *) &nextCommand[0], 2 ); + strncpy ( endled, (const char *) &nextCommand[2], 2 ); + strncpy ( colorval, (const char *) &nextCommand[4], 6 ); + int rangebegin = atoi(startled); + int rangeend = atoi(endled); + DBG_OUTPUT_PORT.printf("Setting RANGE from [%i] to [%i] as color [%s] \n", rangebegin, rangeend, colorval); - while ( rangebegin <= rangeend ) { - char rangeData[9] = { 0,0,0,0,0,0,0,0,0 }; - if ( rangebegin < 10 ) { - //Create the valid 'nextCommand' structure - sprintf(rangeData, "0%d%s", rangebegin, colorval); - } - if ( rangebegin >= 10 ) { - //Create the valid 'nextCommand' structure - sprintf(rangeData, "%d%s", rangebegin, colorval); - } - //Set one LED - handleSetSingleLED((uint8_t*) rangeData, 0); - rangebegin++; + while ( rangebegin <= rangeend ) { + char rangeData[9] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + if ( rangebegin < 10 ) { + //Create the valid 'nextCommand' structure + sprintf(rangeData, "0%d%s", rangebegin, colorval); } + if ( rangebegin >= 10 ) { + //Create the valid 'nextCommand' structure + sprintf(rangeData, "%d%s", rangebegin, colorval); + } + //Set one LED + handleSetSingleLED((uint8_t*) rangeData, 0); + rangebegin++; + } - //Next Range at R - nextCommand = (uint8_t*) strtok(NULL, "R"); + //Next Range at R + nextCommand = (uint8_t*) strtok(NULL, "R"); } } +void setModeByStateString(String saved_state_string) { + String str_mode = getValue(saved_state_string, '|', 1); + mode = static_cast(str_mode.toInt()); + String str_ws2812fx_mode = getValue(saved_state_string, '|', 2); + ws2812fx_mode = str_ws2812fx_mode.toInt(); + String str_ws2812fx_speed = getValue(saved_state_string, '|', 3); + ws2812fx_speed = str_ws2812fx_speed.toInt(); + String str_brightness = getValue(saved_state_string, '|', 4); + brightness = str_brightness.toInt(); + String str_red = getValue(saved_state_string, '|', 5); + main_color.red = str_red.toInt(); + String str_green = getValue(saved_state_string, '|', 6); + main_color.green = str_green.toInt(); + String str_blue = getValue(saved_state_string, '|', 7); + main_color.blue = str_blue.toInt(); + + DBG_OUTPUT_PORT.printf("ws2812fx_mode: %d\n", ws2812fx_mode); + DBG_OUTPUT_PORT.printf("ws2812fx_speed: %d\n", ws2812fx_speed); + DBG_OUTPUT_PORT.printf("brightness: %d\n", brightness); + DBG_OUTPUT_PORT.printf("main_color.red: %d\n", main_color.red); + DBG_OUTPUT_PORT.printf("main_color.green: %d\n", main_color.green); + DBG_OUTPUT_PORT.printf("main_color.blue: %d\n", main_color.blue); + + strip.setMode(ws2812fx_mode); + strip.setSpeed(convertSpeed(ws2812fx_speed)); + strip.setBrightness(brightness); + strip.setColor(main_color.red, main_color.green, main_color.blue); +} + void handleSetNamedMode(String str_mode) { exit_func = true; @@ -178,6 +208,9 @@ void handleSetNamedMode(String str_mode) { if (str_mode.startsWith("=theaterchase")) { mode = THEATERCHASE; } + if (str_mode.startsWith("=twinkleRandom")) { + mode = TWINKLERANDOM; + } if (str_mode.startsWith("=theaterchaseRainbow")) { mode = THEATERCHASERAINBOW; } @@ -202,7 +235,7 @@ char* listStatusJSON() { strncpy_P(modeName, (PGM_P)strip.getModeName(strip.getMode()), sizeof(modeName)); // copy from progmem snprintf(json, sizeof(json), "{\"mode\":%d, \"ws2812fx_mode\":%d, \"ws2812fx_mode_name\":\"%s\", \"speed\":%d, \"brightness\":%d, \"color\":[%d, %d, %d]}", - mode, strip.getMode(), modeName, ws2812fx_speed, brightness, main_color.red, main_color.green, main_color.blue); + mode, strip.getMode(), modeName, ws2812fx_speed, brightness, main_color.red, main_color.green, main_color.blue); return json; } @@ -212,7 +245,7 @@ void getStatusJSON() { String listModesJSON() { String modes = "["; - for(uint8_t i=0; i < strip.getModeCount(); i++) { + for (uint8_t i = 0; i < strip.getModeCount(); i++) { modes += "{\"mode\":"; modes += i; modes += ", \"name\":\""; @@ -235,7 +268,7 @@ void handleMinimalUpload() { char temp[1500]; snprintf ( temp, 1500, - "\ + "\ \ \ ESP8266 Upload\ @@ -251,7 +284,7 @@ void handleMinimalUpload() { \ \ " - ); + ); server.send ( 200, "text/html", temp ); } @@ -283,11 +316,11 @@ void autoTick() { DBG_OUTPUT_PORT.println(autoCount); autoCount++; - if(autoCount >= (sizeof(autoParams) / sizeof(autoParams[0]))) autoCount=0; + if (autoCount >= (sizeof(autoParams) / sizeof(autoParams[0]))) autoCount = 0; } void handleAutoStart() { - autoCount=0; + autoCount = 0; autoTick(); strip.start(); } @@ -427,130 +460,189 @@ void checkForRequests() { // 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); +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(convertSpeed(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, 1); - 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()); - } - - // + ==> Set multiple LED in the given colors - if (payload[0] == '+') { - handleSetDifferentColors(payload); - mqtt_client.publish(mqtt_outtopic, String(String("OK ") + String((char *)payload)).c_str()); - } - - // R ==> Set range of LEDs in the given colors - if (payload[0] == 'R') { - handleRangeDifferentColors(payload); - DBG_OUTPUT_PORT.printf("MQTT: Set range of LEDS to single 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? - // Hint: https://github.com/knolleary/pubsubclient/issues/110 - 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()); - } - - free(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()); } - void mqtt_reconnect() { - // Loop until we're reconnected - while (!mqtt_client.connected() && mqtt_reconnect_retries < MQTT_MAX_RECONNECT_TRIES) { - mqtt_reconnect_retries++; - DBG_OUTPUT_PORT.printf("Attempting MQTT connection %d / %d ...\n", mqtt_reconnect_retries, MQTT_MAX_RECONNECT_TRIES); - // Attempt to connect - if (mqtt_client.connect(mqtt_clientid, mqtt_user, mqtt_pass)) { - DBG_OUTPUT_PORT.println("MQTT 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); + // ? ==> 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(convertSpeed(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()); + } - 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); + // % ==> 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, 1); + 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()); + } + + // + ==> Set multiple LED in the given colors + if (payload[0] == '+') { + handleSetDifferentColors(payload); + mqtt_client.publish(mqtt_outtopic, String(String("OK ") + String((char *)payload)).c_str()); + } + + // R ==> Set range of LEDs in the given colors + if (payload[0] == 'R') { + handleRangeDifferentColors(payload); + DBG_OUTPUT_PORT.printf("MQTT: Set range of LEDS to single 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? + // Hint: https://github.com/knolleary/pubsubclient/issues/110 + 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()); + } + + free(payload); +} + +void mqtt_reconnect() { + // Loop until we're reconnected + while (!mqtt_client.connected() && mqtt_reconnect_retries < MQTT_MAX_RECONNECT_TRIES) { + mqtt_reconnect_retries++; + DBG_OUTPUT_PORT.printf("Attempting MQTT connection %d / %d ...\n", mqtt_reconnect_retries, MQTT_MAX_RECONNECT_TRIES); + // Attempt to connect + if (mqtt_client.connect(mqtt_clientid, mqtt_user, mqtt_pass)) { + DBG_OUTPUT_PORT.println("MQTT 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); + } + } + if (mqtt_reconnect_retries >= MQTT_MAX_RECONNECT_TRIES) { + DBG_OUTPUT_PORT.printf("MQTT connection failed, giving up after %d tries ...\n", mqtt_reconnect_retries); + } +} +#endif + + +// *************************************************************************** +// Button management +// *************************************************************************** +#ifdef ENABLE_BUTTON +void shortKeyPress() { + DBG_OUTPUT_PORT.printf("Short button press\n"); + if (buttonState == false) { + setModeByStateString(BTN_MODE_SHORT); + buttonState = true; + } else { + mode = OFF; + buttonState = false; + } +} + +// called when button is kept pressed for less than 2 seconds +void mediumKeyPress() { + DBG_OUTPUT_PORT.printf("Medium button press\n"); + setModeByStateString(BTN_MODE_MEDIUM); +} + +// called when button is kept pressed for 2 seconds or more +void longKeyPress() { + DBG_OUTPUT_PORT.printf("Long button press\n"); + setModeByStateString(BTN_MODE_LONG); +} + +void button() { + if (millis() - keyPrevMillis >= keySampleIntervalMs) { + keyPrevMillis = millis(); + + byte currKeyState = digitalRead(BUTTON); + + if ((prevKeyState == HIGH) && (currKeyState == LOW)) { + // key goes from not pressed to pressed + KeyPressCount = 0; + } + else if ((prevKeyState == LOW) && (currKeyState == HIGH)) { + if (KeyPressCount < longKeyPressCountMax && KeyPressCount >= mediumKeyPressCountMin) { + mediumKeyPress(); + } + else { + if (KeyPressCount < mediumKeyPressCountMin) { + shortKeyPress(); + } } } - if (mqtt_reconnect_retries >= MQTT_MAX_RECONNECT_TRIES) { - DBG_OUTPUT_PORT.printf("MQTT connection failed, giving up after %d tries ...\n", mqtt_reconnect_retries); + else if (currKeyState == LOW) { + KeyPressCount++; + if (KeyPressCount >= longKeyPressCountMax) { + longKeyPress(); + } } + prevKeyState = currKeyState; } -#endif +} +#endif diff --git a/Arduino/McLighting/spiffs_webserver.h b/Arduino/McLighting/spiffs_webserver.h index c68af2f..a59565e 100644 --- a/Arduino/McLighting/spiffs_webserver.h +++ b/Arduino/McLighting/spiffs_webserver.h @@ -155,4 +155,4 @@ void handleFileList() { output += "]"; server.send(200, "text/json", output); } - +