Merge branch 'debsahu/master'

Support for AMQTT, NEOANIMATIONFX
This commit is contained in:
Tobias Blum 2018-04-07 21:57:21 +02:00
commit 9b7ca2ac47
4 changed files with 1157 additions and 396 deletions

View file

@ -35,6 +35,18 @@
PubSubClient mqtt_client(espClient); PubSubClient mqtt_client(espClient);
#endif #endif
#ifdef ENABLE_AMQTT
#include <AsyncMqttClient.h> //https://github.com/marvinroger/async-mqtt-client
//https://github.com/me-no-dev/ESPAsyncTCP
#ifdef ENABLE_HOMEASSISTANT
#include <ArduinoJson.h>
#endif
AsyncMqttClient amqttClient;
WiFiEventHandler wifiConnectHandler;
WiFiEventHandler wifiDisconnectHandler;
#endif
// *************************************************************************** // ***************************************************************************
// Instanciate HTTP(80) / WebSockets(81) Server // Instanciate HTTP(80) / WebSockets(81) Server
@ -43,10 +55,29 @@ ESP8266WebServer server(80);
WebSocketsServer webSocket = WebSocketsServer(81); WebSocketsServer webSocket = WebSocketsServer(81);
#ifdef HTTP_OTA #ifdef HTTP_OTA
#include <ESP8266HTTPUpdateServer.h> #include <ESP8266HTTPUpdateServer.h>
ESP8266HTTPUpdateServer httpUpdater; ESP8266HTTPUpdateServer httpUpdater;
#endif #endif
#ifdef USE_NEOANIMATIONFX
// ***************************************************************************
// Load libraries / Instanciate NeoAnimationFX library
// ***************************************************************************
// https://github.com/debsahu/NeoAnimationFX
#include <NeoAnimationFX.h>
#define NEOMETHOD NeoPBBGRB800
NEOMETHOD neoStrip(NUMLEDS);
NeoAnimationFX<NEOMETHOD> strip(neoStrip);
// Uses Pin RX / GPIO3 (Only pin that is supported, due to hardware limitations)
// NEOMETHOD NeoPBBGRB800 uses GRB config 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
// NEOMETHOD NeoPBBGRB400 uses GRB config 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
// NEOMETHOD NeoPBBRGB800 uses RGB config 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
// NEOMETHOD NeoPBBRGB400 uses RGB config 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
#endif
#ifdef USE_WS2812FX
// *************************************************************************** // ***************************************************************************
// Load libraries / Instanciate WS2812FX library // Load libraries / Instanciate WS2812FX library
// *************************************************************************** // ***************************************************************************
@ -66,14 +97,23 @@ WS2812FX strip = WS2812FX(NUMLEDS, PIN, NEO_GRB + NEO_KHZ800);
// pixel power leads, add 300 - 500 Ohm resistor on first pixel's data input // pixel power leads, add 300 - 500 Ohm resistor on first pixel's data input
// and minimize distance between Arduino and first pixel. Avoid connecting // and minimize distance between Arduino and first pixel. Avoid connecting
// on a live circuit...if you must, connect GND first. // on a live circuit...if you must, connect GND first.
#endif
// *************************************************************************** // ***************************************************************************
// Load library "ticker" for blinking status led // Load library "ticker" for blinking status led
// *************************************************************************** // ***************************************************************************
#include <Ticker.h> #include <Ticker.h>
Ticker ticker; Ticker ticker;
#ifdef ENABLE_HOMEASSISTANT
Ticker ha_send_data;
#endif
#ifdef ENABLE_AMQTT
Ticker mqttReconnectTimer;
Ticker wifiReconnectTimer;
#endif
#ifdef ENABLE_STATE_SAVE_SPIFFS
Ticker spiffs_save_state;
#endif
void tick() void tick()
{ {
//toggle state //toggle state
@ -81,11 +121,11 @@ void tick()
digitalWrite(BUILTIN_LED, !state); // set pin to the opposite state digitalWrite(BUILTIN_LED, !state); // set pin to the opposite state
} }
#ifdef ENABLE_STATE_SAVE_EEPROM
// *************************************************************************** // ***************************************************************************
// EEPROM helper // EEPROM helper
// *************************************************************************** // ***************************************************************************
String readEEPROM(int offset, int len) { String readEEPROM(int offset, int len) {
String res = ""; String res = "";
for (int i = 0; i < len; ++i) for (int i = 0; i < len; ++i)
{ {
@ -94,9 +134,9 @@ String readEEPROM(int offset, int len) {
} }
DBG_OUTPUT_PORT.printf("readEEPROM(): %s\n", res.c_str()); DBG_OUTPUT_PORT.printf("readEEPROM(): %s\n", res.c_str());
return res; return res;
} }
void writeEEPROM(int offset, int len, String value) { void writeEEPROM(int offset, int len, String value) {
DBG_OUTPUT_PORT.printf("writeEEPROM(): %s\n", value.c_str()); DBG_OUTPUT_PORT.printf("writeEEPROM(): %s\n", value.c_str());
for (int i = 0; i < len; ++i) for (int i = 0; i < len; ++i)
{ {
@ -106,8 +146,8 @@ void writeEEPROM(int offset, int len, String value) {
EEPROM.write(i + offset, NULL); EEPROM.write(i + offset, NULL);
} }
} }
} }
#endif
// *************************************************************************** // ***************************************************************************
// Saved state handling // Saved state handling
@ -130,7 +170,6 @@ String getValue(String data, char separator, int index)
return found>index ? data.substring(strIndex[0], strIndex[1]) : ""; return found>index ? data.substring(strIndex[0], strIndex[1]) : "";
} }
// *************************************************************************** // ***************************************************************************
// Callback for WiFiManager library when config mode is entered // Callback for WiFiManager library when config mode is entered
// *************************************************************************** // ***************************************************************************
@ -171,12 +210,12 @@ void saveConfigCallback () {
// *************************************************************************** // ***************************************************************************
#include "colormodes.h" #include "colormodes.h"
// *************************************************************************** // ***************************************************************************
// MAIN // MAIN
// *************************************************************************** // ***************************************************************************
void setup() { void setup() {
// system_update_cpu_freq(160);
DBG_OUTPUT_PORT.begin(115200); DBG_OUTPUT_PORT.begin(115200);
EEPROM.begin(512); EEPROM.begin(512);
@ -189,6 +228,23 @@ void setup() {
// start ticker with 0.5 because we start in AP mode and try to connect // start ticker with 0.5 because we start in AP mode and try to connect
ticker.attach(0.5, tick); ticker.attach(0.5, tick);
// ***************************************************************************
// Setup: SPIFFS
// ***************************************************************************
SPIFFS.begin();
{
Dir dir = SPIFFS.openDir("/");
while (dir.next()) {
String fileName = dir.fileName();
size_t fileSize = dir.fileSize();
DBG_OUTPUT_PORT.printf("FS File: %s, size: %s\n", fileName.c_str(), formatBytes(fileSize).c_str());
}
FSInfo fs_info;
SPIFFS.info(fs_info);
DBG_OUTPUT_PORT.printf("FS Usage: %d/%d bytes\n\n", fs_info.usedBytes, fs_info.totalBytes);
}
wifi_station_set_hostname(const_cast<char*>(HOSTNAME)); wifi_station_set_hostname(const_cast<char*>(HOSTNAME));
// *************************************************************************** // ***************************************************************************
@ -207,7 +263,10 @@ void setup() {
// The extra parameters to be configured (can be either global or just in the setup) // 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 // After connecting, parameter.getValue() will get you the configured value
// id/name placeholder/prompt default length // id/name placeholder/prompt default length
#ifdef ENABLE_MQTT #if defined(ENABLE_MQTT) or defined(ENABLE_AMQTT)
#if defined(ENABLE_STATE_SAVE_SPIFFS)
(readConfigFS()) ? DBG_OUTPUT_PORT.println("WiFiManager config FS Read success!"): DBG_OUTPUT_PORT.println("WiFiManager config FS Read failure!");
#else
String settings_available = readEEPROM(134, 1); String settings_available = readEEPROM(134, 1);
if (settings_available == "1") { if (settings_available == "1") {
readEEPROM(0, 64).toCharArray(mqtt_host, 64); // 0-63 readEEPROM(0, 64).toCharArray(mqtt_host, 64); // 0-63
@ -219,7 +278,7 @@ void setup() {
DBG_OUTPUT_PORT.printf("MQTT user: %s\n", mqtt_user); DBG_OUTPUT_PORT.printf("MQTT user: %s\n", mqtt_user);
DBG_OUTPUT_PORT.printf("MQTT pass: %s\n", mqtt_pass); DBG_OUTPUT_PORT.printf("MQTT pass: %s\n", mqtt_pass);
} }
#endif
WiFiManagerParameter custom_mqtt_host("host", "MQTT hostname", mqtt_host, 64); WiFiManagerParameter custom_mqtt_host("host", "MQTT hostname", mqtt_host, 64);
WiFiManagerParameter custom_mqtt_port("port", "MQTT port", mqtt_port, 6); WiFiManagerParameter custom_mqtt_port("port", "MQTT port", mqtt_port, 6);
WiFiManagerParameter custom_mqtt_user("user", "MQTT user", mqtt_user, 32); WiFiManagerParameter custom_mqtt_user("user", "MQTT user", mqtt_user, 32);
@ -234,7 +293,7 @@ void setup() {
//set callback that gets called when connecting to previous WiFi fails, and enters Access Point mode //set callback that gets called when connecting to previous WiFi fails, and enters Access Point mode
wifiManager.setAPCallback(configModeCallback); wifiManager.setAPCallback(configModeCallback);
#ifdef ENABLE_MQTT #if defined(ENABLE_MQTT) or defined(ENABLE_AMQTT)
//set config save notify callback //set config save notify callback
wifiManager.setSaveConfigCallback(saveConfigCallback); wifiManager.setSaveConfigCallback(saveConfigCallback);
@ -245,6 +304,8 @@ void setup() {
wifiManager.addParameter(&custom_mqtt_pass); wifiManager.addParameter(&custom_mqtt_pass);
#endif #endif
WiFi.setSleepMode(WIFI_NONE_SLEEP);
//fetches ssid and pass and tries to connect //fetches ssid and pass and tries to connect
//if it does not connect it starts an access point with the specified name //if it does not connect it starts an access point with the specified name
//here "AutoConnectAP" //here "AutoConnectAP"
@ -256,7 +317,7 @@ void setup() {
delay(1000); delay(1000);
} }
#ifdef ENABLE_MQTT #if defined(ENABLE_MQTT) or defined(ENABLE_AMQTT)
//read updated parameters //read updated parameters
strcpy(mqtt_host, custom_mqtt_host.getValue()); strcpy(mqtt_host, custom_mqtt_host.getValue());
strcpy(mqtt_port, custom_mqtt_port.getValue()); strcpy(mqtt_port, custom_mqtt_port.getValue());
@ -264,6 +325,9 @@ void setup() {
strcpy(mqtt_pass, custom_mqtt_pass.getValue()); strcpy(mqtt_pass, custom_mqtt_pass.getValue());
//save the custom parameters to FS //save the custom parameters to FS
#if defined(ENABLE_STATE_SAVE_SPIFFS)
(writeConfigFS(shouldSaveConfig)) ? DBG_OUTPUT_PORT.println("WiFiManager config FS Save success!"): DBG_OUTPUT_PORT.println("WiFiManager config FS Save failure!");
#else if defined(ENABLE_STATE_SAVE_EEPROM)
if (shouldSaveConfig) { if (shouldSaveConfig) {
DBG_OUTPUT_PORT.println("Saving WiFiManager config"); DBG_OUTPUT_PORT.println("Saving WiFiManager config");
@ -275,6 +339,12 @@ void setup() {
EEPROM.commit(); EEPROM.commit();
} }
#endif #endif
#endif
#ifdef ENABLE_AMQTT
wifiConnectHandler = WiFi.onStationModeGotIP(onWifiConnect);
wifiDisconnectHandler = WiFi.onStationModeDisconnected(onWifiDisconnect);
#endif
//if you get here you have connected to the WiFi //if you get here you have connected to the WiFi
DBG_OUTPUT_PORT.println("connected...yeey :)"); DBG_OUTPUT_PORT.println("connected...yeey :)");
@ -340,6 +410,21 @@ void setup() {
} }
#endif #endif
#ifdef ENABLE_AMQTT
if (mqtt_host != "" && String(mqtt_port).toInt() > 0) {
amqttClient.onConnect(onMqttConnect);
amqttClient.onDisconnect(onMqttDisconnect);
amqttClient.onMessage(onMqttMessage);
amqttClient.setServer(mqtt_host, String(mqtt_port).toInt());
amqttClient.setClientId(mqtt_clientid);
connectToMqtt();
}
#endif
// #ifdef ENABLE_HOMEASSISTANT
// ha_send_data.attach(5, tickerSendState); // Send HA data back only every 5 sec
// #endif
// *************************************************************************** // ***************************************************************************
// Setup: MDNS responder // Setup: MDNS responder
@ -367,24 +452,6 @@ void setup() {
webSocket.begin(); webSocket.begin();
webSocket.onEvent(webSocketEvent); webSocket.onEvent(webSocketEvent);
// ***************************************************************************
// Setup: SPIFFS
// ***************************************************************************
SPIFFS.begin();
{
Dir dir = SPIFFS.openDir("/");
while (dir.next()) {
String fileName = dir.fileName();
size_t fileSize = dir.fileSize();
DBG_OUTPUT_PORT.printf("FS File: %s, size: %s\n", fileName.c_str(), formatBytes(fileSize).c_str());
}
FSInfo fs_info;
SPIFFS.info(fs_info);
DBG_OUTPUT_PORT.printf("FS Usage: %d/%d bytes\n\n", fs_info.usedBytes, fs_info.totalBytes);
}
// *************************************************************************** // ***************************************************************************
// Setup: SPIFFS Webserver handler // Setup: SPIFFS Webserver handler
// *************************************************************************** // ***************************************************************************
@ -462,7 +529,19 @@ void setup() {
brightness = 0; brightness = 0;
} }
strip.setBrightness(brightness); strip.setBrightness(brightness);
#ifdef ENABLE_MQTT
mqtt_client.publish(mqtt_outtopic, String(String("OK %") + String(brightness)).c_str());
#endif
#ifdef ENABLE_AMQTT
amqttClient.publish(mqtt_outtopic.c_str(), qospub, false, String(String("OK %") + String(brightness)).c_str());
#endif
#ifdef ENABLE_HOMEASSISTANT
stateOn = true;
if(!ha_send_data.active()) ha_send_data.once(5, tickerSendState);
#endif
#ifdef ENABLE_STATE_SAVE_SPIFFS
if(!spiffs_save_state.active()) spiffs_save_state.once(3, tickerSpiffsSaveState);
#endif
getStatusJSON(); getStatusJSON();
}); });
@ -478,6 +557,15 @@ void setup() {
ws2812fx_speed = server.arg("d").toInt(); ws2812fx_speed = server.arg("d").toInt();
ws2812fx_speed = constrain(ws2812fx_speed, 0, 255); ws2812fx_speed = constrain(ws2812fx_speed, 0, 255);
strip.setSpeed(convertSpeed(ws2812fx_speed)); strip.setSpeed(convertSpeed(ws2812fx_speed));
#ifdef ENABLE_MQTT
mqtt_client.publish(mqtt_outtopic, String(String("OK ?") + String(ws2812fx_speed)).c_str());
#endif
#ifdef ENABLE_AMQTT
amqttClient.publish(mqtt_outtopic.c_str(), qospub, false, String(String("OK ?") + String(ws2812fx_speed)).c_str());
#endif
#ifdef ENABLE_HOMEASSISTANT
if(!ha_send_data.active()) ha_send_data.once(5, tickerSendState);
#endif
} }
getStatusJSON(); getStatusJSON();
@ -511,6 +599,18 @@ void setup() {
mode = OFF; mode = OFF;
getArgs(); getArgs();
getStatusJSON(); getStatusJSON();
#ifdef ENABLE_MQTT
mqtt_client.publish(mqtt_outtopic, String("OK =off").c_str());
#endif
#ifdef ENABLE_AMQTT
amqttClient.publish(mqtt_outtopic.c_str(), qospub, false, String("OK =off").c_str());
#endif
#ifdef ENABLE_HOMEASSISTANT
stateOn = false;
#endif
#ifdef ENABLE_STATE_SAVE_SPIFFS
if(!spiffs_save_state.active()) spiffs_save_state.once(3, tickerSpiffsSaveState);
#endif
}); });
server.on("/all", []() { server.on("/all", []() {
@ -518,6 +618,18 @@ void setup() {
mode = ALL; mode = ALL;
getArgs(); getArgs();
getStatusJSON(); getStatusJSON();
#ifdef ENABLE_MQTT
mqtt_client.publish(mqtt_outtopic, String("OK =all").c_str());
#endif
#ifdef ENABLE_AMQTT
amqttClient.publish(mqtt_outtopic.c_str(), qospub, false, String("OK =all").c_str());
#endif
#ifdef ENABLE_HOMEASSISTANT
stateOn = true;
#endif
#ifdef ENABLE_STATE_SAVE_SPIFFS
if(!spiffs_save_state.active()) spiffs_save_state.once(3, tickerSpiffsSaveState);
#endif
}); });
server.on("/wipe", []() { server.on("/wipe", []() {
@ -525,6 +637,18 @@ void setup() {
mode = WIPE; mode = WIPE;
getArgs(); getArgs();
getStatusJSON(); getStatusJSON();
#ifdef ENABLE_MQTT
mqtt_client.publish(mqtt_outtopic, String("OK =wipe").c_str());
#endif
#ifdef ENABLE_AMQTT
amqttClient.publish(mqtt_outtopic.c_str(), qospub, false, String("OK =wipe").c_str());
#endif
#ifdef ENABLE_HOMEASSISTANT
stateOn = true;
#endif
#ifdef ENABLE_STATE_SAVE_SPIFFS
if(!spiffs_save_state.active()) spiffs_save_state.once(3, tickerSpiffsSaveState);
#endif
}); });
server.on("/rainbow", []() { server.on("/rainbow", []() {
@ -532,6 +656,18 @@ void setup() {
mode = RAINBOW; mode = RAINBOW;
getArgs(); getArgs();
getStatusJSON(); getStatusJSON();
#ifdef ENABLE_MQTT
mqtt_client.publish(mqtt_outtopic, String("OK =rainbow").c_str());
#endif
#ifdef ENABLE_AMQTT
amqttClient.publish(mqtt_outtopic.c_str(), qospub, false, String("OK =rainbow").c_str());
#endif
#ifdef ENABLE_HOMEASSISTANT
stateOn = true;
#endif
#ifdef ENABLE_STATE_SAVE_SPIFFS
if(!spiffs_save_state.active()) spiffs_save_state.once(3, tickerSpiffsSaveState);
#endif
}); });
server.on("/rainbowCycle", []() { server.on("/rainbowCycle", []() {
@ -539,6 +675,18 @@ void setup() {
mode = RAINBOWCYCLE; mode = RAINBOWCYCLE;
getArgs(); getArgs();
getStatusJSON(); getStatusJSON();
#ifdef ENABLE_MQTT
mqtt_client.publish(mqtt_outtopic, String("OK =rainbowCycle").c_str());
#endif
#ifdef ENABLE_AMQTT
amqttClient.publish(mqtt_outtopic.c_str(), qospub, false, String("OK =rainbowCycle").c_str());
#endif
#ifdef ENABLE_HOMEASSISTANT
stateOn = true;
#endif
#ifdef ENABLE_STATE_SAVE_SPIFFS
if(!spiffs_save_state.active()) spiffs_save_state.once(3, tickerSpiffsSaveState);
#endif
}); });
server.on("/theaterchase", []() { server.on("/theaterchase", []() {
@ -546,6 +694,37 @@ void setup() {
mode = THEATERCHASE; mode = THEATERCHASE;
getArgs(); getArgs();
getStatusJSON(); getStatusJSON();
#ifdef ENABLE_MQTT
mqtt_client.publish(mqtt_outtopic, String("OK =theaterchase").c_str());
#endif
#ifdef ENABLE_AMQTT
amqttClient.publish(mqtt_outtopic.c_str(), qospub, false, String("OK =theaterchase").c_str());
#endif
#ifdef ENABLE_HOMEASSISTANT
stateOn = true;
#endif
#ifdef ENABLE_STATE_SAVE_SPIFFS
if(!spiffs_save_state.active()) spiffs_save_state.once(3, tickerSpiffsSaveState);
#endif
});
server.on("/twinkleRandom", []() {
exit_func = true;
mode = TWINKLERANDOM;
getArgs();
getStatusJSON();
#ifdef ENABLE_MQTT
mqtt_client.publish(mqtt_outtopic, String("OK =twinkleRandom").c_str());
#endif
#ifdef ENABLE_AMQTT
amqttClient.publish(mqtt_outtopic.c_str(), qospub, false, String("OK =twinkleRandom").c_str());
#endif
#ifdef ENABLE_HOMEASSISTANT
stateOn = true;
#endif
#ifdef ENABLE_STATE_SAVE_SPIFFS
if(!spiffs_save_state.active()) spiffs_save_state.once(3, tickerSpiffsSaveState);
#endif
}); });
server.on("/theaterchaseRainbow", []() { server.on("/theaterchaseRainbow", []() {
@ -553,6 +732,18 @@ void setup() {
mode = THEATERCHASERAINBOW; mode = THEATERCHASERAINBOW;
getArgs(); getArgs();
getStatusJSON(); getStatusJSON();
#ifdef ENABLE_MQTT
mqtt_client.publish(mqtt_outtopic, String("OK =theaterchaseRainbow").c_str());
#endif
#ifdef ENABLE_AMQTT
amqttClient.publish(mqtt_outtopic.c_str(), qospub, false, String("OK =theaterchaseRainbow").c_str());
#endif
#ifdef ENABLE_HOMEASSISTANT
stateOn = true;
#endif
#ifdef ENABLE_STATE_SAVE_SPIFFS
if(!spiffs_save_state.active()) spiffs_save_state.once(3, tickerSpiffsSaveState);
#endif
}); });
server.on("/tv", []() { server.on("/tv", []() {
@ -560,6 +751,18 @@ void setup() {
mode = TV; mode = TV;
getArgs(); getArgs();
getStatusJSON(); getStatusJSON();
#ifdef ENABLE_MQTT
mqtt_client.publish(mqtt_outtopic, String("OK =tv").c_str());
#endif
#ifdef ENABLE_AMQTT
amqttClient.publish(mqtt_outtopic.c_str(), qospub, false, String("OK =tv").c_str());
#endif
#ifdef ENABLE_HOMEASSISTANT
stateOn = true;
#endif
#ifdef ENABLE_STATE_SAVE_SPIFFS
if(!spiffs_save_state.active()) spiffs_save_state.once(3, tickerSpiffsSaveState);
#endif
}); });
server.on("/get_modes", []() { server.on("/get_modes", []() {
@ -570,20 +773,40 @@ void setup() {
getArgs(); getArgs();
mode = SET_MODE; mode = SET_MODE;
getStatusJSON(); getStatusJSON();
#ifdef ENABLE_MQTT
mqtt_client.publish(mqtt_outtopic, String(String("OK /") + String(ws2812fx_mode).c_str());
#endif
#ifdef ENABLE_AMQTT
amqttClient.publish(mqtt_outtopic.c_str(), qospub, false, String(String("OK /") + String(ws2812fx_mode)).c_str());
#endif
#ifdef ENABLE_HOMEASSISTANT
stateOn = true;
if(!ha_send_data.active()) ha_send_data.once(5, tickerSendState);
#endif
#ifdef ENABLE_STATE_SAVE_SPIFFS
if(!spiffs_save_state.active()) spiffs_save_state.once(3, tickerSpiffsSaveState);
#endif
}); });
#ifdef HTTP_OTA #ifdef HTTP_OTA
httpUpdater.setup(&server,"/update"); httpUpdater.setup(&server,"/update");
#endif #endif
#ifdef HTTP_OTA
httpUpdater.setup(&server, "/update");
#endif
server.begin(); server.begin();
// Start MDNS service // Start MDNS service
if (mdns_result) { if (mdns_result) {
MDNS.addService("http", "tcp", 80); MDNS.addService("http", "tcp", 80);
} }
#ifdef ENABLE_STATE_SAVE_SPIFFS
#ifdef ENABLE_STATE_SAVE (readStateFS()) ? DBG_OUTPUT_PORT.println(" Success!") : DBG_OUTPUT_PORT.println(" Failure!");
#endif
#ifdef ENABLE_STATE_SAVE_EEPROM
// Load state string from EEPROM // Load state string from EEPROM
String saved_state_string = readEEPROM(256, 32); String saved_state_string = readEEPROM(256, 32);
String chk = getValue(saved_state_string, '|', 0); String chk = getValue(saved_state_string, '|', 0);
@ -608,13 +831,32 @@ void loop() {
#endif #endif
#ifdef ENABLE_MQTT #ifdef ENABLE_MQTT
if (WiFi.status() != WL_CONNECTED) {
#ifdef ENABLE_HOMEASSISTANT
ha_send_data.detach();
#endif
DBG_OUTPUT_PORT.println("WiFi disconnected, reconnecting!");
WiFi.disconnect();
WiFi.setSleepMode(WIFI_NONE_SLEEP);
WiFi.mode(WIFI_STA);
WiFi.begin();
} else {
if (mqtt_host != "" && String(mqtt_port).toInt() > 0 && mqtt_reconnect_retries < MQTT_MAX_RECONNECT_TRIES) { if (mqtt_host != "" && String(mqtt_port).toInt() > 0 && mqtt_reconnect_retries < MQTT_MAX_RECONNECT_TRIES) {
if (!mqtt_client.connected()) { if (!mqtt_client.connected()) {
#ifdef ENABLE_HOMEASSISTANT
ha_send_data.detach();
#endif
DBG_OUTPUT_PORT.println("MQTT disconnected, reconnecting!");
mqtt_reconnect(); mqtt_reconnect();
} else { } else {
mqtt_client.loop(); mqtt_client.loop();
} }
} }
}
#endif
#ifdef ENABLE_HOMEASSISTANT
// if(!ha_send_data.active()) ha_send_data.once(5, tickerSendState);
if (new_ha_mqtt_msg) sendState();
#endif #endif
// Simple statemachine that handles the different modes // Simple statemachine that handles the different modes
@ -624,8 +866,9 @@ void loop() {
mode = HOLD; mode = HOLD;
} }
if (mode == OFF) { if (mode == OFF) {
strip.setColor(0,0,0); // strip.setColor(0,0,0);
strip.setMode(FX_MODE_STATIC); // strip.setMode(FX_MODE_STATIC);
if(strip.isRunning()) strip.stop(); //should clear memory
// mode = HOLD; // mode = HOLD;
} }
if (mode == ALL) { if (mode == ALL) {
@ -633,6 +876,18 @@ void loop() {
strip.setMode(FX_MODE_STATIC); strip.setMode(FX_MODE_STATIC);
mode = HOLD; mode = HOLD;
} }
if (mode == SETCOLOR) {
strip.setColor(main_color.red, main_color.green, main_color.blue);
mode = HOLD;
}
if (mode == SETSPEED) {
strip.setSpeed(convertSpeed(ws2812fx_speed));
// mode = HOLD;
}
if (mode == BRIGHTNESS) {
strip.setBrightness(brightness);
mode = HOLD;
}
if (mode == WIPE) { if (mode == WIPE) {
strip.setColor(main_color.red, main_color.green, main_color.blue); strip.setColor(main_color.red, main_color.green, main_color.blue);
strip.setMode(FX_MODE_COLOR_WIPE); strip.setMode(FX_MODE_COLOR_WIPE);
@ -661,11 +916,13 @@ void loop() {
mode = HOLD; mode = HOLD;
} }
if (mode == HOLD || mode == CUSTOM) { if (mode == HOLD || mode == CUSTOM) {
if(!strip.isRunning()) strip.start();
if (exit_func) { if (exit_func) {
exit_func = false; exit_func = false;
} }
} }
if (mode == TV) { if (mode == TV) {
if(!strip.isRunning()) strip.start();
tv(); tv();
} }
@ -674,8 +931,13 @@ void loop() {
strip.service(); strip.service();
} }
#ifdef ENABLE_STATE_SAVE_SPIFFS
if (updateStateFS) {
(writeStateFS()) ? DBG_OUTPUT_PORT.println(" Success!") : DBG_OUTPUT_PORT.println(" Failure!");
}
#endif
#ifdef ENABLE_STATE_SAVE #ifdef ENABLE_STATE_SAVE_EEPROM
// Check for state changes // Check for state changes
sprintf(current_state, "STA|%2d|%3d|%3d|%3d|%3d|%3d|%3d", mode, strip.getMode(), ws2812fx_speed, brightness, main_color.red, main_color.green, main_color.blue); sprintf(current_state, "STA|%2d|%3d|%3d|%3d|%3d|%3d|%3d", mode, strip.getMode(), ws2812fx_speed, brightness, main_color.red, main_color.green, main_color.blue);

View file

@ -1,16 +1,31 @@
//#define USE_NEOANIMATIONFX // Uses NeoAnimationFX, PIN is ignored & set to RX/GPIO3
#define USE_WS2812FX // Uses WS2812FX
// Neopixel // Neopixel
#define PIN 5 // PIN (5 / D1) where neopixel / WS2811 strip is attached #define PIN 5 // PIN (14 / D5) where neopixel / WS2811 strip is attached
#define NUMLEDS 24 // Number of leds in the strip #define NUMLEDS 24 // 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 BUILTIN_LED 2 // ESP-12F has the built in LED on GPIO2, see https://github.com/esp8266/Arduino/issues/2192
#define BUTTON 4 // Input pin (4 / D2) for switching the LED strip on / off, connect this PIN to ground to trigger button. #define BUTTON 4 // Input pin (4 / D2) for switching the LED strip on / off, connect this PIN to ground to trigger button.
const char HOSTNAME[] = "McLighting01"; // Friedly hostname const char HOSTNAME[] = "McLighting01"; // Friedly hostname
//#define HTTP_OTA // If defined, enable Added ESP8266HTTPUpdateServer
#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, see: https://github.com/toblum/McLighting/wiki/MQTT-API #define ENABLE_MQTT // If defined, enable MQTT client code, see: https://github.com/toblum/McLighting/wiki/MQTT-API
#define ENABLE_HOMEASSISTANT // If defined, enable Homeassistant integration, ENABLE_MQTT must be active #define ENABLE_HOMEASSISTANT // If defined, enable Homeassistant integration, ENABLE_MQTT must be active
// #define ENABLE_BUTTON // If defined, enable button handling code, see: https://github.com/toblum/McLighting/wiki/Button-control #define ENABLE_BUTTON // If defined, enable button handling code, see: https://github.com/toblum/McLighting/wiki/Button-control
#if defined(USE_NEOANIMATIONFX) and defined(USE_WS2812FX)
#error "Cant have both NeoAnimationFX and WS2812FX enabled. Choose either one."
#endif
#if !defined(USE_NEOANIMATIONFX) and !defined(USE_WS2812FX)
#error "Need to either use NeoAnimationFX and WS2812FX mode."
#endif
#if defined(ENABLE_MQTT) and defined(ENABLE_AMQTT)
#error "Cant have both PubSubClient and AsyncMQTT enabled. Choose either one."
#endif
#if ( (defined(ENABLE_HOMEASSISTANT) and !defined(ENABLE_MQTT)) and (defined(ENABLE_HOMEASSISTANT) and !defined(ENABLE_AMQTT)) )
#error "To use HA, you have to either enable PubCubClient or AsyncMQTT"
#endif
// parameters for automatically cycling favorite patterns // parameters for automatically cycling favorite patterns
uint32_t autoParams[][4] = { // color, speed, mode, duration (seconds) uint32_t autoParams[][4] = { // color, speed, mode, duration (seconds)
@ -20,33 +35,44 @@ uint32_t autoParams[][4] = { // color, speed, mode, duration (seconds)
{0x0000ff, 200, 42, 15.0} // fireworks for 15 seconds {0x0000ff, 200, 42, 15.0} // fireworks for 15 seconds
}; };
#ifdef ENABLE_MQTT #if defined(ENABLE_MQTT) or defined(ENABLE_AMQTT)
#ifdef ENABLE_MQTT
#define MQTT_MAX_PACKET_SIZE 512 #define MQTT_MAX_PACKET_SIZE 512
#define MQTT_MAX_RECONNECT_TRIES 4 #define MQTT_MAX_RECONNECT_TRIES 4
int mqtt_reconnect_retries = 0; int mqtt_reconnect_retries = 0;
char mqtt_intopic[strlen(HOSTNAME) + 4 + 5]; // Topic in will be: <HOSTNAME>/in char mqtt_intopic[strlen(HOSTNAME) + 4 + 5]; // Topic in will be: <HOSTNAME>/in
char mqtt_outtopic[strlen(HOSTNAME) + 5 + 5]; // Topic out will be: <HOSTNAME>/out char mqtt_outtopic[strlen(HOSTNAME) + 5 + 5]; // Topic out will be: <HOSTNAME>/out
uint8_t qossub = 0; // PubSubClient can sub qos 0 or 1
#endif
#ifdef ENABLE_AMQTT
String mqtt_intopic = String(HOSTNAME) + "/in";
String mqtt_outtopic = String(HOSTNAME) + "/out";
uint8_t qossub = 0; // AMQTT can sub qos 0 or 1 or 2
uint8_t qospub = 0; // AMQTT can pub qos 0 or 1 or 2
#endif
#ifdef ENABLE_HOMEASSISTANT #ifdef ENABLE_HOMEASSISTANT
String mqtt_ha = "home/" + String(HOSTNAME) + "_ha/"; String mqtt_ha = "home/" + String(HOSTNAME) + "_ha/";
String mqtt_ha_state_in = mqtt_ha + "state/in"; String mqtt_ha_state_in = mqtt_ha + "state/in";
String mqtt_ha_state_out = mqtt_ha + "state/out"; String mqtt_ha_state_out = mqtt_ha + "state/out";
String mqtt_ha_speed = mqtt_ha + "speed";
const char* on_cmd = "ON"; const char* on_cmd = "ON";
const char* off_cmd = "OFF"; const char* off_cmd = "OFF";
bool stateOn = false; bool stateOn = false;
bool animation_on = false; bool animation_on = false;
String effectString = "Static"; bool new_ha_mqtt_msg = false;
uint16_t color_temp = 327; // min is 154 and max is 500
#endif #endif
const char * mqtt_clientid = HOSTNAME; // Set ClientID to HOSTNAME to be unique const char mqtt_clientid[] = "NeoPixelsStrip"; // MQTT ClientID
char mqtt_host[64] = ""; char mqtt_host[64] = "";
char mqtt_port[6] = ""; char mqtt_port[6] = "";
char mqtt_user[32] = ""; char mqtt_user[32] = "";
char mqtt_pass[32] = ""; char mqtt_pass[32] = "";
#endif #endif
@ -56,7 +82,7 @@ uint32_t autoParams[][4] = { // color, speed, mode, duration (seconds)
#define DBG_OUTPUT_PORT Serial // Set debug output port #define DBG_OUTPUT_PORT Serial // Set debug output port
// List of all color modes // List of all color modes
enum MODE { SET_MODE, HOLD, OFF, ALL, WIPE, RAINBOW, RAINBOWCYCLE, THEATERCHASE, TWINKLERANDOM, THEATERCHASERAINBOW, TV, CUSTOM }; enum MODE { SET_MODE, HOLD, OFF, ALL, SETCOLOR, SETSPEED, BRIGHTNESS, WIPE, RAINBOW, RAINBOWCYCLE, THEATERCHASE, TWINKLERANDOM, THEATERCHASERAINBOW, TV, CUSTOM };
MODE mode = RAINBOW; // Standard mode that is active when software starts MODE mode = RAINBOW; // Standard mode that is active when software starts
@ -80,14 +106,18 @@ 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 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 #define ENABLE_STATE_SAVE_SPIFFS // If defined, saves state on SPIFFS
#ifdef ENABLE_STATE_SAVE //#define ENABLE_STATE_SAVE_EEPROM // If defined, save state on reboot
#ifdef ENABLE_STATE_SAVE_EEPROM
char current_state[32]; // Keeps the current state representation char current_state[32]; // Keeps the current state representation
char last_state[32]; // Save the last state as string representation char last_state[32]; // Save the last state as string representation
unsigned long time_statechange = 0; // Time when the state last changed unsigned long time_statechange = 0; // Time when the state last changed
int timeout_statechange_save = 5000; // Timeout in ms to wait before state is saved 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 bool state_save_requested = false; // State has to be saved after timeout
#endif #endif
#ifdef ENABLE_STATE_SAVE_SPIFFS
bool updateStateFS = false;
#endif
// Button handling // Button handling
#ifdef ENABLE_BUTTON #ifdef ENABLE_BUTTON
@ -103,3 +133,13 @@ LEDState main_color = { 255, 0, 0 }; // Store the "main color" of the strip use
byte prevKeyState = HIGH; // button is active low byte prevKeyState = HIGH; // button is active low
boolean buttonState = false; boolean buttonState = false;
#endif #endif
#define PIN 14 // PIN (14 / D5) where neopixel / WS2811 strip is attached
#define NUMLEDS 300 // 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 0 // Input pin (4 / D2) for switching the LED strip on / off, connect this PIN to ground to trigger button.
#define HTTP_OTA // If defined, enable ESP8266HTTPUpdateServer OTA code.
//#define ENABLE_OTA // If defined, enable Arduino OTA code.
#define ENABLE_AMQTT // If defined, enable Async MQTT code, see: https://github.com/marvinroger/async-mqtt-client
//#define ENABLE_MQTT // If defined, enable MQTT client code, see: https://github.com/toblum/McLighting/wiki/MQTT-API
const char * mqtt_clientid = HOSTNAME; // Set ClientID to HOSTNAME to be unique

View file

@ -1,6 +1,17 @@
// *************************************************************************** // ***************************************************************************
// Request handlers // Request handlers
// *************************************************************************** // ***************************************************************************
#ifdef ENABLE_HOMEASSISTANT
void tickerSendState(){
new_ha_mqtt_msg = true;
}
#endif
#ifdef ENABLE_STATE_SAVE_SPIFFS
void tickerSpiffsSaveState(){
updateStateFS = true;
}
#endif
void getArgs() { void getArgs() {
if (server.arg("rgb") != "") { if (server.arg("rgb") != "") {
uint32_t rgb = (uint32_t) strtol(server.arg("rgb").c_str(), NULL, 16); uint32_t rgb = (uint32_t) strtol(server.arg("rgb").c_str(), NULL, 16);
@ -40,8 +51,9 @@ void getArgs() {
} }
long convertSpeed(int mcl_speed) { uint16_t convertSpeed(uint8_t mcl_speed) {
long ws2812_speed = mcl_speed * 256; //long ws2812_speed = mcl_speed * 256;
uint16_t ws2812_speed = 61760 * (exp(0.0002336 * mcl_speed) - exp(-0.03181 * mcl_speed));
ws2812_speed = SPEED_MAX - ws2812_speed; ws2812_speed = SPEED_MAX - ws2812_speed;
if (ws2812_speed < SPEED_MIN) { if (ws2812_speed < SPEED_MIN) {
ws2812_speed = SPEED_MIN; ws2812_speed = SPEED_MIN;
@ -286,33 +298,6 @@ void getModesJSON() {
server.send ( 200, "application/json", listModesJSON() ); server.send ( 200, "application/json", listModesJSON() );
} }
#ifdef ENABLE_HOMEASSISTANT
/********************************** START SEND STATE*****************************************/
void sendState() {
StaticJsonBuffer<JSON_OBJECT_SIZE(10)> jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
root["state"] = (stateOn) ? on_cmd : off_cmd;
JsonObject& color = root.createNestedObject("color");
color["r"] = main_color.red;
color["g"] = main_color.green;
color["b"] = main_color.blue;
root["brightness"] = brightness;
char modeName[30];
strncpy_P(modeName, (PGM_P)strip.getModeName(strip.getMode()), sizeof(modeName)); // copy from progmem
root["effect"] = modeName;
char buffer[root.measureLength() + 1];
root.printTo(buffer, sizeof(buffer));
mqtt_client.publish(mqtt_ha_state_out.c_str(), buffer, true);
}
#endif
// *************************************************************************** // ***************************************************************************
// HTTP request handlers // HTTP request handlers
// *************************************************************************** // ***************************************************************************
@ -408,9 +393,18 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t lenght
handleSetMainColor(payload); handleSetMainColor(payload);
DBG_OUTPUT_PORT.printf("Set main color to: [%u] [%u] [%u]\n", main_color.red, main_color.green, main_color.blue); 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"); webSocket.sendTXT(num, "OK");
#ifdef ENABLE_MQTT
mqtt_client.publish(mqtt_outtopic, String(String("OK ") + String((char *)payload)).c_str());
#endif
#ifdef ENABLE_AMQTT
amqttClient.publish(mqtt_outtopic.c_str(), qospub, false, String(String("OK ") + String((char *)payload)).c_str());
#endif
#ifdef ENABLE_HOMEASSISTANT #ifdef ENABLE_HOMEASSISTANT
stateOn = true; stateOn = true;
sendState(); if(!ha_send_data.active()) ha_send_data.once(5, tickerSendState);
#endif
#ifdef ENABLE_STATE_SAVE_SPIFFS
if(!spiffs_save_state.active()) spiffs_save_state.once(3, tickerSpiffsSaveState);
#endif #endif
} }
@ -421,6 +415,15 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t lenght
strip.setSpeed(convertSpeed(ws2812fx_speed)); strip.setSpeed(convertSpeed(ws2812fx_speed));
DBG_OUTPUT_PORT.printf("WS: Set speed to: [%u]\n", ws2812fx_speed); DBG_OUTPUT_PORT.printf("WS: Set speed to: [%u]\n", ws2812fx_speed);
webSocket.sendTXT(num, "OK"); webSocket.sendTXT(num, "OK");
#ifdef ENABLE_HOMEASSISTANT
if(!ha_send_data.active()) ha_send_data.once(5, tickerSendState);
#endif
#ifdef ENABLE_MQTT
mqtt_client.publish(mqtt_outtopic, String(String("OK ") + String((char *)payload)).c_str());
#endif
#ifdef ENABLE_AMQTT
amqttClient.publish(mqtt_outtopic.c_str(), qospub, false, String(String("OK ") + String((char *)payload)).c_str());
#endif
} }
// % ==> Set brightness // % ==> Set brightness
@ -430,9 +433,18 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t lenght
DBG_OUTPUT_PORT.printf("WS: Set brightness to: [%u]\n", brightness); DBG_OUTPUT_PORT.printf("WS: Set brightness to: [%u]\n", brightness);
strip.setBrightness(brightness); strip.setBrightness(brightness);
webSocket.sendTXT(num, "OK"); webSocket.sendTXT(num, "OK");
#ifdef ENABLE_MQTT
mqtt_client.publish(mqtt_outtopic, String(String("OK ") + String((char *)payload)).c_str());
#endif
#ifdef ENABLE_AMQTT
amqttClient.publish(mqtt_outtopic.c_str(), qospub, false, String(String("OK ") + String((char *)payload)).c_str());
#endif
#ifdef ENABLE_HOMEASSISTANT #ifdef ENABLE_HOMEASSISTANT
stateOn = true; stateOn = true;
sendState(); if(!ha_send_data.active()) ha_send_data.once(5, tickerSendState);
#endif
#ifdef ENABLE_STATE_SAVE_SPIFFS
if(!spiffs_save_state.active()) spiffs_save_state.once(3, tickerSpiffsSaveState);
#endif #endif
} }
@ -440,9 +452,18 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t lenght
if (payload[0] == '*') { if (payload[0] == '*') {
handleSetAllMode(payload); handleSetAllMode(payload);
webSocket.sendTXT(num, "OK"); webSocket.sendTXT(num, "OK");
#ifdef ENABLE_MQTT
mqtt_client.publish(mqtt_outtopic, String(String("OK ") + String((char *)payload)).c_str());
#endif
#ifdef ENABLE_AMQTT
amqttClient.publish(mqtt_outtopic.c_str(), qospub, false, String(String("OK ") + String((char *)payload)).c_str());
#endif
#ifdef ENABLE_HOMEASSISTANT #ifdef ENABLE_HOMEASSISTANT
stateOn = true; stateOn = true;
sendState(); if(!ha_send_data.active()) ha_send_data.once(5, tickerSendState);
#endif
#ifdef ENABLE_STATE_SAVE_SPIFFS
if(!spiffs_save_state.active()) spiffs_save_state.once(3, tickerSpiffsSaveState);
#endif #endif
} }
@ -450,18 +471,36 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t lenght
if (payload[0] == '!') { if (payload[0] == '!') {
handleSetSingleLED(payload, 1); handleSetSingleLED(payload, 1);
webSocket.sendTXT(num, "OK"); webSocket.sendTXT(num, "OK");
#ifdef ENABLE_MQTT
mqtt_client.publish(mqtt_outtopic, String(String("OK ") + String((char *)payload)).c_str());
#endif
#ifdef ENABLE_AMQTT
amqttClient.publish(mqtt_outtopic.c_str(), qospub, false, String(String("OK ") + String((char *)payload)).c_str());
#endif
} }
// + ==> Set multiple LED in the given colors // + ==> Set multiple LED in the given colors
if (payload[0] == '+') { if (payload[0] == '+') {
handleSetDifferentColors(payload); handleSetDifferentColors(payload);
webSocket.sendTXT(num, "OK"); webSocket.sendTXT(num, "OK");
#ifdef ENABLE_MQTT
mqtt_client.publish(mqtt_outtopic, String(String("OK ") + String((char *)payload)).c_str());
#endif
#ifdef ENABLE_AMQTT
amqttClient.publish(mqtt_outtopic.c_str(), qospub, false, String(String("OK ") + String((char *)payload)).c_str());
#endif
} }
// + ==> Set range of LEDs in the given color // + ==> Set range of LEDs in the given color
if (payload[0] == 'R') { if (payload[0] == 'R') {
handleRangeDifferentColors(payload); handleRangeDifferentColors(payload);
webSocket.sendTXT(num, "OK"); webSocket.sendTXT(num, "OK");
#ifdef ENABLE_MQTT
mqtt_client.publish(mqtt_outtopic, String(String("OK ") + String((char *)payload)).c_str());
#endif
#ifdef ENABLE_AMQTT
amqttClient.publish(mqtt_outtopic.c_str(), qospub, false, String(String("OK ") + String((char *)payload)).c_str());
#endif
} }
// = ==> Activate named mode // = ==> Activate named mode
@ -473,8 +512,17 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t lenght
DBG_OUTPUT_PORT.printf("Activated mode [%u]!\n", mode); DBG_OUTPUT_PORT.printf("Activated mode [%u]!\n", mode);
webSocket.sendTXT(num, "OK"); webSocket.sendTXT(num, "OK");
#ifdef ENABLE_MQTT
mqtt_client.publish(mqtt_outtopic, String(String("OK ") + String((char *)payload)).c_str());
#endif
#ifdef ENABLE_AMQTT
amqttClient.publish(mqtt_outtopic.c_str(), qospub, false, String(String("OK ") + String((char *)payload)).c_str());
#endif
#ifdef ENABLE_HOMEASSISTANT #ifdef ENABLE_HOMEASSISTANT
sendState(); if(!ha_send_data.active()) ha_send_data.once(5, tickerSendState);
#endif
#ifdef ENABLE_STATE_SAVE_SPIFFS
if(!spiffs_save_state.active()) spiffs_save_state.once(3, tickerSpiffsSaveState);
#endif #endif
} }
@ -485,6 +533,13 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t lenght
String json = listStatusJSON(); String json = listStatusJSON();
DBG_OUTPUT_PORT.println(json); DBG_OUTPUT_PORT.println(json);
webSocket.sendTXT(num, json); webSocket.sendTXT(num, json);
#ifdef ENABLE_MQTT
mqtt_client.publish(mqtt_outtopic, listStatusJSON());
#endif
#ifdef ENABLE_AMQTT
String liststat = (String) listStatusJSON();
amqttClient.publish(mqtt_outtopic.c_str(), qospub, false, liststat.c_str());
#endif
} }
// ~ ==> Get WS2812 modes. // ~ ==> Get WS2812 modes.
@ -494,15 +549,36 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t lenght
String json = listModesJSON(); String json = listModesJSON();
DBG_OUTPUT_PORT.println(json); DBG_OUTPUT_PORT.println(json);
webSocket.sendTXT(num, json); webSocket.sendTXT(num, json);
#ifdef ENABLE_MQTT
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());
#endif
#ifdef ENABLE_AMQTT
amqttClient.publish(mqtt_outtopic.c_str(), qospub, false, String("ERROR: Not implemented. Message too large for AsyncMQTT.").c_str());
#endif
} }
// / ==> Set WS2812 mode. // / ==> Set WS2812 mode.
if (payload[0] == '/') { if (payload[0] == '/') {
handleSetWS2812FXMode(payload); handleSetWS2812FXMode(payload);
webSocket.sendTXT(num, "OK"); webSocket.sendTXT(num, "OK");
#ifdef ENABLE_MQTT
mqtt_client.publish(mqtt_outtopic, String(String("OK ") + String((char *)payload)).c_str());
#endif
#ifdef ENABLE_AMQTT
amqttClient.publish(mqtt_outtopic.c_str(), qospub, false, String(String("OK ") + String((char *)payload)).c_str());
#endif
#ifdef ENABLE_HOMEASSISTANT #ifdef ENABLE_HOMEASSISTANT
stateOn = true; stateOn = true;
sendState(); if(!ha_send_data.active()) ha_send_data.once(5, tickerSendState);
#endif
#ifdef ENABLE_STATE_SAVE_SPIFFS
if(!spiffs_save_state.active()) spiffs_save_state.once(3, tickerSpiffsSaveState);
#endif #endif
} }
@ -533,24 +609,25 @@ void checkForRequests() {
// *************************************************************************** // ***************************************************************************
// MQTT callback / connection handler // MQTT callback / connection handler
// *************************************************************************** // ***************************************************************************
#ifdef ENABLE_MQTT #if defined(ENABLE_MQTT) or defined(ENABLE_AMQTT)
#ifdef ENABLE_HOMEASSISTANT #ifdef ENABLE_HOMEASSISTANT
void temp2rgb(unsigned int kelvin) { LEDState temp2rgb(unsigned int kelvin) {
int tmp_internal = kelvin / 100.0; int tmp_internal = kelvin / 100.0;
LEDState tmp_color;
// red // red
if (tmp_internal <= 66) { if (tmp_internal <= 66) {
main_color.red = 255; tmp_color.red = 255;
} else { } else {
float tmp_red = 329.698727446 * pow(tmp_internal - 60, -0.1332047592); float tmp_red = 329.698727446 * pow(tmp_internal - 60, -0.1332047592);
if (tmp_red < 0) { if (tmp_red < 0) {
main_color.red = 0; tmp_color.red = 0;
} else if (tmp_red > 255) { } else if (tmp_red > 255) {
main_color.red = 255; tmp_color.red = 255;
} else { } else {
main_color.red = tmp_red; tmp_color.red = tmp_red;
} }
} }
@ -558,142 +635,203 @@ void checkForRequests() {
if (tmp_internal <= 66) { if (tmp_internal <= 66) {
float tmp_green = 99.4708025861 * log(tmp_internal) - 161.1195681661; float tmp_green = 99.4708025861 * log(tmp_internal) - 161.1195681661;
if (tmp_green < 0) { if (tmp_green < 0) {
main_color.green = 0; tmp_color.green = 0;
} else if (tmp_green > 255) { } else if (tmp_green > 255) {
main_color.green = 255; tmp_color.green = 255;
} else { } else {
main_color.green = tmp_green; tmp_color.green = tmp_green;
} }
} else { } else {
float tmp_green = 288.1221695283 * pow(tmp_internal - 60, -0.0755148492); float tmp_green = 288.1221695283 * pow(tmp_internal - 60, -0.0755148492);
if (tmp_green < 0) { if (tmp_green < 0) {
main_color.green = 0; tmp_color.green = 0;
} else if (tmp_green > 255) { } else if (tmp_green > 255) {
main_color.green = 255; tmp_color.green = 255;
} else { } else {
main_color.green = tmp_green; tmp_color.green = tmp_green;
} }
} }
// blue // blue
if (tmp_internal >= 66) { if (tmp_internal >= 66) {
main_color.blue = 255; tmp_color.blue = 255;
} else if (tmp_internal <= 19) { } else if (tmp_internal <= 19) {
main_color.blue = 0; tmp_color.blue = 0;
} else { } else {
float tmp_blue = 138.5177312231 * log(tmp_internal - 10) - 305.0447927307; float tmp_blue = 138.5177312231 * log(tmp_internal - 10) - 305.0447927307;
if (tmp_blue < 0) { if (tmp_blue < 0) {
main_color.blue = 0; tmp_color.blue = 0;
} else if (tmp_blue > 255) { } else if (tmp_blue > 255) {
main_color.blue = 255; tmp_color.blue = 255;
} else { } else {
main_color.blue = tmp_blue; tmp_color.blue = tmp_blue;
} }
} }
return tmp_color;
}
//handleSetWS2812FXMode((uint8_t *) "/0"); void sendState() {
strip.setColor(main_color.red, main_color.green, main_color.blue); const size_t bufferSize = JSON_OBJECT_SIZE(3) + JSON_OBJECT_SIZE(6);
strip.start(); //StaticJsonBuffer<bufferSize> jsonBuffer;
DynamicJsonBuffer jsonBuffer(bufferSize);
JsonObject& root = jsonBuffer.createObject();
root["state"] = (stateOn) ? on_cmd : off_cmd;
JsonObject& color = root.createNestedObject("color");
color["r"] = main_color.red;
color["g"] = main_color.green;
color["b"] = main_color.blue;
root["brightness"] = brightness;
root["color_temp"] = color_temp;
root["speed"] = ws2812fx_speed;
char modeName[30];
strncpy_P(modeName, (PGM_P)strip.getModeName(strip.getMode()), sizeof(modeName)); // copy from progmem
root["effect"] = modeName;
char buffer[root.measureLength() + 1];
root.printTo(buffer, sizeof(buffer));
#ifdef ENABLE_MQTT
mqtt_client.publish(mqtt_ha_state_out.c_str(), buffer, true);
DBG_OUTPUT_PORT.printf("MQTT: Send [%s]: %s\n", mqtt_ha_state_out.c_str(), buffer);
#endif
#ifdef ENABLE_AMQTT
amqttClient.publish(mqtt_ha_state_out.c_str(), 1, true, buffer);
DBG_OUTPUT_PORT.printf("MQTT: Send [%s]: %s\n", mqtt_ha_state_out.c_str(), buffer);
#endif
new_ha_mqtt_msg = false;
ha_send_data.detach();
DBG_OUTPUT_PORT.printf("Heap size: %u\n", ESP.getFreeHeap());
} }
bool processJson(char* message) { bool processJson(char* message) {
StaticJsonBuffer<JSON_OBJECT_SIZE(10)> jsonBuffer; const size_t bufferSize = JSON_OBJECT_SIZE(3) + JSON_OBJECT_SIZE(5) + 150;
//StaticJsonBuffer<bufferSize> jsonBuffer;
DynamicJsonBuffer jsonBuffer(bufferSize);
JsonObject& root = jsonBuffer.parseObject(message); JsonObject& root = jsonBuffer.parseObject(message);
if (!root.success()) { if (!root.success()) {
Serial.println("parseObject() failed"); DBG_OUTPUT_PORT.println("parseObject() failed");
return false; return false;
} }
//DBG_OUTPUT_PORT.println("JSON ParseObject() done!");
if (root.containsKey("state")) { if (root.containsKey("state")) {
if (strcmp(root["state"], on_cmd) == 0 and !(animation_on)) { const char* state_in = root["state"];
if (strcmp(state_in, on_cmd) == 0 and !(animation_on)) {
stateOn = true; stateOn = true;
mode = ALL; mode = ALL;
strip.setColor(main_color.red, main_color.green, main_color.blue);
strip.start();
} }
else if (strcmp(root["state"], off_cmd) == 0) { else if (strcmp(state_in, off_cmd) == 0) {
stateOn = false; stateOn = false;
mode = OFF;
animation_on = false; animation_on = false;
strip.start(); mode = OFF;
return true;
} }
} }
if (root.containsKey("color")) { if (root.containsKey("color")) {
main_color.red = root["color"]["r"]; JsonObject& color = root["color"];
main_color.green = root["color"]["g"]; main_color.red = (uint8_t) color["r"];
main_color.blue = root["color"]["b"]; main_color.green = (uint8_t) color["g"];
//handleSetWS2812FXMode((uint8_t *) "/0"); main_color.blue = (uint8_t) color["b"];
strip.setColor(main_color.red, main_color.green, main_color.blue); mode = SETCOLOR;
strip.start(); }
if (root.containsKey("speed")) {
uint8_t json_speed = constrain((uint8_t) root["speed"], 0, 255);
if (json_speed != ws2812fx_speed) {
ws2812fx_speed = json_speed;
mode = SETSPEED;
}
} }
if (root.containsKey("color_temp")) { if (root.containsKey("color_temp")) {
//temp comes in as mireds, need to convert to kelvin then to RGB //temp comes in as mireds, need to convert to kelvin then to RGB
int color_temp = root["color_temp"]; color_temp = (uint16_t) root["color_temp"];
unsigned int kelvin = 1000000 / color_temp; unsigned int kelvin = 1000000 / color_temp;
main_color = temp2rgb(kelvin);
temp2rgb(kelvin); mode = SETCOLOR;
} }
if (root.containsKey("brightness")) { if (root.containsKey("brightness")) {
const char * brightness_json = root["brightness"]; const char * brightness_json = root["brightness"];
uint8_t b = (uint8_t) strtol((const char *) &brightness_json[0], NULL, 10); uint8_t b = (uint8_t) strtol((const char *) &brightness_json[0], NULL, 10);
brightness = constrain(b, 0, 255); brightness = constrain(b, 0, 255);
strip.setBrightness(brightness); mode = BRIGHTNESS;
} }
if (root.containsKey("effect")) { if (root.containsKey("effect")) {
animation_on = true; animation_on = true;
effectString = String((const char *)root["effect"]); String effectString = root["effect"].asString();
for (uint8_t i = 0; i < strip.getModeCount(); i++) { for (uint8_t i = 0; i < strip.getModeCount(); i++) {
if(String(strip.getModeName(i)) == effectString) { if(String(strip.getModeName(i)) == effectString) {
mode = HOLD; mode = SET_MODE;
strip.setColor(main_color.red, main_color.green, main_color.blue); ws2812fx_mode = i;
strip.setMode(i);
strip.start();
break; break;
} }
} }
} }
jsonBuffer.clear();
return true; return true;
} }
#endif #endif
#ifdef ENABLE_AMQTT
void onMqttMessage(char* topic, char* payload_in, AsyncMqttClientMessageProperties properties, size_t length, size_t index, size_t total) {
DBG_OUTPUT_PORT.print("MQTT: Recieved ["); DBG_OUTPUT_PORT.print(topic);
// DBG_OUTPUT_PORT.print("]: "); DBG_OUTPUT_PORT.println(payload_in);
uint8_t * payload = (uint8_t *) malloc(length + 1);
memcpy(payload, payload_in, length);
payload[length] = NULL;
DBG_OUTPUT_PORT.printf("]: %s\n", payload);
#endif
#ifdef ENABLE_MQTT
void mqtt_callback(char* topic, byte* payload_in, unsigned int length) { void mqtt_callback(char* topic, byte* payload_in, unsigned int length) {
uint8_t * payload = (uint8_t *)malloc(length + 1); uint8_t * payload = (uint8_t *)malloc(length + 1);
memcpy(payload, payload_in, length); memcpy(payload, payload_in, length);
payload[length] = NULL; payload[length] = NULL;
DBG_OUTPUT_PORT.printf("MQTT: Message arrived [%s]\n", payload); DBG_OUTPUT_PORT.printf("MQTT: Message arrived [%s]\n", payload);
#endif
#ifdef ENABLE_HOMEASSISTANT #ifdef ENABLE_HOMEASSISTANT
if (strcmp(topic, mqtt_ha_state_in.c_str()) == 0) { if (strcmp(topic, mqtt_ha_state_in.c_str()) == 0) {
if (!processJson((char*)payload)) { if (!processJson((char*)payload)) {
return; return;
} }
sendState(); if(!ha_send_data.active()) ha_send_data.once(5, tickerSendState);
#ifdef ENABLE_STATE_SAVE_SPIFFS
} else if (strcmp(topic, mqtt_ha_speed.c_str()) == 0) { if(!spiffs_save_state.active()) spiffs_save_state.once(3, tickerSpiffsSaveState);
uint8_t d = (uint8_t) strtol((const char *) &payload[0], NULL, 10); #endif
ws2812fx_speed = constrain(d, 0, 255); #ifdef ENABLE_MQTT
strip.setSpeed(convertSpeed(ws2812fx_speed));
} else if (strcmp(topic, (char *)mqtt_intopic) == 0) { } else if (strcmp(topic, (char *)mqtt_intopic) == 0) {
#endif
#ifdef ENABLE_AMQTT
} else if (strcmp(topic, mqtt_intopic.c_str()) == 0) {
#endif
#endif #endif
// # ==> Set main color // # ==> Set main color
if (payload[0] == '#') { if (payload[0] == '#') {
handleSetMainColor(payload); handleSetMainColor(payload);
DBG_OUTPUT_PORT.printf("MQTT: Set main color to [%u] [%u] [%u]\n", main_color.red, main_color.green, main_color.blue); DBG_OUTPUT_PORT.printf("MQTT: Set main color to [%u] [%u] [%u]\n", main_color.red, main_color.green, main_color.blue);
#ifdef ENABLE_MQTT
mqtt_client.publish(mqtt_outtopic, String(String("OK ") + String((char *)payload)).c_str()); mqtt_client.publish(mqtt_outtopic, String(String("OK ") + String((char *)payload)).c_str());
#endif
#ifdef ENABLE_AMQTT
amqttClient.publish(mqtt_outtopic.c_str(), qospub, false, String(String("OK ") + String((char *)payload)).c_str());
#endif
#ifdef ENABLE_HOMEASSISTANT #ifdef ENABLE_HOMEASSISTANT
stateOn = true; stateOn = true;
sendState(); if(!ha_send_data.active()) ha_send_data.once(5, tickerSendState);
#endif
#ifdef ENABLE_STATE_SAVE_SPIFFS
if(!spiffs_save_state.active()) spiffs_save_state.once(3, tickerSpiffsSaveState);
#endif #endif
} }
@ -703,7 +841,15 @@ void checkForRequests() {
ws2812fx_speed = constrain(d, 0, 255); ws2812fx_speed = constrain(d, 0, 255);
strip.setSpeed(convertSpeed(ws2812fx_speed)); strip.setSpeed(convertSpeed(ws2812fx_speed));
DBG_OUTPUT_PORT.printf("MQTT: Set speed to [%u]\n", ws2812fx_speed); DBG_OUTPUT_PORT.printf("MQTT: Set speed to [%u]\n", ws2812fx_speed);
#ifdef ENABLE_HOMEASSISTANT
if(!ha_send_data.active()) ha_send_data.once(5, tickerSendState);
#endif
#ifdef ENABLE_MQTT
mqtt_client.publish(mqtt_outtopic, String(String("OK ") + String((char *)payload)).c_str()); mqtt_client.publish(mqtt_outtopic, String(String("OK ") + String((char *)payload)).c_str());
#endif
#ifdef ENABLE_AMQTT
amqttClient.publish(mqtt_outtopic.c_str(), qospub, false, String(String("OK ") + String((char *)payload)).c_str());
#endif
} }
// % ==> Set brightness // % ==> Set brightness
@ -712,10 +858,18 @@ void checkForRequests() {
brightness = constrain(b, 0, 255); brightness = constrain(b, 0, 255);
strip.setBrightness(brightness); strip.setBrightness(brightness);
DBG_OUTPUT_PORT.printf("MQTT: Set brightness to [%u]\n", brightness); DBG_OUTPUT_PORT.printf("MQTT: Set brightness to [%u]\n", brightness);
#ifdef ENABLE_MQTT
mqtt_client.publish(mqtt_outtopic, String(String("OK ") + String((char *)payload)).c_str()); mqtt_client.publish(mqtt_outtopic, String(String("OK ") + String((char *)payload)).c_str());
#endif
#ifdef ENABLE_AMQTT
amqttClient.publish(mqtt_outtopic.c_str(), qospub, false, String(String("OK ") + String((char *)payload)).c_str());
#endif
#ifdef ENABLE_HOMEASSISTANT #ifdef ENABLE_HOMEASSISTANT
stateOn = true; stateOn = true;
sendState(); if(!ha_send_data.active()) ha_send_data.once(5, tickerSendState);
#endif
#ifdef ENABLE_STATE_SAVE_SPIFFS
if(!spiffs_save_state.active()) spiffs_save_state.once(3, tickerSpiffsSaveState);
#endif #endif
} }
@ -723,10 +877,18 @@ void checkForRequests() {
if (payload[0] == '*') { if (payload[0] == '*') {
handleSetAllMode(payload); handleSetAllMode(payload);
DBG_OUTPUT_PORT.printf("MQTT: Set main color and light all LEDs [%s]\n", payload); DBG_OUTPUT_PORT.printf("MQTT: Set main color and light all LEDs [%s]\n", payload);
#ifdef ENABLE_MQTT
mqtt_client.publish(mqtt_outtopic, String(String("OK ") + String((char *)payload)).c_str()); mqtt_client.publish(mqtt_outtopic, String(String("OK ") + String((char *)payload)).c_str());
#endif
#ifdef ENABLE_AMQTT
amqttClient.publish(mqtt_outtopic.c_str(), qospub, false, String(String("OK ") + String((char *)payload)).c_str());
#endif
#ifdef ENABLE_HOMEASSISTANT #ifdef ENABLE_HOMEASSISTANT
stateOn = true; stateOn = true;
sendState(); if(!ha_send_data.active()) ha_send_data.once(5, tickerSendState);
#endif
#ifdef ENABLE_STATE_SAVE_SPIFFS
if(!spiffs_save_state.active()) spiffs_save_state.once(3, tickerSpiffsSaveState);
#endif #endif
} }
@ -734,20 +896,35 @@ void checkForRequests() {
if (payload[0] == '!') { if (payload[0] == '!') {
handleSetSingleLED(payload, 1); handleSetSingleLED(payload, 1);
DBG_OUTPUT_PORT.printf("MQTT: Set single LED in given color [%s]\n", payload); DBG_OUTPUT_PORT.printf("MQTT: Set single LED in given color [%s]\n", payload);
#ifdef ENABLE_MQTT
mqtt_client.publish(mqtt_outtopic, String(String("OK ") + String((char *)payload)).c_str()); mqtt_client.publish(mqtt_outtopic, String(String("OK ") + String((char *)payload)).c_str());
#endif
#ifdef ENABLE_AMQTT
amqttClient.publish(mqtt_outtopic.c_str(), qospub, false, String(String("OK ") + String((char *)payload)).c_str());
#endif
} }
// + ==> Set multiple LED in the given colors // + ==> Set multiple LED in the given colors
if (payload[0] == '+') { if (payload[0] == '+') {
handleSetDifferentColors(payload); handleSetDifferentColors(payload);
#ifdef ENABLE_MQTT
mqtt_client.publish(mqtt_outtopic, String(String("OK ") + String((char *)payload)).c_str()); mqtt_client.publish(mqtt_outtopic, String(String("OK ") + String((char *)payload)).c_str());
#endif
#ifdef ENABLE_AMQTT
amqttClient.publish(mqtt_outtopic.c_str(), qospub, false, String(String("OK ") + String((char *)payload)).c_str());
#endif
} }
// R ==> Set range of LEDs in the given colors // R ==> Set range of LEDs in the given colors
if (payload[0] == 'R') { if (payload[0] == 'R') {
handleRangeDifferentColors(payload); handleRangeDifferentColors(payload);
DBG_OUTPUT_PORT.printf("MQTT: Set range of LEDS to single color: [%s]\n", payload); DBG_OUTPUT_PORT.printf("MQTT: Set range of LEDS to single color: [%s]\n", payload);
#ifdef ENABLE_MQTT
mqtt_client.publish(mqtt_outtopic, String(String("OK ") + String((char *)payload)).c_str()); mqtt_client.publish(mqtt_outtopic, String(String("OK ") + String((char *)payload)).c_str());
#endif
#ifdef ENABLE_AMQTT
amqttClient.publish(mqtt_outtopic.c_str(), qospub, false, String(String("OK ") + String((char *)payload)).c_str());
#endif
} }
// = ==> Activate named mode // = ==> Activate named mode
@ -755,9 +932,17 @@ void checkForRequests() {
String str_mode = String((char *) &payload[0]); String str_mode = String((char *) &payload[0]);
handleSetNamedMode(str_mode); handleSetNamedMode(str_mode);
DBG_OUTPUT_PORT.printf("MQTT: Activate named mode [%s]\n", payload); DBG_OUTPUT_PORT.printf("MQTT: Activate named mode [%s]\n", payload);
#ifdef ENABLE_MQTT
mqtt_client.publish(mqtt_outtopic, String(String("OK ") + String((char *)payload)).c_str()); mqtt_client.publish(mqtt_outtopic, String(String("OK ") + String((char *)payload)).c_str());
#endif
#ifdef ENABLE_AMQTT
amqttClient.publish(mqtt_outtopic.c_str(), qospub, false, String(String("OK ") + String((char *)payload)).c_str());
#endif
#ifdef ENABLE_HOMEASSISTANT #ifdef ENABLE_HOMEASSISTANT
sendState(); if(!ha_send_data.active()) ha_send_data.once(5, tickerSendState);
#endif
#ifdef ENABLE_STATE_SAVE_SPIFFS
if(!spiffs_save_state.active()) spiffs_save_state.once(3, tickerSpiffsSaveState);
#endif #endif
} }
@ -765,7 +950,13 @@ void checkForRequests() {
if (payload[0] == '$') { if (payload[0] == '$') {
DBG_OUTPUT_PORT.printf("MQTT: Get status info.\n"); DBG_OUTPUT_PORT.printf("MQTT: Get status info.\n");
DBG_OUTPUT_PORT.println("MQTT: Out: " + String(listStatusJSON())); DBG_OUTPUT_PORT.println("MQTT: Out: " + String(listStatusJSON()));
#ifdef ENABLE_MQTT
mqtt_client.publish(mqtt_outtopic, listStatusJSON()); mqtt_client.publish(mqtt_outtopic, listStatusJSON());
#endif
#ifdef ENABLE_AMQTT
String liststat = (String) listStatusJSON();
amqttClient.publish(mqtt_outtopic.c_str(), qospub, false, liststat.c_str());
#endif
} }
// ~ ==> Get WS2812 modes. // ~ ==> Get WS2812 modes.
@ -773,6 +964,7 @@ void checkForRequests() {
// Hint: https://github.com/knolleary/pubsubclient/issues/110 // Hint: https://github.com/knolleary/pubsubclient/issues/110
if (payload[0] == '~') { if (payload[0] == '~') {
DBG_OUTPUT_PORT.printf("MQTT: Get WS2812 modes.\n"); DBG_OUTPUT_PORT.printf("MQTT: Get WS2812 modes.\n");
#ifdef ENABLE_MQTT
DBG_OUTPUT_PORT.printf("Error: Not implemented. Message too large for pubsubclient."); 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."); mqtt_client.publish(mqtt_outtopic, "ERROR: Not implemented. Message too large for pubsubclient.");
//String json_modes = listModesJSON(); //String json_modes = listModesJSON();
@ -780,16 +972,28 @@ void checkForRequests() {
//int res = mqtt_client.publish(mqtt_outtopic, json_modes.c_str(), json_modes.length()); //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()); //DBG_OUTPUT_PORT.printf("Result: %d / %d", res, json_modes.length());
#endif
#ifdef ENABLE_AMQTT
amqttClient.publish(mqtt_outtopic.c_str(), qospub, false, String("ERROR: Not implemented. Message too large for AsyncMQTT.").c_str());
#endif
} }
// / ==> Set WS2812 mode. // / ==> Set WS2812 mode.
if (payload[0] == '/') { if (payload[0] == '/') {
handleSetWS2812FXMode(payload); handleSetWS2812FXMode(payload);
DBG_OUTPUT_PORT.printf("MQTT: Set WS2812 mode [%s]\n", payload); DBG_OUTPUT_PORT.printf("MQTT: Set WS2812 mode [%s]\n", payload);
#ifdef ENABLE_MQTT
mqtt_client.publish(mqtt_outtopic, String(String("OK ") + String((char *)payload)).c_str()); mqtt_client.publish(mqtt_outtopic, String(String("OK ") + String((char *)payload)).c_str());
#endif
#ifdef ENABLE_AMQTT
amqttClient.publish(mqtt_outtopic.c_str(), qospub, false, String(String("OK ") + String((char *)payload)).c_str());
#endif
#ifdef ENABLE_HOMEASSISTANT #ifdef ENABLE_HOMEASSISTANT
stateOn = true; stateOn = true;
sendState(); if(!ha_send_data.active()) ha_send_data.once(5, tickerSendState);
#endif
#ifdef ENABLE_STATE_SAVE_SPIFFS
if(!spiffs_save_state.active()) spiffs_save_state.once(3, tickerSpiffsSaveState);
#endif #endif
} }
@ -799,11 +1003,12 @@ void checkForRequests() {
free(payload); free(payload);
} }
#ifdef ENABLE_MQTT
void mqtt_reconnect() { void mqtt_reconnect() {
// Loop until we're reconnected // Loop until we're reconnected
while (!mqtt_client.connected() && mqtt_reconnect_retries < MQTT_MAX_RECONNECT_TRIES) { while (!mqtt_client.connected() && mqtt_reconnect_retries < MQTT_MAX_RECONNECT_TRIES) {
mqtt_reconnect_retries++; mqtt_reconnect_retries++;
DBG_OUTPUT_PORT.printf("Attempting MQTT connection %d / %d (%s) ...\n", mqtt_reconnect_retries, MQTT_MAX_RECONNECT_TRIES, mqtt_clientid); DBG_OUTPUT_PORT.printf("Attempting MQTT connection %d / %d ...\n", mqtt_reconnect_retries, MQTT_MAX_RECONNECT_TRIES);
// Attempt to connect // Attempt to connect
if (mqtt_client.connect(mqtt_clientid, mqtt_user, mqtt_pass)) { if (mqtt_client.connect(mqtt_clientid, mqtt_user, mqtt_pass)) {
DBG_OUTPUT_PORT.println("MQTT connected!"); DBG_OUTPUT_PORT.println("MQTT connected!");
@ -813,11 +1018,10 @@ void checkForRequests() {
strcat(message, HOSTNAME); strcat(message, HOSTNAME);
mqtt_client.publish(mqtt_outtopic, message); mqtt_client.publish(mqtt_outtopic, message);
// ... and resubscribe // ... and resubscribe
mqtt_client.subscribe(mqtt_intopic); mqtt_client.subscribe(mqtt_intopic, qossub, qossub);
#ifdef ENABLE_HOMEASSISTANT #ifdef ENABLE_HOMEASSISTANT
DBG_OUTPUT_PORT.printf("Homeassistant MQTT topic in: %s\n", mqtt_ha_state_in.c_str()); ha_send_data.detach();
mqtt_client.subscribe(mqtt_ha_state_in.c_str()); mqtt_client.subscribe(mqtt_ha_state_in.c_str(), qossub);
mqtt_client.subscribe(mqtt_ha_speed.c_str());
#endif #endif
DBG_OUTPUT_PORT.printf("MQTT topic in: %s\n", mqtt_intopic); DBG_OUTPUT_PORT.printf("MQTT topic in: %s\n", mqtt_intopic);
@ -834,6 +1038,76 @@ void checkForRequests() {
DBG_OUTPUT_PORT.printf("MQTT connection failed, giving up after %d tries ...\n", mqtt_reconnect_retries); DBG_OUTPUT_PORT.printf("MQTT connection failed, giving up after %d tries ...\n", mqtt_reconnect_retries);
} }
} }
#endif
#ifdef ENABLE_AMQTT
void connectToWifi() {
DBG_OUTPUT_PORT.println("Re-connecting to Wi-Fi...");
WiFi.setSleepMode(WIFI_NONE_SLEEP);
WiFi.mode(WIFI_STA);
WiFi.begin();
}
void connectToMqtt() {
DBG_OUTPUT_PORT.println("Connecting to MQTT...");
amqttClient.connect();
}
void onWifiConnect(const WiFiEventStationModeGotIP& event) {
DBG_OUTPUT_PORT.println("Connected to Wi-Fi.");
connectToMqtt();
}
void onWifiDisconnect(const WiFiEventStationModeDisconnected& event) {
DBG_OUTPUT_PORT.println("Disconnected from Wi-Fi.");
#ifdef ENABLE_HOMEASSISTANT
ha_send_data.detach();
#endif
mqttReconnectTimer.detach(); // ensure we don't reconnect to MQTT while reconnecting to Wi-Fi
wifiReconnectTimer.once(2, connectToWifi);
}
void onMqttConnect(bool sessionPresent) {
DBG_OUTPUT_PORT.println("Connected to MQTT.");
DBG_OUTPUT_PORT.print("Session present: ");
DBG_OUTPUT_PORT.println(sessionPresent);
char * message = new char[18 + strlen(HOSTNAME) + 1];
strcpy(message, "McLighting ready: ");
strcat(message, HOSTNAME);
amqttClient.publish(mqtt_outtopic.c_str(), qospub, false, message);
//Subscribe
uint16_t packetIdSub1 = amqttClient.subscribe((char *)mqtt_intopic.c_str(), qossub);
DBG_OUTPUT_PORT.printf("Subscribing at QoS %d, packetId: ", qossub); DBG_OUTPUT_PORT.println(packetIdSub1);
#ifdef ENABLE_HOMEASSISTANT
ha_send_data.detach();
uint16_t packetIdSub2 = amqttClient.subscribe((char *)mqtt_ha_state_in.c_str(), qossub);
DBG_OUTPUT_PORT.printf("Subscribing at QoS %d, packetId: ", qossub); DBG_OUTPUT_PORT.println(packetIdSub2);
#endif
}
void onMqttDisconnect(AsyncMqttClientDisconnectReason reason) {
DBG_OUTPUT_PORT.print("Disconnected from MQTT, reason: ");
if (reason == AsyncMqttClientDisconnectReason::TLS_BAD_FINGERPRINT) {
DBG_OUTPUT_PORT.println("Bad server fingerprint.");
} else if (reason == AsyncMqttClientDisconnectReason::TCP_DISCONNECTED) {
DBG_OUTPUT_PORT.println("TCP Disconnected.");
} else if (reason == AsyncMqttClientDisconnectReason::MQTT_UNACCEPTABLE_PROTOCOL_VERSION) {
DBG_OUTPUT_PORT.println("Bad server fingerprint.");
} else if (reason == AsyncMqttClientDisconnectReason::MQTT_IDENTIFIER_REJECTED) {
DBG_OUTPUT_PORT.println("MQTT Identifier rejected.");
} else if (reason == AsyncMqttClientDisconnectReason::MQTT_SERVER_UNAVAILABLE) {
DBG_OUTPUT_PORT.println("MQTT server unavailable.");
} else if (reason == AsyncMqttClientDisconnectReason::MQTT_MALFORMED_CREDENTIALS) {
DBG_OUTPUT_PORT.println("MQTT malformed credentials.");
} else if (reason == AsyncMqttClientDisconnectReason::MQTT_NOT_AUTHORIZED) {
DBG_OUTPUT_PORT.println("MQTT not authorized.");
} else if (reason == AsyncMqttClientDisconnectReason::ESP8266_NOT_ENOUGH_SPACE) {
DBG_OUTPUT_PORT.println("Not enough space on esp8266.");
}
if (WiFi.isConnected()) {
mqttReconnectTimer.once(5, connectToMqtt);
}
}
#endif
#endif #endif
@ -854,10 +1128,16 @@ void checkForRequests() {
buttonState = false; buttonState = false;
#ifdef ENABLE_MQTT #ifdef ENABLE_MQTT
mqtt_client.publish(mqtt_outtopic, String("OK =off").c_str()); mqtt_client.publish(mqtt_outtopic, String("OK =off").c_str());
#endif
#ifdef ENABLE_AMQTT
amqttClient.publish(mqtt_outtopic.c_str(), qospub, false, String("OK =off").c_str());
#endif
#ifdef ENABLE_HOMEASSISTANT #ifdef ENABLE_HOMEASSISTANT
stateOn = false; stateOn = false;
sendState(); if(!ha_send_data.active()) ha_send_data.once(5, tickerSendState);
#endif #endif
#ifdef ENABLE_STATE_SAVE_SPIFFS
if(!spiffs_save_state.active()) spiffs_save_state.once(3, tickerSpiffsSaveState);
#endif #endif
} }
} }
@ -868,10 +1148,16 @@ void checkForRequests() {
setModeByStateString(BTN_MODE_MEDIUM); setModeByStateString(BTN_MODE_MEDIUM);
#ifdef ENABLE_MQTT #ifdef ENABLE_MQTT
mqtt_client.publish(mqtt_outtopic, String("OK =fire flicker").c_str()); mqtt_client.publish(mqtt_outtopic, String("OK =fire flicker").c_str());
#endif
#ifdef ENABLE_AMQTT
amqttClient.publish(mqtt_outtopic.c_str(), qospub, false, String("OK =fire flicker").c_str());
#endif
#ifdef ENABLE_HOMEASSISTANT #ifdef ENABLE_HOMEASSISTANT
stateOn = true; stateOn = true;
sendState(); if(!ha_send_data.active()) ha_send_data.once(5, tickerSendState);
#endif #endif
#ifdef ENABLE_STATE_SAVE_SPIFFS
if(!spiffs_save_state.active()) spiffs_save_state.once(3, tickerSpiffsSaveState);
#endif #endif
} }
@ -881,10 +1167,16 @@ void checkForRequests() {
setModeByStateString(BTN_MODE_LONG); setModeByStateString(BTN_MODE_LONG);
#ifdef ENABLE_MQTT #ifdef ENABLE_MQTT
mqtt_client.publish(mqtt_outtopic, String("OK =fireworks random").c_str()); mqtt_client.publish(mqtt_outtopic, String("OK =fireworks random").c_str());
#endif
#ifdef ENABLE_AMQTT
amqttClient.publish(mqtt_outtopic.c_str(), qospub, false, String("OK =fireworks random").c_str());
#endif
#ifdef ENABLE_HOMEASSISTANT #ifdef ENABLE_HOMEASSISTANT
stateOn = true; stateOn = true;
sendState(); if(!ha_send_data.active()) ha_send_data.once(5, tickerSendState);
#endif #endif
#ifdef ENABLE_STATE_SAVE_SPIFFS
if(!spiffs_save_state.active()) spiffs_save_state.once(3, tickerSpiffsSaveState);
#endif #endif
} }
@ -918,3 +1210,157 @@ void checkForRequests() {
} }
} }
#endif #endif
#ifdef ENABLE_STATE_SAVE_SPIFFS
bool updateFS = false;
// Write configuration to FS JSON
bool writeConfigFS(bool saveConfig){
if (saveConfig) {
//FS save
updateFS = true;
DBG_OUTPUT_PORT.print("Saving config: ");
DynamicJsonBuffer jsonBuffer(JSON_OBJECT_SIZE(4));
// StaticJsonBuffer<JSON_OBJECT_SIZE(4)> jsonBuffer;
JsonObject& json = jsonBuffer.createObject();
json["mqtt_host"] = mqtt_host;
json["mqtt_port"] = mqtt_port;
json["mqtt_user"] = mqtt_user;
json["mqtt_pass"] = mqtt_pass;
// SPIFFS.remove("/config.json") ? DBG_OUTPUT_PORT.println("removed file") : DBG_OUTPUT_PORT.println("failed removing file");
File configFile = SPIFFS.open("/config.json", "w");
if (!configFile) DBG_OUTPUT_PORT.println("failed to open config file for writing");
json.printTo(DBG_OUTPUT_PORT);
json.printTo(configFile);
configFile.close();
updateFS = false;
return true;
//end save
} else {
DBG_OUTPUT_PORT.println("SaveConfig is False!");
return false;
}
}
// Read search_str to FS
bool readConfigFS() {
//read configuration from FS JSON
updateFS = true;
if (SPIFFS.exists("/config.json")) {
//file exists, reading and loading
DBG_OUTPUT_PORT.print("Reading config file... ");
File configFile = SPIFFS.open("/config.json", "r");
if (configFile) {
DBG_OUTPUT_PORT.println("Opened!");
size_t size = configFile.size();
std::unique_ptr<char[]> buf(new char[size]);
configFile.readBytes(buf.get(), size);
DynamicJsonBuffer jsonBuffer(JSON_OBJECT_SIZE(4)+300);
// StaticJsonBuffer<JSON_OBJECT_SIZE(4)+300> jsonBuffer;
JsonObject& json = jsonBuffer.parseObject(buf.get());
DBG_OUTPUT_PORT.print("Config: ");
json.printTo(DBG_OUTPUT_PORT);
if (json.success()) {
DBG_OUTPUT_PORT.println(" Parsed!");
strcpy(mqtt_host, json["mqtt_host"]);
strcpy(mqtt_port, json["mqtt_port"]);
strcpy(mqtt_user, json["mqtt_user"]);
strcpy(mqtt_pass, json["mqtt_pass"]);
updateFS = false;
return true;
} else {
DBG_OUTPUT_PORT.println("Failed to load json config");
}
} else {
DBG_OUTPUT_PORT.println("Failed to open /config.json");
}
} else {
DBG_OUTPUT_PORT.println("Coudnt find config.json");
}
//end read
updateFS = false;
return false;
}
bool writeStateFS(){
updateFS = true;
//save the strip state to FS JSON
DBG_OUTPUT_PORT.print("Saving cfg: ");
DynamicJsonBuffer jsonBuffer(JSON_OBJECT_SIZE(7));
// StaticJsonBuffer<JSON_OBJECT_SIZE(7)> jsonBuffer;
JsonObject& json = jsonBuffer.createObject();
json["mode"] = static_cast<int>(mode);
json["strip_mode"] = (int) strip.getMode();
json["brightness"] = brightness;
json["speed"] = ws2812fx_speed;
json["red"] = main_color.red;
json["green"] = main_color.green;
json["blue"] = main_color.blue;
// SPIFFS.remove("/state.json") ? DBG_OUTPUT_PORT.println("removed file") : DBG_OUTPUT_PORT.println("failed removing file");
File configFile = SPIFFS.open("/stripstate.json", "w");
if (!configFile) {
DBG_OUTPUT_PORT.println("Failed!");
updateFS = false;
spiffs_save_state.detach();
updateStateFS = false;
return false;
}
json.printTo(DBG_OUTPUT_PORT);
json.printTo(configFile);
configFile.close();
updateFS = false;
spiffs_save_state.detach();
updateStateFS = false;
return true;
//end save
}
bool readStateFS() {
//read strip state from FS JSON
updateFS = true;
//if (resetsettings) { SPIFFS.begin(); SPIFFS.remove("/config.json"); SPIFFS.format(); delay(1000);}
if (SPIFFS.exists("/stripstate.json")) {
//file exists, reading and loading
DBG_OUTPUT_PORT.print("Read cfg: ");
File configFile = SPIFFS.open("/stripstate.json", "r");
if (configFile) {
size_t size = configFile.size();
// Allocate a buffer to store contents of the file.
std::unique_ptr<char[]> buf(new char[size]);
configFile.readBytes(buf.get(), size);
DynamicJsonBuffer jsonBuffer(JSON_OBJECT_SIZE(7)+200);
// StaticJsonBuffer<JSON_OBJECT_SIZE(7)+200> jsonBuffer;
JsonObject& json = jsonBuffer.parseObject(buf.get());
json.printTo(DBG_OUTPUT_PORT);
if (json.success()) {
mode = static_cast<MODE>((int) json["mode"]);
ws2812fx_mode = json["strip_mode"];
brightness = json["brightness"];
ws2812fx_speed = json["speed"];
main_color.red = json["red"];
main_color.green = json["green"];
main_color.blue = json["blue"];
strip.setMode(ws2812fx_mode);
strip.setSpeed(convertSpeed(ws2812fx_speed));
strip.setBrightness(brightness);
strip.setColor(main_color.red, main_color.green, main_color.blue);
updateFS = false;
return true;
} else {
DBG_OUTPUT_PORT.println("Failed to parse JSON!");
}
} else {
DBG_OUTPUT_PORT.println("Failed to open \"/stripstate.json\"");
}
} else {
DBG_OUTPUT_PORT.println("Coudnt find \"/stripstate.json\"");
}
//end read
updateFS = false;
return false;
}
#endif

View file

@ -3,6 +3,7 @@ light:
name: "NeoPixel LEDs" name: "NeoPixel LEDs"
state_topic: "home/McLighting01_ha/state/out" state_topic: "home/McLighting01_ha/state/out"
command_topic: "home/McLighting01_ha/state/in" command_topic: "home/McLighting01_ha/state/in"
on_command_type: 'first'
effect: true effect: true
effect_list: effect_list:
###### ######
@ -62,6 +63,7 @@ light:
- "Tricolor Chase" - "Tricolor Chase"
- "ICU" - "ICU"
brightness: true brightness: true
color_temp: true
rgb: true rgb: true
optimistic: false optimistic: false
qos: 0 qos: 0
@ -77,7 +79,7 @@ input_number:
automation: automation:
- id: 71938579813759813757 - id: 71938579813759813757
alias: NeoPixel Animation Speed alias: NeoPixel Animation Speed Send
initial_state: true initial_state: true
hide_entity: false hide_entity: false
trigger: trigger:
@ -85,7 +87,18 @@ automation:
platform: state platform: state
action: action:
- data_template: - data_template:
payload_template: '{{ trigger.to_state.state | int }}' payload_template: '{"speed": {{ trigger.to_state.state | int }}}'
retain: true retain: true
topic: home/McLighting01_ha/speed topic: home/McLighting01_ha/state/in
service: mqtt.publish service: mqtt.publish
- id: 93786598732698756967
alias: NeoPixel Animation Speed Receive
trigger:
- platform: mqtt
topic: home/McLighting01_ha/state/out
action:
- data_template:
entity_id: input_number.neopixel_animation_speed
value: '{{ trigger.payload_json.speed | int }}'
service: input_number.set_value