Compare commits

..

No commits in common. "main" and "v1.0" have entirely different histories.
main ... v1.0

16 changed files with 215 additions and 256 deletions

View File

@ -1,10 +1,10 @@
# ESP-NOW light/led strip controller for ESP8266 # 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. ESP-NOW based light/led strip controller for ESP8266. Alternate firmware for Tuya/SmartLife WiFi light/led strip controllers.
## Features ## 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. 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. 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. 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. 4. Automatically adds light/led strip configuration to Home Assistan via MQTT discovery as a light.
@ -19,14 +19,11 @@ ESP-NOW based light/led strip controller for ESP8266. Alternate firmware for Tuy
## Tested on ## Tested on
See [here](https://github.com/aZholtikov/ESP-NOW-Light-Led-Strip/tree/main/hardware). Coming soon.
## Attention ## Attention
1. A gateway is required. For details see [ESP-NOW Gateway](https://github.com/aZholtikov/ESP-NOW-Gateway). 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. 2. ESP-NOW network name must be set same of all another ESP-NOW devices in network.
3. If encryption is used, the key 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. 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).
5. 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).
Any feedback via [e-mail](mailto:github@zh.com.ru) would be appreciated. Or... [Buy me a coffee](https://paypal.me/aZholtikov).

View File

@ -10,7 +10,7 @@ function createXmlHttpObject() {
function load() { function load() {
if (xmlHttp.readyState == 0 || xmlHttp.readyState == 4) { if (xmlHttp.readyState == 0 || xmlHttp.readyState == 4) {
xmlHttp.open('GET', '/config', true); xmlHttp.open('PUT', '/config.json', true);
xmlHttp.send(null); xmlHttp.send(null);
xmlHttp.onload = function () { xmlHttp.onload = function () {
jsonResponse = JSON.parse(xmlHttp.responseText); jsonResponse = JSON.parse(xmlHttp.responseText);

View File

@ -5,12 +5,12 @@
<meta name="viewport" content="width=device-width, initial-scale=0.9"> <meta name="viewport" content="width=device-width, initial-scale=0.9">
<link rel="stylesheet" href="style.css"> <link rel="stylesheet" href="style.css">
<script type="text/javascript" src="function.js"></script> <script type="text/javascript" src="function.js"></script>
<title>ESP-NOW Light</title> <title>ESP-NOW Led/Light Strip</title>
</head> </head>
<body onload="load();"> <body onload="load();">
<form class="box"> <form class="box">
<h1>ESP-NOW Light</h1> <h1>ESP-NOW Led/Light Strip </h1>
<div class="wrapper"> <div class="wrapper">
<p class="text">Firmware:</p> <p class="text">Firmware:</p>
<p class="text" id="version"></p> <p class="text" id="version"></p>

View File

@ -1,7 +1,3 @@
p{
margin: 0 0;
}
body { body {
font-family: "Gill Sans", sans-serif; font-family: "Gill Sans", sans-serif;
background: rgb(255, 255, 255); background: rgb(255, 255, 255);
@ -25,8 +21,6 @@ h1 {
font-weight: 600; font-weight: 600;
flex-shrink: 0; flex-shrink: 0;
margin-right: 10px; margin-right: 10px;
margin-left: 10px;
margin: 10px 0;
} }
.text-select { .text-select {
@ -48,7 +42,6 @@ input {
border-radius: 5px; border-radius: 5px;
border: none; border: none;
margin-bottom: 10px; margin-bottom: 10px;
margin-left: 10px;
padding: 0 10px; padding: 0 10px;
color: rgb(0, 0, 0); color: rgb(0, 0, 0);
background: #a3e0f1; background: #a3e0f1;
@ -83,8 +76,6 @@ select:hover {
background: rgb(65, 125, 238); background: rgb(65, 125, 238);
color: white; color: white;
transition: .5s; transition: .5s;
margin-left: 0;
margin-top: 8px;
} }
.btn:hover { .btn:hover {
@ -98,10 +89,6 @@ select:hover {
width: 100%; width: 100%;
} }
#espnowNetName {
margin-bottom: 15px;
}
.wrapper.wrapper--end { .wrapper.wrapper--end {
align-items: baseline; align-items: baseline;
} }

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 MiB

View File

@ -1,13 +0,0 @@
# Tested on
1. AP-FUTURE RGB Led controller. Built on Tuya WiFi module WB3S (BK7231N chip). Replacement required. Performed replacement with ESP-12E. [Photo](https://github.com/aZholtikov/ESP-NOW-Light-Led-Strip/tree/main/hardware/AP-FUTURE_RGB). A connect EN to VCC is required. A pull-up to GND of GPIO15 is required (i used a 0805 10K SMD resistor on top of the module pins).
```text
Device type RGB
Red GPIO GPIO04
Green GPIO GPIO12
Blue GPIO GPIO14
```
2. FLYIDEA RGBW Light E27 15W (Coming soon)
3. FLYIDEA RGBWW Light E14 7W (Coming soon)

View File

@ -1,27 +1,43 @@
[env:ESP-12E] [env:esp8266]
platform = espressif8266 platform = espressif8266
board = esp12e board = esp12e
framework = arduino framework = arduino
build_flags = -D PIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK305
board_build.filesystem = littlefs
board_build.ldscript = eagle.flash.4m1m.ld
lib_deps = lib_deps =
https://github.com/aZholtikov/ZHNetwork https://github.com/aZholtikov/ZHNetwork
https://github.com/aZholtikov/ZHConfig https://github.com/aZholtikov/ZHConfig
https://github.com/aZholtikov/Async-Web-Server bblanchon/ArduinoJson@^6.19.4
https://github.com/bblanchon/ArduinoJson me-no-dev/ESP Async WebServer@^1.2.3
[env:ESP-12E-OTA] [env:esp8266-ota]
platform = espressif8266 platform = espressif8266
board = esp12e board = esp12e
framework = arduino framework = arduino
build_flags = -D PIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK305
board_build.filesystem = littlefs
board_build.ldscript = eagle.flash.4m1m.ld
upload_port = 192.168.4.1 upload_port = 192.168.4.1
upload_protocol = espota upload_protocol = espota
lib_deps = lib_deps =
https://github.com/aZholtikov/ZHNetwork https://github.com/aZholtikov/ZHNetwork
https://github.com/aZholtikov/ZHConfig https://github.com/aZholtikov/ZHConfig
https://github.com/aZholtikov/Async-Web-Server bblanchon/ArduinoJson@^6.19.4
https://github.com/bblanchon/ArduinoJson 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

View File

@ -1,20 +1,16 @@
#include "ArduinoJson.h" #include "ArduinoJson.h"
#include "ArduinoOTA.h" #include "ArduinoOTA.h"
#include "ESPAsyncWebServer.h" // https://github.com/aZholtikov/Async-Web-Server #include "ESPAsyncWebServer.h"
#include "LittleFS.h"
#include "EEPROM.h"
#include "Ticker.h" #include "Ticker.h"
#include "ZHNetwork.h" #include "ZHNetwork.h"
#include "ZHConfig.h" #include "ZHConfig.h"
void onBroadcastReceiving(const char *data, const uint8_t *sender); void onBroadcastReceiving(const char *data, const uint8_t *sender);
void onUnicastReceiving(const char *data, const uint8_t *sender); void onUnicastReceiving(const char *data, const uint8_t *sender);
void onConfirmReceiving(const uint8_t *target, const uint16_t id, const bool status); void onConfirmReceiving(const uint8_t *target, const bool status);
void loadConfig(void); void loadConfig(void);
void saveConfig(void); void saveConfig(void);
void loadStatus(void);
void saveStatus(void);
void setupWebServer(void); void setupWebServer(void);
void sendAttributesMessage(void); void sendAttributesMessage(void);
@ -22,33 +18,24 @@ void sendKeepAliveMessage(void);
void sendConfigMessage(void); void sendConfigMessage(void);
void sendStatusMessage(void); void sendStatusMessage(void);
String getValue(String data, char separator, uint8_t index); String getValue(String data, char separator, byte index);
void changeLedState(void); void changeLedState(void);
typedef struct const String firmware{"1.0"};
{
uint16_t id{0};
char message[200]{0};
} espnow_message_t;
struct deviceConfig String espnowNetName{"DEFAULT"};
{
String espnowNetName{"DEFAULT"};
String deviceName = "ESP-NOW light " + String(ESP.getChipId(), HEX);
uint8_t ledType{ENLT_NONE};
uint8_t coldWhitePin{0};
uint8_t warmWhitePin{0};
uint8_t redPin{0};
uint8_t greenPin{0};
uint8_t bluePin{0};
} config;
std::vector<espnow_message_t> espnowMessage; String deviceName{"ESP-NOW Light/Led Strip"};
const String firmware{"1.21"};
uint8_t ledType{ENLT_NONE};
bool ledStatus{false}; 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}; uint8_t brightness{255};
uint16_t temperature{255}; uint16_t temperature{255};
uint8_t red{255}; uint8_t red{255};
@ -72,47 +59,54 @@ void apModeHideTimerCallback(void);
Ticker attributesMessageTimer; Ticker attributesMessageTimer;
bool attributesMessageTimerSemaphore{true}; bool attributesMessageTimerSemaphore{true};
void attributesMessageTimerCallback(void); void attributesMessageTimerCallback(void);
Ticker attributesMessageResendTimer;
bool attributesMessageResendTimerSemaphore{false};
Ticker keepAliveMessageTimer; Ticker keepAliveMessageTimer;
bool keepAliveMessageTimerSemaphore{true}; bool keepAliveMessageTimerSemaphore{true};
void keepAliveMessageTimerCallback(void); void keepAliveMessageTimerCallback(void);
Ticker keepAliveMessageResendTimer;
bool keepAliveMessageResendTimerSemaphore{false};
Ticker configMessageResendTimer;
bool configMessageResendTimerSemaphore{false};
Ticker statusMessageTimer; Ticker statusMessageTimer;
bool statusMessageTimerSemaphore{true}; bool statusMessageTimerSemaphore{true};
void statusMessageTimerCallback(void); void statusMessageTimerCallback(void);
Ticker statusMessageResendTimer;
bool statusMessageResendTimerSemaphore{false};
void setup() void setup()
{ {
analogWriteRange(255); analogWriteRange(255);
LittleFS.begin(); SPIFFS.begin();
loadConfig(); loadConfig();
loadStatus();
if (config.coldWhitePin) if (coldWhitePin)
pinMode(config.coldWhitePin, OUTPUT); pinMode(coldWhitePin, OUTPUT);
if (config.warmWhitePin) if (warmWhitePin)
pinMode(config.warmWhitePin, OUTPUT); pinMode(warmWhitePin, OUTPUT);
if (config.redPin) if (redPin)
pinMode(config.redPin, OUTPUT); pinMode(redPin, OUTPUT);
if (config.greenPin) if (greenPin)
pinMode(config.greenPin, OUTPUT); pinMode(greenPin, OUTPUT);
if (config.bluePin) if (bluePin)
pinMode(config.bluePin, OUTPUT); pinMode(bluePin, OUTPUT);
changeLedState(); changeLedState();
WiFi.setSleepMode(WIFI_NONE_SLEEP); WiFi.setSleepMode(WIFI_NONE_SLEEP);
myNet.begin(config.espnowNetName.c_str()); myNet.begin(espnowNetName.c_str());
// myNet.setCryptKey("VERY_LONG_CRYPT_KEY"); // If encryption is used, the key must be set same of all another ESP-NOW devices in network.
myNet.setOnBroadcastReceivingCallback(onBroadcastReceiving); myNet.setOnBroadcastReceivingCallback(onBroadcastReceiving);
myNet.setOnUnicastReceivingCallback(onUnicastReceiving); myNet.setOnUnicastReceivingCallback(onUnicastReceiving);
myNet.setOnConfirmReceivingCallback(onConfirmReceiving); myNet.setOnConfirmReceivingCallback(onConfirmReceiving);
WiFi.mode(WIFI_AP_STA); WiFi.mode(WIFI_AP_STA);
WiFi.softAP(("ESP-NOW light " + String(ESP.getChipId(), HEX)).c_str(), "12345678", 1, 0); WiFi.softAP(("ESP-NOW Light " + myNet.getNodeMac()).c_str(), "12345678", 1, 0);
apModeHideTimer.once(300, apModeHideTimerCallback); apModeHideTimer.once(300, apModeHideTimerCallback);
setupWebServer(); setupWebServer();
@ -136,41 +130,37 @@ void loop()
ArduinoOTA.handle(); ArduinoOTA.handle();
} }
void onBroadcastReceiving(const char *data, const uint8_t *sender) void onBroadcastReceiving(const char *data, const byte *sender)
{ {
esp_now_payload_data_t incomingData; esp_now_payload_data_t incomingData;
memcpy(&incomingData, data, sizeof(esp_now_payload_data_t)); memcpy(&incomingData, data, sizeof(esp_now_payload_data_t));
if (incomingData.deviceType != ENDT_GATEWAY) if (incomingData.deviceType != ENDT_GATEWAY)
return; return;
if (myNet.macToString(gatewayMAC) != myNet.macToString(sender) && incomingData.payloadsType == ENPT_KEEP_ALIVE) if (myNet.macToString(gatewayMAC) != myNet.macToString(sender) && incomingData.payloadsType == ENPT_KEEP_ALIVE)
memcpy(&gatewayMAC, sender, 6); memcpy(gatewayMAC, sender, 6);
if (myNet.macToString(gatewayMAC) == myNet.macToString(sender) && incomingData.payloadsType == ENPT_KEEP_ALIVE) if (myNet.macToString(gatewayMAC) == myNet.macToString(sender) && incomingData.payloadsType == ENPT_KEEP_ALIVE)
{ {
isGatewayAvailable = true; isGatewayAvailable = true;
DynamicJsonDocument json(sizeof(esp_now_payload_data_t::message)); StaticJsonDocument<sizeof(esp_now_payload_data_t::message)> json;
deserializeJson(json, incomingData.message); deserializeJson(json, incomingData.message);
bool temp = json["MQTT"] == "online" ? true : false; bool temp = json["MQTT"] == "online" ? true : false;
if (wasMqttAvailable != temp) if (wasMqttAvailable != temp)
{ {
wasMqttAvailable = temp; wasMqttAvailable = temp;
if (temp) if (temp)
{
sendConfigMessage(); sendConfigMessage();
sendAttributesMessage();
sendStatusMessage();
}
} }
gatewayAvailabilityCheckTimer.once(15, gatewayAvailabilityCheckTimerCallback); gatewayAvailabilityCheckTimer.once(15, gatewayAvailabilityCheckTimerCallback);
} }
} }
void onUnicastReceiving(const char *data, const uint8_t *sender) void onUnicastReceiving(const char *data, const byte *sender)
{ {
esp_now_payload_data_t incomingData; esp_now_payload_data_t incomingData;
memcpy(&incomingData, data, sizeof(esp_now_payload_data_t)); memcpy(&incomingData, data, sizeof(esp_now_payload_data_t));
if (incomingData.deviceType != ENDT_GATEWAY || myNet.macToString(gatewayMAC) != myNet.macToString(sender)) if (incomingData.deviceType != ENDT_GATEWAY || myNet.macToString(gatewayMAC) != myNet.macToString(sender))
return; return;
DynamicJsonDocument json(sizeof(esp_now_payload_data_t::message)); StaticJsonDocument<sizeof(esp_now_payload_data_t::message)> json;
if (incomingData.payloadsType == ENPT_SET) if (incomingData.payloadsType == ENPT_SET)
{ {
deserializeJson(json, incomingData.message); deserializeJson(json, incomingData.message);
@ -191,146 +181,120 @@ void onUnicastReceiving(const char *data, const uint8_t *sender)
} }
if (incomingData.payloadsType == ENPT_UPDATE) if (incomingData.payloadsType == ENPT_UPDATE)
{ {
WiFi.softAP(("ESP-NOW light " + String(ESP.getChipId(), HEX)).c_str(), "12345678", 1, 0); WiFi.softAP(("ESP-NOW Light " + myNet.getNodeMac()).c_str(), "12345678", 1, 0);
webServer.begin();
apModeHideTimer.once(300, apModeHideTimerCallback); apModeHideTimer.once(300, apModeHideTimerCallback);
} }
if (incomingData.payloadsType == ENPT_RESTART) if (incomingData.payloadsType == ENPT_RESTART)
ESP.restart(); ESP.restart();
} }
void onConfirmReceiving(const uint8_t *target, const uint16_t id, const bool status) void onConfirmReceiving(const uint8_t *target, const bool status)
{ {
for (uint16_t i{0}; i < espnowMessage.size(); ++i) if (status)
{ {
espnow_message_t message = espnowMessage[i]; if (attributesMessageResendTimerSemaphore)
if (message.id == id)
{ {
if (status) attributesMessageResendTimerSemaphore = false;
espnowMessage.erase(espnowMessage.begin() + i); attributesMessageResendTimer.detach();
else }
{ if (keepAliveMessageResendTimerSemaphore)
message.id = myNet.sendUnicastMessage(message.message, gatewayMAC, true); {
espnowMessage.at(i) = message; keepAliveMessageResendTimerSemaphore = false;
} keepAliveMessageResendTimer.detach();
}
if (configMessageResendTimerSemaphore)
{
configMessageResendTimerSemaphore = false;
configMessageResendTimer.detach();
}
if (statusMessageResendTimerSemaphore)
{
statusMessageResendTimerSemaphore = false;
statusMessageResendTimer.detach();
} }
} }
} }
void loadConfig() void loadConfig()
{ {
ETS_GPIO_INTR_DISABLE(); if (!SPIFFS.exists("/config.json"))
EEPROM.begin(4096);
if (EEPROM.read(4095) == 254)
{
EEPROM.get(0, config);
EEPROM.end();
}
else
{
EEPROM.end();
saveConfig(); saveConfig();
} File file = SPIFFS.open("/config.json", "r");
delay(50);
ETS_GPIO_INTR_ENABLE();
}
void saveConfig()
{
ETS_GPIO_INTR_DISABLE();
EEPROM.begin(4096);
EEPROM.write(4095, 254);
EEPROM.put(0, config);
EEPROM.end();
delay(50);
ETS_GPIO_INTR_ENABLE();
}
void loadStatus()
{
ETS_GPIO_INTR_DISABLE();
if (!LittleFS.exists("/status.json"))
saveStatus();
File file = LittleFS.open("/status.json", "r");
String jsonFile = file.readString(); String jsonFile = file.readString();
DynamicJsonDocument json(192); // To calculate the buffer size uses https://arduinojson.org/v6/assistant. StaticJsonDocument<512> json;
deserializeJson(json, jsonFile); deserializeJson(json, jsonFile);
ledStatus = json["status"]; espnowNetName = json["espnowNetName"].as<String>();
deviceName = json["deviceName"].as<String>();
ledType = json["ledType"];
ledStatus = json["ledStatus"];
coldWhitePin = json["coldWhitePin"];
warmWhitePin = json["warmWhitePin"];
redPin = json["redPin"];
greenPin = json["greenPin"];
bluePin = json["bluePin"];
brightness = json["brightness"]; brightness = json["brightness"];
temperature = json["temperature"]; temperature = json["temperature"];
red = json["red"]; red = json["red"];
green = json["green"]; green = json["green"];
blue = json["blue"]; blue = json["blue"];
file.close(); file.close();
delay(50);
ETS_GPIO_INTR_ENABLE();
} }
void saveStatus() void saveConfig()
{ {
ETS_GPIO_INTR_DISABLE(); StaticJsonDocument<512> json;
DynamicJsonDocument json(128); // To calculate the buffer size uses https://arduinojson.org/v6/assistant. json["firmware"] = firmware;
json["status"] = ledStatus; 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["brightness"] = brightness;
json["temperature"] = temperature; json["temperature"] = temperature;
json["red"] = red; json["red"] = red;
json["green"] = green; json["green"] = green;
json["blue"] = blue; json["blue"] = blue;
json["system"] = "empty"; json["system"] = "empty";
File file = LittleFS.open("/status.json", "w"); File file = SPIFFS.open("/config.json", "w");
serializeJsonPretty(json, file); serializeJsonPretty(json, file);
file.close(); file.close();
delay(50);
ETS_GPIO_INTR_ENABLE();
} }
void setupWebServer() void setupWebServer()
{ {
webServer.on("/", HTTP_GET, [](AsyncWebServerRequest *request) webServer.on("/", HTTP_GET, [](AsyncWebServerRequest *request)
{ request->send(LittleFS, "/index.htm"); }); { request->send(SPIFFS, "/index.htm"); });
webServer.on("/function.js", HTTP_GET, [](AsyncWebServerRequest *request)
{ request->send(LittleFS, "/function.js"); });
webServer.on("/style.css", HTTP_GET, [](AsyncWebServerRequest *request)
{ request->send(LittleFS, "/style.css"); });
webServer.on("/setting", HTTP_GET, [](AsyncWebServerRequest *request) webServer.on("/setting", HTTP_GET, [](AsyncWebServerRequest *request)
{ {
config.ledType = request->getParam("ledType")->value().toInt(); ledType = request->getParam("ledType")->value().toInt();
config.coldWhitePin = request->getParam("coldWhitePin")->value().toInt(); coldWhitePin = request->getParam("coldWhitePin")->value().toInt();
config.warmWhitePin = request->getParam("warmWhitePin")->value().toInt(); warmWhitePin = request->getParam("warmWhitePin")->value().toInt();
config.redPin = request->getParam("redPin")->value().toInt(); redPin = request->getParam("redPin")->value().toInt();
config.greenPin = request->getParam("greenPin")->value().toInt(); greenPin = request->getParam("greenPin")->value().toInt();
config.bluePin = request->getParam("bluePin")->value().toInt(); bluePin = request->getParam("bluePin")->value().toInt();
config.deviceName = request->getParam("deviceName")->value(); deviceName = request->getParam("deviceName")->value();
config.espnowNetName = request->getParam("espnowNetName")->value(); espnowNetName = request->getParam("espnowNetName")->value();
request->send(200); request->send(200);
saveConfig(); }); saveConfig(); });
webServer.on("/config", HTTP_GET, [](AsyncWebServerRequest *request)
{
String configJson;
DynamicJsonDocument json(384); // To calculate the buffer size uses https://arduinojson.org/v6/assistant.
json["firmware"] = firmware;
json["espnowNetName"] = config.espnowNetName;
json["deviceName"] = config.deviceName;
json["ledType"] = config.ledType;
json["coldWhitePin"] = config.coldWhitePin;
json["warmWhitePin"] = config.warmWhitePin;
json["redPin"] = config.redPin;
json["greenPin"] = config.greenPin;
json["bluePin"] = config.bluePin;
serializeJsonPretty(json, configJson);
request->send(200, "application/json", configJson); });
webServer.on("/restart", HTTP_GET, [](AsyncWebServerRequest *request) webServer.on("/restart", HTTP_GET, [](AsyncWebServerRequest *request)
{ {
request->send(200); request->send(200);
ESP.restart(); }); ESP.restart(); });
webServer.onNotFound([](AsyncWebServerRequest *request) webServer.onNotFound([](AsyncWebServerRequest *request)
{ request->send(404, "text/plain", "File Not Found"); }); {
if (SPIFFS.exists(request->url()))
request->send(SPIFFS, request->url());
else
{
request->send(404, "text/plain", "File Not Found");
} });
webServer.begin(); webServer.begin();
} }
@ -345,19 +309,22 @@ void sendAttributesMessage()
uint32_t hours = mins / 60; uint32_t hours = mins / 60;
uint32_t days = hours / 24; uint32_t days = hours / 24;
esp_now_payload_data_t outgoingData{ENDT_LED, ENPT_ATTRIBUTES}; esp_now_payload_data_t outgoingData{ENDT_LED, ENPT_ATTRIBUTES};
espnow_message_t message; StaticJsonDocument<sizeof(esp_now_payload_data_t::message)> json;
DynamicJsonDocument json(sizeof(esp_now_payload_data_t::message)); json["Type"] = "ESP-NOW Led/Light Strip";
json["Type"] = "ESP-NOW light";
json["MCU"] = "ESP8266"; json["MCU"] = "ESP8266";
json["MAC"] = myNet.getNodeMac(); json["MAC"] = myNet.getNodeMac();
json["Firmware"] = firmware; json["Firmware"] = firmware;
json["Library"] = myNet.getFirmwareVersion(); json["Library"] = myNet.getFirmwareVersion();
json["Uptime"] = "Days:" + String(days) + " Hours:" + String(hours - (days * 24)) + " Mins:" + String(mins - (hours * 60)); json["Uptime"] = "Days:" + String(days) + " Hours:" + String(hours - (days * 24)) + " Mins:" + String(mins - (hours * 60));
serializeJsonPretty(json, outgoingData.message); char buffer[sizeof(esp_now_payload_data_t::message)]{0};
memcpy(&message.message, &outgoingData, sizeof(esp_now_payload_data_t)); serializeJsonPretty(json, buffer);
message.id = myNet.sendUnicastMessage(message.message, gatewayMAC, true); 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);
espnowMessage.push_back(message); attributesMessageResendTimerSemaphore = true;
attributesMessageResendTimer.once(1, sendAttributesMessage);
} }
void sendKeepAliveMessage() void sendKeepAliveMessage()
@ -366,11 +333,12 @@ void sendKeepAliveMessage()
return; return;
keepAliveMessageTimerSemaphore = false; keepAliveMessageTimerSemaphore = false;
esp_now_payload_data_t outgoingData{ENDT_LED, ENPT_KEEP_ALIVE}; esp_now_payload_data_t outgoingData{ENDT_LED, ENPT_KEEP_ALIVE};
espnow_message_t message; char temp[sizeof(esp_now_payload_data_t)]{0};
memcpy(&message.message, &outgoingData, sizeof(esp_now_payload_data_t)); memcpy(&temp, &outgoingData, sizeof(esp_now_payload_data_t));
message.id = myNet.sendUnicastMessage(message.message, gatewayMAC, true); myNet.sendUnicastMessage(temp, gatewayMAC, true);
espnowMessage.push_back(message); keepAliveMessageResendTimerSemaphore = true;
keepAliveMessageResendTimer.once(1, sendKeepAliveMessage);
} }
void sendConfigMessage() void sendConfigMessage()
@ -378,17 +346,20 @@ void sendConfigMessage()
if (!isGatewayAvailable) if (!isGatewayAvailable)
return; return;
esp_now_payload_data_t outgoingData{ENDT_LED, ENPT_CONFIG}; esp_now_payload_data_t outgoingData{ENDT_LED, ENPT_CONFIG};
espnow_message_t message; StaticJsonDocument<sizeof(esp_now_payload_data_t::message)> json;
DynamicJsonDocument json(sizeof(esp_now_payload_data_t::message)); json["name"] = deviceName;
json[MCMT_DEVICE_NAME] = config.deviceName; json["unit"] = 1;
json[MCMT_DEVICE_UNIT] = 1; json["type"] = getValueName(HACT_LIGHT);
json[MCMT_COMPONENT_TYPE] = HACT_LIGHT; json["class"] = ledType;
json[MCMT_DEVICE_CLASS] = config.ledType; char buffer[sizeof(esp_now_payload_data_t::message)]{0};
serializeJsonPretty(json, outgoingData.message); serializeJsonPretty(json, buffer);
memcpy(&message.message, &outgoingData, sizeof(esp_now_payload_data_t)); memcpy(outgoingData.message, buffer, sizeof(esp_now_payload_data_t::message));
message.id = myNet.sendUnicastMessage(message.message, gatewayMAC, true); char temp[sizeof(esp_now_payload_data_t)]{0};
memcpy(&temp, &outgoingData, sizeof(esp_now_payload_data_t));
myNet.sendUnicastMessage(temp, gatewayMAC, true);
espnowMessage.push_back(message); configMessageResendTimerSemaphore = true;
configMessageResendTimer.once(5, sendConfigMessage);
} }
void sendStatusMessage() void sendStatusMessage()
@ -397,25 +368,28 @@ void sendStatusMessage()
return; return;
statusMessageTimerSemaphore = false; statusMessageTimerSemaphore = false;
esp_now_payload_data_t outgoingData{ENDT_LED, ENPT_STATE}; esp_now_payload_data_t outgoingData{ENDT_LED, ENPT_STATE};
espnow_message_t message; StaticJsonDocument<sizeof(esp_now_payload_data_t::message)> json;
DynamicJsonDocument json(sizeof(esp_now_payload_data_t::message));
json["state"] = ledStatus ? "ON" : "OFF"; json["state"] = ledStatus ? "ON" : "OFF";
json["brightness"] = brightness; json["brightness"] = brightness;
json["temperature"] = temperature; json["temperature"] = temperature;
json["rgb"] = String(red) + "," + String(green) + "," + String(blue); json["rgb"] = String(red) + "," + String(green) + "," + String(blue);
serializeJsonPretty(json, outgoingData.message); char buffer[sizeof(esp_now_payload_data_t::message)]{0};
memcpy(&message.message, &outgoingData, sizeof(esp_now_payload_data_t)); serializeJsonPretty(json, buffer);
message.id = myNet.sendUnicastMessage(message.message, gatewayMAC, true); 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);
espnowMessage.push_back(message); statusMessageResendTimerSemaphore = true;
statusMessageResendTimer.once(1, sendStatusMessage);
} }
String getValue(String data, char separator, uint8_t index) String getValue(String data, char separator, byte index)
{ {
uint8_t found{0}; byte found{0};
int strIndex[]{0, -1}; int strIndex[]{0, -1};
int maxIndex = data.length() - 1; int maxIndex = data.length() - 1;
for (uint8_t i{0}; i <= maxIndex && found <= index; i++) for (byte i{0}; i <= maxIndex && found <= index; i++)
if (data.charAt(i) == separator || i == maxIndex) if (data.charAt(i) == separator || i == maxIndex)
{ {
found++; found++;
@ -431,74 +405,72 @@ void changeLedState(void)
{ {
if (red == 255 && green == 255 && blue == 255) if (red == 255 && green == 255 && blue == 255)
{ {
if (config.ledType == ENLT_W || config.ledType == ENLT_RGBW) if (ledType == ENLT_W || ledType == ENLT_RGBW)
analogWrite(config.coldWhitePin, brightness); analogWrite(coldWhitePin, brightness);
if (config.ledType == ENLT_WW || config.ledType == ENLT_RGBWW) if (ledType == ENLT_WW || ledType == ENLT_RGBWW)
{ {
analogWrite(config.coldWhitePin, map(brightness, 0, 255, 0, map(temperature, 500, 153, 0, 255))); analogWrite(coldWhitePin, map(brightness, 0, 255, 0, map(temperature, 500, 153, 0, 255)));
analogWrite(config.warmWhitePin, map(brightness, 0, 255, 0, map(temperature, 153, 500, 0, 255))); analogWrite(warmWhitePin, map(brightness, 0, 255, 0, map(temperature, 153, 500, 0, 255)));
} }
if (config.ledType == ENLT_RGB) if (ledType == ENLT_RGB)
{ {
analogWrite(config.redPin, map(red, 0, 255, 0, brightness)); analogWrite(redPin, map(red, 0, 255, 0, brightness));
analogWrite(config.greenPin, map(green, 0, 255, 0, brightness)); analogWrite(greenPin, map(green, 0, 255, 0, brightness));
analogWrite(config.bluePin, map(blue, 0, 255, 0, brightness)); analogWrite(bluePin, map(blue, 0, 255, 0, brightness));
} }
if (config.ledType == ENLT_RGBW || config.ledType == ENLT_RGBWW) if (ledType == ENLT_RGBW || ledType == ENLT_RGBWW)
{ {
digitalWrite(config.redPin, LOW); digitalWrite(redPin, LOW);
digitalWrite(config.greenPin, LOW); digitalWrite(greenPin, LOW);
digitalWrite(config.bluePin, LOW); digitalWrite(bluePin, LOW);
} }
} }
else else
{ {
if (config.ledType == ENLT_W) if (ledType == ENLT_W)
analogWrite(config.coldWhitePin, brightness); analogWrite(coldWhitePin, brightness);
if (config.ledType == ENLT_WW) if (ledType == ENLT_WW)
{ {
analogWrite(config.coldWhitePin, map(brightness, 0, 255, 0, map(temperature, 500, 153, 0, 255))); analogWrite(coldWhitePin, map(brightness, 0, 255, 0, map(temperature, 500, 153, 0, 255)));
analogWrite(config.warmWhitePin, map(brightness, 0, 255, 0, map(temperature, 153, 500, 0, 255))); analogWrite(warmWhitePin, map(brightness, 0, 255, 0, map(temperature, 153, 500, 0, 255)));
} }
if (config.ledType == ENLT_RGBW || config.ledType == ENLT_RGBWW) if (ledType == ENLT_RGBW || ledType == ENLT_RGBWW)
digitalWrite(config.coldWhitePin, LOW); digitalWrite(coldWhitePin, LOW);
if (config.ledType == ENLT_RGBWW) if (ledType == ENLT_RGBWW)
digitalWrite(config.warmWhitePin, LOW); digitalWrite(warmWhitePin, LOW);
if (config.ledType == ENLT_RGB || config.ledType == ENLT_RGBW || config.ledType == ENLT_RGBWW) if (ledType == ENLT_RGB || ledType == ENLT_RGBW || ledType == ENLT_RGBWW)
{ {
analogWrite(config.redPin, map(red, 0, 255, 0, brightness)); analogWrite(redPin, map(red, 0, 255, 0, brightness));
analogWrite(config.greenPin, map(green, 0, 255, 0, brightness)); analogWrite(greenPin, map(green, 0, 255, 0, brightness));
analogWrite(config.bluePin, map(blue, 0, 255, 0, brightness)); analogWrite(bluePin, map(blue, 0, 255, 0, brightness));
} }
} }
} }
else else
{ {
if (config.ledType == ENLT_W || config.ledType == ENLT_WW || config.ledType == ENLT_RGBW || config.ledType == ENLT_RGBWW) if (ledType == ENLT_W || ledType == ENLT_WW || ledType == ENLT_RGBW || ledType == ENLT_RGBWW)
digitalWrite(config.coldWhitePin, LOW); digitalWrite(coldWhitePin, LOW);
if (config.ledType == ENLT_WW || config.ledType == ENLT_RGBWW) if (ledType == ENLT_WW || ledType == ENLT_RGBWW)
digitalWrite(config.warmWhitePin, LOW); digitalWrite(warmWhitePin, LOW);
if (config.ledType == ENLT_RGB || config.ledType == ENLT_RGBW || config.ledType == ENLT_RGBWW) if (ledType == ENLT_RGB || ledType == ENLT_RGBW || ledType == ENLT_RGBWW)
{ {
digitalWrite(config.redPin, LOW); digitalWrite(redPin, LOW);
digitalWrite(config.greenPin, LOW); digitalWrite(greenPin, LOW);
digitalWrite(config.bluePin, LOW); digitalWrite(bluePin, LOW);
} }
} }
saveStatus(); saveConfig();
} }
void gatewayAvailabilityCheckTimerCallback() void gatewayAvailabilityCheckTimerCallback()
{ {
isGatewayAvailable = false; isGatewayAvailable = false;
memset(&gatewayMAC, 0, 6); memset(gatewayMAC, 0, 6);
espnowMessage.clear();
} }
void apModeHideTimerCallback() void apModeHideTimerCallback()
{ {
WiFi.softAP(("ESP-NOW light " + String(ESP.getChipId(), HEX)).c_str(), "12345678", 1, 1); WiFi.softAP(("ESP-NOW Light " + myNet.getNodeMac()).c_str(), "12345678", 1, 1);
webServer.end();
} }
void attributesMessageTimerCallback() void attributesMessageTimerCallback()