diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..40433be
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+.pio
+.vscode
+.DS_Store
\ No newline at end of file
diff --git a/README.md b/README.md
index 5391fe3..0940e16 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,29 @@
-# ESP-NOW-Light-Led-Strip
+# Light/led strip controller for ESP8266
+ESP-NOW based light/led strip controller for ESP8266. Alternate firmware for Tuya/SmartLife WiFi light/led strip controllers.
+
+## Features
+
+1. After turn on (or after rebooting) creates an access point named "ESP-NOW Light XXXXXXXXXXXX" with password "12345678" (IP 192.168.4.1). Access point will be shown during 5 minutes. The rest of the time access point is a hidden.
+2. Periodically transmission of system information (every 60 seconds), availability status (every 10 seconds) and state status (every 300 seconds) to the gateway.
+3. Saves the last state when the power is turned off. Goes to the last state when the power is turned on.
+4. Automatically adds light/led strip configuration to Home Assistan via MQTT discovery as a light.
+5. Possibility firmware update over OTA (if is allows the size of the flash memory).
+6. Web interface for settings.
+
+## Notes
+
+1. ESP-NOW mesh network based on the library [ZHNetwork](https://github.com/aZholtikov/ZHNetwork).
+2. Regardless of the status of connection to gateway the device perform ESP-NOW node function.
+3. For show the access point for setting or firmware update, send the command "update" to the device's root topic (example - "homeassistant/espnow_light/E8DB849CA148"). Access point will be shown during 5 minutes. Similarly, for restart send the command "restart".
+
+## Tested on
+
+Coming soon.
+
+## Attention
+
+1. A gateway is required. For details see [ESP-NOW Gateway](https://github.com/aZholtikov/ESP-NOW-Gateway).
+2. ESP-NOW network name must be set same of all another ESP-NOW devices in network.
+3. Upload the "data" folder (with web interface) into the filesystem before flashing.
+4. For using this firmware on Tuya/SmartLife WiFi light/led strip controllers, the WiFi module must be replaced with an ESP8266 compatible module (if necessary).
diff --git a/data/function.js b/data/function.js
new file mode 100755
index 0000000..fa51261
--- /dev/null
+++ b/data/function.js
@@ -0,0 +1,83 @@
+var xmlHttp = createXmlHttpObject();
+function createXmlHttpObject() {
+ if (window.XMLHttpRequest) {
+ xmlHttp = new XMLHttpRequest();
+ } else {
+ xmlHttp = new ActiveXObject('Microsoft.XMLHTTP');
+ }
+ return xmlHttp;
+}
+
+function load() {
+ if (xmlHttp.readyState == 0 || xmlHttp.readyState == 4) {
+ xmlHttp.open('PUT', '/config.json', true);
+ xmlHttp.send(null);
+ xmlHttp.onload = function () {
+ jsonResponse = JSON.parse(xmlHttp.responseText);
+ loadBlock();
+ }
+ }
+}
+
+function loadBlock() {
+ newData = JSON.parse(xmlHttp.responseText);
+ data = document.getElementsByTagName('body')[0].innerHTML;
+ var newString;
+ for (var key in newData) {
+ newString = data.replace(new RegExp('{{' + key + '}}', 'g'), newData[key]);
+ data = newString;
+ }
+ document.getElementsByTagName('body')[0].innerHTML = newString;
+ setFirmvareValue('version', 'firmware');
+ setGpioValue('ledTypeSelect', 'ledType');
+ setGpioValue('coldWhitePinSelect', 'coldWhitePin');
+ setGpioValue('warmWhitePinSelect', 'warmWhitePin');
+ setGpioValue('redPinSelect', 'redPin');
+ setGpioValue('greenPinSelect', 'greenPin');
+ setGpioValue('bluePinSelect', 'bluePin');
+ handleServerResponse();
+}
+
+function getValue(id) {
+ var value = document.getElementById(id).value;
+ return value;
+}
+
+function getSelectValue(id) {
+ var select = document.getElementById(id);
+ var value = select.value;
+ return value;
+}
+
+function sendRequest(submit, server) {
+ request = new XMLHttpRequest();
+ request.open("GET", server, true);
+ request.send();
+}
+
+function saveSetting(submit) {
+ server = "/setting?deviceName=" + getValue('deviceName')
+ + "&espnowNetName=" + getValue('espnowNetName')
+ + "&ledType=" + getSelectValue('ledTypeSelect')
+ + "&coldWhitePin=" + getSelectValue('coldWhitePinSelect')
+ + "&warmWhitePin=" + getSelectValue('warmWhitePinSelect')
+ + "&redPin=" + getSelectValue('redPinSelect')
+ + "&greenPin=" + getSelectValue('greenPinSelect')
+ + "&bluePin=" + getSelectValue('bluePinSelect');
+ sendRequest(submit, server);
+ alert("Please restart device for changes apply.");
+}
+
+function restart(submit) {
+ server = "/restart";
+ sendRequest(submit, server);
+}
+
+function setFirmvareValue(id, value) {
+ document.getElementById(id).innerHTML = document.getElementById(value).value;
+}
+
+function setGpioValue(id, value) {
+ var select = document.getElementById(id);
+ select.value = document.getElementById(value).value;
+}
diff --git a/data/index.htm b/data/index.htm
new file mode 100644
index 0000000..14970d6
--- /dev/null
+++ b/data/index.htm
@@ -0,0 +1,172 @@
+
+
+
+
+
+
+
+ ESP-NOW Led/Light Strip
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/data/style.css b/data/style.css
new file mode 100644
index 0000000..7b13ef7
--- /dev/null
+++ b/data/style.css
@@ -0,0 +1,94 @@
+body {
+ font-family: "Gill Sans", sans-serif;
+ background: rgb(255, 255, 255);
+}
+
+.box {
+ width: 400px;
+ padding: 20px 20px;
+ margin: 20px auto;
+ background: #e0f5fb;
+ box-shadow: 4px 4px 30px rgba(0, 0, 0, 0.2);
+ border-radius: 10px;
+}
+
+h1 {
+ color: rgb(65, 125, 238);
+ text-align: center;
+}
+
+.text {
+ font-weight: 600;
+ flex-shrink: 0;
+ margin-right: 10px;
+}
+
+.text-select {
+ width: 35%;
+ font-weight: 600;
+ flex-shrink: 0;
+ margin-right: 10px;
+}
+
+.wrapper {
+ display: flex;
+ justify-content: space-between;
+ align-items: baseline;
+}
+
+input {
+ width: 48%;
+ min-height: 30px;
+ border-radius: 5px;
+ border: none;
+ margin-bottom: 10px;
+ padding: 0 10px;
+ color: rgb(0, 0, 0);
+ background: #a3e0f1;
+ transition: .5s;
+}
+
+select {
+ width: 110px;
+ min-height: 30px;
+ border-radius: 5px;
+ border: none;
+ margin-bottom: 10px;
+ padding: 0 10px;
+ color: rgb(0, 0, 0);
+ background: #a3e0f1;
+ transition: .5s;
+}
+
+input:hover {
+ background: white;
+ cursor: pointer;
+}
+
+select:hover {
+ background: white;
+ cursor: pointer;
+}
+
+
+.btn {
+ width: 48%;
+ background: rgb(65, 125, 238);
+ color: white;
+ transition: .5s;
+}
+
+.btn:hover {
+ background: rgb(65, 125, 238);
+ opacity: 0.5;
+ transform: translatey(-3px);
+}
+
+#deviceName,
+#espnowNetName {
+ width: 100%;
+}
+
+.wrapper.wrapper--end {
+ align-items: baseline;
+}
\ No newline at end of file
diff --git a/platformio.ini b/platformio.ini
new file mode 100644
index 0000000..628f7eb
--- /dev/null
+++ b/platformio.ini
@@ -0,0 +1,43 @@
+[env:esp8266]
+platform = espressif8266
+board = esp12e
+framework = arduino
+lib_deps =
+ https://github.com/aZholtikov/ZHNetwork
+ https://github.com/aZholtikov/ZHConfig
+ bblanchon/ArduinoJson@^6.19.4
+ me-no-dev/ESP Async WebServer@^1.2.3
+
+[env:esp8266-ota]
+platform = espressif8266
+board = esp12e
+framework = arduino
+upload_port = 192.168.4.1
+upload_protocol = espota
+lib_deps =
+ https://github.com/aZholtikov/ZHNetwork
+ https://github.com/aZholtikov/ZHConfig
+ bblanchon/ArduinoJson@^6.19.4
+ me-no-dev/ESP Async WebServer@^1.2.3
+
+[env:esp8285]
+platform = espressif8266
+board = esp8285
+framework = arduino
+lib_deps =
+ https://github.com/aZholtikov/ZHNetwork
+ https://github.com/aZholtikov/ZHConfig
+ bblanchon/ArduinoJson@^6.19.4
+ me-no-dev/ESP Async WebServer@^1.2.3
+
+[env:esp8285-ota]
+platform = espressif8266
+board = esp8285
+framework = arduino
+upload_port = 192.168.4.1
+upload_protocol = espota
+lib_deps =
+ https://github.com/aZholtikov/ZHNetwork
+ https://github.com/aZholtikov/ZHConfig
+ bblanchon/ArduinoJson@^6.19.4
+ me-no-dev/ESP Async WebServer@^1.2.3
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644
index 0000000..f2913d9
--- /dev/null
+++ b/src/main.cpp
@@ -0,0 +1,489 @@
+#include "ArduinoJson.h"
+#include "ArduinoOTA.h"
+#include "ESPAsyncWebServer.h"
+#include "Ticker.h"
+#include "ZHNetwork.h"
+#include "ZHConfig.h"
+
+void onBroadcastReceiving(const char *data, const uint8_t *sender);
+void onUnicastReceiving(const char *data, const uint8_t *sender);
+void onConfirmReceiving(const uint8_t *target, const bool status);
+
+void loadConfig(void);
+void saveConfig(void);
+void setupWebServer(void);
+
+void sendAttributesMessage(void);
+void sendKeepAliveMessage(void);
+void sendConfigMessage(void);
+void sendStatusMessage(void);
+
+String getValue(String data, char separator, byte index);
+
+void changeLedState(void);
+
+const String firmware{"1.0"};
+
+String espnowNetName{"DEFAULT"};
+
+String deviceName{"ESP-NOW Light/Led Strip"};
+
+uint8_t ledType{ENLT_NONE};
+bool ledStatus{false};
+uint8_t coldWhitePin{0};
+uint8_t warmWhitePin{0};
+uint8_t redPin{0};
+uint8_t greenPin{0};
+uint8_t bluePin{0};
+
+uint8_t brightness{255};
+uint16_t temperature{255};
+uint8_t red{255};
+uint8_t green{255};
+uint8_t blue{255};
+
+bool wasMqttAvailable{false};
+
+uint8_t gatewayMAC[6]{0};
+
+ZHNetwork myNet;
+AsyncWebServer webServer(80);
+
+Ticker gatewayAvailabilityCheckTimer;
+bool isGatewayAvailable{false};
+void gatewayAvailabilityCheckTimerCallback(void);
+
+Ticker apModeHideTimer;
+void apModeHideTimerCallback(void);
+
+Ticker attributesMessageTimer;
+bool attributesMessageTimerSemaphore{true};
+void attributesMessageTimerCallback(void);
+Ticker attributesMessageResendTimer;
+bool attributesMessageResendTimerSemaphore{false};
+
+Ticker keepAliveMessageTimer;
+bool keepAliveMessageTimerSemaphore{true};
+void keepAliveMessageTimerCallback(void);
+Ticker keepAliveMessageResendTimer;
+bool keepAliveMessageResendTimerSemaphore{false};
+
+Ticker configMessageResendTimer;
+bool configMessageResendTimerSemaphore{false};
+
+Ticker statusMessageTimer;
+bool statusMessageTimerSemaphore{true};
+void statusMessageTimerCallback(void);
+Ticker statusMessageResendTimer;
+bool statusMessageResendTimerSemaphore{false};
+
+void setup()
+{
+ analogWriteRange(255);
+
+ SPIFFS.begin();
+
+ loadConfig();
+
+ if (coldWhitePin)
+ pinMode(coldWhitePin, OUTPUT);
+ if (warmWhitePin)
+ pinMode(warmWhitePin, OUTPUT);
+ if (redPin)
+ pinMode(redPin, OUTPUT);
+ if (greenPin)
+ pinMode(greenPin, OUTPUT);
+ if (bluePin)
+ pinMode(bluePin, OUTPUT);
+
+ changeLedState();
+
+ WiFi.setSleepMode(WIFI_NONE_SLEEP);
+ myNet.begin(espnowNetName.c_str());
+
+ myNet.setOnBroadcastReceivingCallback(onBroadcastReceiving);
+ myNet.setOnUnicastReceivingCallback(onUnicastReceiving);
+ myNet.setOnConfirmReceivingCallback(onConfirmReceiving);
+
+ WiFi.mode(WIFI_AP_STA);
+ WiFi.softAP(("ESP-NOW Light " + myNet.getNodeMac()).c_str(), "12345678", 1, 0);
+ apModeHideTimer.once(300, apModeHideTimerCallback);
+
+ setupWebServer();
+
+ ArduinoOTA.begin();
+
+ attributesMessageTimer.attach(60, attributesMessageTimerCallback);
+ keepAliveMessageTimer.attach(10, keepAliveMessageTimerCallback);
+ statusMessageTimer.attach(300, statusMessageTimerCallback);
+}
+
+void loop()
+{
+ if (attributesMessageTimerSemaphore)
+ sendAttributesMessage();
+ if (keepAliveMessageTimerSemaphore)
+ sendKeepAliveMessage();
+ if (statusMessageTimerSemaphore)
+ sendStatusMessage();
+ myNet.maintenance();
+ ArduinoOTA.handle();
+}
+
+void onBroadcastReceiving(const char *data, const byte *sender)
+{
+ esp_now_payload_data_t incomingData;
+ memcpy(&incomingData, data, sizeof(esp_now_payload_data_t));
+ if (incomingData.deviceType != ENDT_GATEWAY)
+ return;
+ if (myNet.macToString(gatewayMAC) != myNet.macToString(sender) && incomingData.payloadsType == ENPT_KEEP_ALIVE)
+ memcpy(gatewayMAC, sender, 6);
+ if (myNet.macToString(gatewayMAC) == myNet.macToString(sender) && incomingData.payloadsType == ENPT_KEEP_ALIVE)
+ {
+ isGatewayAvailable = true;
+ StaticJsonDocument json;
+ deserializeJson(json, incomingData.message);
+ bool temp = json["MQTT"] == "online" ? true : false;
+ if (wasMqttAvailable != temp)
+ {
+ wasMqttAvailable = temp;
+ if (temp)
+ sendConfigMessage();
+ }
+ gatewayAvailabilityCheckTimer.once(15, gatewayAvailabilityCheckTimerCallback);
+ }
+}
+
+void onUnicastReceiving(const char *data, const byte *sender)
+{
+ esp_now_payload_data_t incomingData;
+ memcpy(&incomingData, data, sizeof(esp_now_payload_data_t));
+ if (incomingData.deviceType != ENDT_GATEWAY || myNet.macToString(gatewayMAC) != myNet.macToString(sender))
+ return;
+ StaticJsonDocument json;
+ if (incomingData.payloadsType == ENPT_SET)
+ {
+ deserializeJson(json, incomingData.message);
+ if (json["set"])
+ ledStatus = json["set"] == "ON" ? true : false;
+ if (json["brightness"])
+ brightness = json["brightness"];
+ if (json["temperature"])
+ temperature = json["temperature"];
+ if (json["rgb"])
+ {
+ red = getValue(String(json["rgb"].as()).substring(0, sizeof(esp_now_payload_data_t::message)).c_str(), ',', 0).toInt();
+ green = getValue(String(json["rgb"].as()).substring(0, sizeof(esp_now_payload_data_t::message)).c_str(), ',', 1).toInt();
+ blue = getValue(String(json["rgb"].as()).substring(0, sizeof(esp_now_payload_data_t::message)).c_str(), ',', 2).toInt();
+ }
+ changeLedState();
+ sendStatusMessage();
+ }
+ if (incomingData.payloadsType == ENPT_UPDATE)
+ {
+ WiFi.softAP(("ESP-NOW Light " + myNet.getNodeMac()).c_str(), "12345678", 1, 0);
+ apModeHideTimer.once(300, apModeHideTimerCallback);
+ }
+ if (incomingData.payloadsType == ENPT_RESTART)
+ ESP.restart();
+}
+
+void onConfirmReceiving(const uint8_t *target, const bool status)
+{
+ if (status)
+ {
+ if (attributesMessageResendTimerSemaphore)
+ {
+ attributesMessageResendTimerSemaphore = false;
+ attributesMessageResendTimer.detach();
+ }
+ if (keepAliveMessageResendTimerSemaphore)
+ {
+ keepAliveMessageResendTimerSemaphore = false;
+ keepAliveMessageResendTimer.detach();
+ }
+ if (configMessageResendTimerSemaphore)
+ {
+ configMessageResendTimerSemaphore = false;
+ configMessageResendTimer.detach();
+ }
+ if (statusMessageResendTimerSemaphore)
+ {
+ statusMessageResendTimerSemaphore = false;
+ statusMessageResendTimer.detach();
+ }
+ }
+}
+
+void loadConfig()
+{
+ if (!SPIFFS.exists("/config.json"))
+ saveConfig();
+ File file = SPIFFS.open("/config.json", "r");
+ String jsonFile = file.readString();
+ StaticJsonDocument<512> json;
+ deserializeJson(json, jsonFile);
+ espnowNetName = json["espnowNetName"].as();
+ deviceName = json["deviceName"].as();
+ ledType = json["ledType"];
+ ledStatus = json["ledStatus"];
+ coldWhitePin = json["coldWhitePin"];
+ warmWhitePin = json["warmWhitePin"];
+ redPin = json["redPin"];
+ greenPin = json["greenPin"];
+ bluePin = json["bluePin"];
+ brightness = json["brightness"];
+ temperature = json["temperature"];
+ red = json["red"];
+ green = json["green"];
+ blue = json["blue"];
+ file.close();
+}
+
+void saveConfig()
+{
+ StaticJsonDocument<512> json;
+ json["firmware"] = firmware;
+ json["espnowNetName"] = espnowNetName;
+ json["deviceName"] = deviceName;
+ json["ledType"] = ledType;
+ json["ledStatus"] = ledStatus;
+ json["coldWhitePin"] = coldWhitePin;
+ json["warmWhitePin"] = warmWhitePin;
+ json["redPin"] = redPin;
+ json["greenPin"] = greenPin;
+ json["bluePin"] = bluePin;
+ json["brightness"] = brightness;
+ json["temperature"] = temperature;
+ json["red"] = red;
+ json["green"] = green;
+ json["blue"] = blue;
+ json["system"] = "empty";
+ File file = SPIFFS.open("/config.json", "w");
+ serializeJsonPretty(json, file);
+ file.close();
+}
+
+void setupWebServer()
+{
+ webServer.on("/", HTTP_GET, [](AsyncWebServerRequest *request)
+ { request->send(SPIFFS, "/index.htm"); });
+
+ webServer.on("/setting", HTTP_GET, [](AsyncWebServerRequest *request)
+ {
+ ledType = request->getParam("ledType")->value().toInt();
+ coldWhitePin = request->getParam("coldWhitePin")->value().toInt();
+ warmWhitePin = request->getParam("warmWhitePin")->value().toInt();
+ redPin = request->getParam("redPin")->value().toInt();
+ greenPin = request->getParam("greenPin")->value().toInt();
+ bluePin = request->getParam("bluePin")->value().toInt();
+ deviceName = request->getParam("deviceName")->value();
+ espnowNetName = request->getParam("espnowNetName")->value();
+ request->send(200);
+ saveConfig(); });
+
+ webServer.on("/restart", HTTP_GET, [](AsyncWebServerRequest *request)
+ {
+ request->send(200);
+ ESP.restart(); });
+
+ webServer.onNotFound([](AsyncWebServerRequest *request)
+ {
+ if (SPIFFS.exists(request->url()))
+ request->send(SPIFFS, request->url());
+ else
+ {
+ request->send(404, "text/plain", "File Not Found");
+ } });
+
+ webServer.begin();
+}
+
+void sendAttributesMessage()
+{
+ if (!isGatewayAvailable)
+ return;
+ attributesMessageTimerSemaphore = false;
+ uint32_t secs = millis() / 1000;
+ uint32_t mins = secs / 60;
+ uint32_t hours = mins / 60;
+ uint32_t days = hours / 24;
+ esp_now_payload_data_t outgoingData{ENDT_LED, ENPT_ATTRIBUTES};
+ StaticJsonDocument json;
+ json["Type"] = "ESP-NOW Led/Light Strip";
+ json["MCU"] = "ESP8266";
+ json["MAC"] = myNet.getNodeMac();
+ json["Firmware"] = firmware;
+ json["Library"] = myNet.getFirmwareVersion();
+ json["Uptime"] = "Days:" + String(days) + " Hours:" + String(hours - (days * 24)) + " Mins:" + String(mins - (hours * 60));
+ char buffer[sizeof(esp_now_payload_data_t::message)]{0};
+ serializeJsonPretty(json, buffer);
+ memcpy(outgoingData.message, buffer, sizeof(esp_now_payload_data_t::message));
+ char temp[sizeof(esp_now_payload_data_t)]{0};
+ memcpy(&temp, &outgoingData, sizeof(esp_now_payload_data_t));
+ myNet.sendUnicastMessage(temp, gatewayMAC, true);
+
+ attributesMessageResendTimerSemaphore = true;
+ attributesMessageResendTimer.once(1, sendAttributesMessage);
+}
+
+void sendKeepAliveMessage()
+{
+ if (!isGatewayAvailable)
+ return;
+ keepAliveMessageTimerSemaphore = false;
+ esp_now_payload_data_t outgoingData{ENDT_LED, ENPT_KEEP_ALIVE};
+ char temp[sizeof(esp_now_payload_data_t)]{0};
+ memcpy(&temp, &outgoingData, sizeof(esp_now_payload_data_t));
+ myNet.sendUnicastMessage(temp, gatewayMAC, true);
+
+ keepAliveMessageResendTimerSemaphore = true;
+ keepAliveMessageResendTimer.once(1, sendKeepAliveMessage);
+}
+
+void sendConfigMessage()
+{
+ if (!isGatewayAvailable)
+ return;
+ esp_now_payload_data_t outgoingData{ENDT_LED, ENPT_CONFIG};
+ StaticJsonDocument json;
+ json["name"] = deviceName;
+ json["unit"] = 1;
+ json["type"] = getValueName(HACT_LIGHT);
+ json["class"] = ledType;
+ char buffer[sizeof(esp_now_payload_data_t::message)]{0};
+ serializeJsonPretty(json, buffer);
+ memcpy(outgoingData.message, buffer, sizeof(esp_now_payload_data_t::message));
+ char temp[sizeof(esp_now_payload_data_t)]{0};
+ memcpy(&temp, &outgoingData, sizeof(esp_now_payload_data_t));
+ myNet.sendUnicastMessage(temp, gatewayMAC, true);
+
+ configMessageResendTimerSemaphore = true;
+ configMessageResendTimer.once(5, sendConfigMessage);
+}
+
+void sendStatusMessage()
+{
+ if (!isGatewayAvailable)
+ return;
+ statusMessageTimerSemaphore = false;
+ esp_now_payload_data_t outgoingData{ENDT_LED, ENPT_STATE};
+ StaticJsonDocument json;
+ json["state"] = ledStatus ? "ON" : "OFF";
+ json["brightness"] = brightness;
+ json["temperature"] = temperature;
+ json["rgb"] = String(red) + "," + String(green) + "," + String(blue);
+ char buffer[sizeof(esp_now_payload_data_t::message)]{0};
+ serializeJsonPretty(json, buffer);
+ memcpy(&outgoingData.message, &buffer, sizeof(esp_now_payload_data_t::message));
+ char temp[sizeof(esp_now_payload_data_t)]{0};
+ memcpy(&temp, &outgoingData, sizeof(esp_now_payload_data_t));
+ myNet.sendUnicastMessage(temp, gatewayMAC, true);
+
+ statusMessageResendTimerSemaphore = true;
+ statusMessageResendTimer.once(1, sendStatusMessage);
+}
+
+String getValue(String data, char separator, byte index)
+{
+ byte found{0};
+ int strIndex[]{0, -1};
+ int maxIndex = data.length() - 1;
+ for (byte i{0}; i <= maxIndex && found <= index; i++)
+ if (data.charAt(i) == separator || i == maxIndex)
+ {
+ found++;
+ strIndex[0] = strIndex[1] + 1;
+ strIndex[1] = (i == maxIndex) ? i + 1 : i;
+ }
+ return found > index ? data.substring(strIndex[0], strIndex[1]) : "";
+}
+
+void changeLedState(void)
+{
+ if (ledStatus)
+ {
+ if (red == 255 && green == 255 && blue == 255)
+ {
+ if (ledType == ENLT_W || ledType == ENLT_RGBW)
+ analogWrite(coldWhitePin, brightness);
+ if (ledType == ENLT_WW || ledType == ENLT_RGBWW)
+ {
+ analogWrite(coldWhitePin, map(brightness, 0, 255, 0, map(temperature, 500, 153, 0, 255)));
+ analogWrite(warmWhitePin, map(brightness, 0, 255, 0, map(temperature, 153, 500, 0, 255)));
+ }
+ if (ledType == ENLT_RGB)
+ {
+ analogWrite(redPin, map(red, 0, 255, 0, brightness));
+ analogWrite(greenPin, map(green, 0, 255, 0, brightness));
+ analogWrite(bluePin, map(blue, 0, 255, 0, brightness));
+ }
+ if (ledType == ENLT_RGBW || ledType == ENLT_RGBWW)
+ {
+ digitalWrite(redPin, LOW);
+ digitalWrite(greenPin, LOW);
+ digitalWrite(bluePin, LOW);
+ }
+ }
+ else
+ {
+ if (ledType == ENLT_W)
+ analogWrite(coldWhitePin, brightness);
+ if (ledType == ENLT_WW)
+ {
+ analogWrite(coldWhitePin, map(brightness, 0, 255, 0, map(temperature, 500, 153, 0, 255)));
+ analogWrite(warmWhitePin, map(brightness, 0, 255, 0, map(temperature, 153, 500, 0, 255)));
+ }
+ if (ledType == ENLT_RGBW || ledType == ENLT_RGBWW)
+ digitalWrite(coldWhitePin, LOW);
+ if (ledType == ENLT_RGBWW)
+ digitalWrite(warmWhitePin, LOW);
+ if (ledType == ENLT_RGB || ledType == ENLT_RGBW || ledType == ENLT_RGBWW)
+ {
+ analogWrite(redPin, map(red, 0, 255, 0, brightness));
+ analogWrite(greenPin, map(green, 0, 255, 0, brightness));
+ analogWrite(bluePin, map(blue, 0, 255, 0, brightness));
+ }
+ }
+ }
+ else
+ {
+ if (ledType == ENLT_W || ledType == ENLT_WW || ledType == ENLT_RGBW || ledType == ENLT_RGBWW)
+ digitalWrite(coldWhitePin, LOW);
+ if (ledType == ENLT_WW || ledType == ENLT_RGBWW)
+ digitalWrite(warmWhitePin, LOW);
+ if (ledType == ENLT_RGB || ledType == ENLT_RGBW || ledType == ENLT_RGBWW)
+ {
+ digitalWrite(redPin, LOW);
+ digitalWrite(greenPin, LOW);
+ digitalWrite(bluePin, LOW);
+ }
+ }
+ saveConfig();
+}
+
+void gatewayAvailabilityCheckTimerCallback()
+{
+ isGatewayAvailable = false;
+ memset(gatewayMAC, 0, 6);
+}
+
+void apModeHideTimerCallback()
+{
+ WiFi.softAP(("ESP-NOW Light " + myNet.getNodeMac()).c_str(), "12345678", 1, 1);
+}
+
+void attributesMessageTimerCallback()
+{
+ attributesMessageTimerSemaphore = true;
+}
+
+void keepAliveMessageTimerCallback()
+{
+ keepAliveMessageTimerSemaphore = true;
+}
+
+void statusMessageTimerCallback()
+{
+ statusMessageTimerSemaphore = true;
+}
\ No newline at end of file