Compare commits

..

5 Commits
v1.42 ... main

Author SHA1 Message Date
b87092d4e1 Version 1.6
Changed config message for ESP-NOW sensors.
Changed config message for RF gateway.
Changed config message for nRF24 sensors.
Minor main code optimization.
Changed config data storage location to EEPROM.
Fixed bug with saving config from Web interface.
2023-03-07 11:54:29 +03:00
Alexey Zholtikov
0038361bb5 Version 1.5
Changed SDK version for 3.0.5 for ESP8266.
Changed config message for ESP-NOW switch.
Changed config message for ESP-NOW light/led strip controller.
Fixed minor bugs.
2023-03-04 08:07:32 +03:00
894eed59f1 Version 1.43
Minor changes.
2023-02-19 12:19:54 +03:00
69cb07f721 Minor changes 2023-02-17 10:08:02 +03:00
5fafe9a538 Minor changes 2023-02-16 18:21:08 +03:00
4 changed files with 243 additions and 234 deletions

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('PUT', '/config.json', true); xmlHttp.open('GET', '/config', true);
xmlHttp.send(null); xmlHttp.send(null);
xmlHttp.onload = function () { xmlHttp.onload = function () {
jsonResponse = JSON.parse(xmlHttp.responseText); jsonResponse = JSON.parse(xmlHttp.responseText);
@ -52,14 +52,14 @@ function sendRequest(submit, server) {
function saveSetting(submit) { function saveSetting(submit) {
server = "/setting?ssid=" + getValue('ssid') + "&password=" + encodeURIComponent(getValue('password')) server = "/setting?ssid=" + getValue('ssid') + "&password=" + encodeURIComponent(getValue('password'))
+ "&host=" + getValue('mqttHostName') + "&port=" + getValue('mqttHostPort') + "&mqttHostName=" + getValue('mqttHostName') + "&mqttHostPort=" + getValue('mqttHostPort')
+ "&login=" + getValue('mqttUserLogin') + "&pass=" + encodeURIComponent(getValue('mqttUserPassword')) + "&mqttUserLogin=" + getValue('mqttUserLogin') + "&mqttUserPassword=" + encodeURIComponent(getValue('mqttUserPassword'))
+ "&prefix=" + getValue('topicPrefix') + "&topicPrefix=" + getValue('topicPrefix')
+ "&name=" + getValue('deviceName') + "&deviceName=" + getValue('deviceName')
+ "&net=" + getValue('espnowNetName') + "&espnowNetName=" + getValue('espnowNetName')
+ "&mode=" + getSelectValue('workModeSelect') + "&workMode=" + getSelectValue('workModeSelect')
+ "&ntp=" + getValue('ntpHostName') + "&ntpHostName=" + getValue('ntpHostName')
+ "&zone=" + getValue('gmtOffset'); + "&gmtOffset=" + getValue('gmtOffset');
sendRequest(submit, server); sendRequest(submit, server);
alert("Please restart device for changes apply."); alert("Please restart device for changes apply.");
} }

View File

@ -10,7 +10,7 @@
<body onload="load();"> <body onload="load();">
<form class="box"> <form class="box">
<h1>ESP-NOW Gateway </h1> <h1>ESP-NOW Gateway</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

@ -2,6 +2,7 @@
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.filesystem = littlefs
lib_deps = lib_deps =
https://github.com/aZholtikov/ZHNetwork https://github.com/aZholtikov/ZHNetwork
@ -16,6 +17,7 @@ lib_deps =
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.filesystem = littlefs
upload_port = 192.168.4.1 upload_port = 192.168.4.1
upload_protocol = espota upload_protocol = espota

View File

@ -4,6 +4,7 @@
#include "Ethernet.h" // https://github.com/arduino-libraries/Ethernet #include "Ethernet.h" // https://github.com/arduino-libraries/Ethernet
#include "PubSubClient.h" #include "PubSubClient.h"
#include "LittleFS.h" #include "LittleFS.h"
#include "EEPROM.h"
#include "Ticker.h" #include "Ticker.h"
#include "NTPClient.h" #include "NTPClient.h"
#include "ZHNetwork.h" #include "ZHNetwork.h"
@ -15,13 +16,6 @@
#include "ESP32SSDP.h" #include "ESP32SSDP.h"
#endif #endif
typedef enum : uint8_t
{
ESP_NOW,
ESP_NOW_WIFI,
ESP_NOW_LAN
} work_mode_t;
void onEspnowMessage(const char *data, const uint8_t *sender); void onEspnowMessage(const char *data, const uint8_t *sender);
void onMqttMessage(char *topic, byte *payload, unsigned int length); void onMqttMessage(char *topic, byte *payload, unsigned int length);
@ -42,31 +36,37 @@ void checkMqttAvailability(void);
void mqttPublish(const char *topic, const char *payload, bool retained); void mqttPublish(const char *topic, const char *payload, bool retained);
const String firmware{"1.42"}; typedef enum : uint8_t
{
String espnowNetName{"DEFAULT"}; ESP_NOW,
ESP_NOW_WIFI,
uint8_t workMode{ESP_NOW}; ESP_NOW_LAN
} work_mode_t;
struct deviceConfig
{
#if defined(ESP8266) #if defined(ESP8266)
String deviceName = "ESP-NOW gateway " + String(ESP.getChipId(), HEX); String deviceName = "ESP-NOW gateway " + String(ESP.getChipId(), HEX);
#endif #endif
#if defined(ESP32) #if defined(ESP32)
String deviceName = "ESP-NOW gateway " + String(ESP.getEfuseMac(), HEX); String deviceName = "ESP-NOW gateway " + String(ESP.getEfuseMac(), HEX);
#endif #endif
String espnowNetName{"DEFAULT"};
uint8_t workMode{ESP_NOW};
String ssid{"SSID"};
String password{"PASSWORD"};
String mqttHostName{"MQTT"};
uint16_t mqttHostPort{1883};
String mqttUserLogin{""};
String mqttUserPassword{""};
String topicPrefix{"homeassistant"};
String ntpHostName{"NTP"};
uint16_t gmtOffset{10800};
} config;
String ssid{"SSID"}; const String firmware{"1.6"};
String password{"PASSWORD"};
String mqttHostName{"MQTT"}; const char *mqttUserID{"ESP"};
uint16_t mqttHostPort{1883};
String mqttUserLogin{""};
String mqttUserPassword{""};
String topicPrefix{"homeassistant"};
const char *mqttUserID{"ESP32"};
String ntpHostName{"NTP"};
uint16_t gmtOffset{10800};
uint8_t w5500Mac[6] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; // Change it if necessary. uint8_t w5500Mac[6] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; // Change it if necessary.
@ -82,8 +82,8 @@ PubSubClient mqttWifiClient(wifiClient);
WiFiUDP udpWiFiClient; WiFiUDP udpWiFiClient;
EthernetUDP udpEthClient; EthernetUDP udpEthClient;
NTPClient ntpWiFiClient(udpWiFiClient, ntpHostName.c_str(), gmtOffset); NTPClient ntpWiFiClient(udpWiFiClient, config.ntpHostName.c_str(), config.gmtOffset);
NTPClient ntpEthClient(udpEthClient, ntpHostName.c_str(), gmtOffset); NTPClient ntpEthClient(udpEthClient, config.ntpHostName.c_str(), config.gmtOffset);
Ticker mqttAvailabilityCheckTimer; Ticker mqttAvailabilityCheckTimer;
bool mqttAvailabilityCheckTimerSemaphore{true}; bool mqttAvailabilityCheckTimerSemaphore{true};
@ -109,13 +109,13 @@ void setup()
loadConfig(); loadConfig();
if (workMode == ESP_NOW_LAN) if (config.workMode == ESP_NOW_LAN)
{ {
Ethernet.init(5); Ethernet.init(5);
Ethernet.begin(w5500Mac); Ethernet.begin(w5500Mac);
} }
if (workMode == ESP_NOW_WIFI) if (config.workMode == ESP_NOW_WIFI)
{ {
#if defined(ESP8266) #if defined(ESP8266)
WiFi.setSleepMode(WIFI_NONE_SLEEP); WiFi.setSleepMode(WIFI_NONE_SLEEP);
@ -128,9 +128,9 @@ void setup()
WiFi.setAutoReconnect(true); WiFi.setAutoReconnect(true);
} }
myNet.begin(espnowNetName.c_str(), true); myNet.begin(config.espnowNetName.c_str(), true);
if (workMode) if (config.workMode)
{ {
// 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.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(onEspnowMessage); myNet.setOnBroadcastReceivingCallback(onEspnowMessage);
@ -144,7 +144,7 @@ void setup()
WiFi.softAP(("ESP-NOW gateway " + String(ESP.getEfuseMac(), HEX)).c_str(), "12345678"); WiFi.softAP(("ESP-NOW gateway " + String(ESP.getEfuseMac(), HEX)).c_str(), "12345678");
#endif #endif
if (workMode == ESP_NOW_WIFI) if (config.workMode == ESP_NOW_WIFI)
{ {
uint8_t scan = WiFi.scanNetworks(false, false); uint8_t scan = WiFi.scanNetworks(false, false);
String name; String name;
@ -161,24 +161,24 @@ void setup()
#if defined(ESP32) #if defined(ESP32)
WiFi.getNetworkInfo(i, name, encryption, rssi, bssid, channel); WiFi.getNetworkInfo(i, name, encryption, rssi, bssid, channel);
#endif #endif
if (name == ssid) if (name == config.ssid)
WiFi.begin(ssid.c_str(), password.c_str()); WiFi.begin(config.ssid.c_str(), config.password.c_str());
} }
} }
if (workMode == ESP_NOW_WIFI) if (config.workMode == ESP_NOW_WIFI)
{ {
ntpWiFiClient.begin(); ntpWiFiClient.begin();
mqttWifiClient.setBufferSize(2048); mqttWifiClient.setBufferSize(2048);
mqttWifiClient.setServer(mqttHostName.c_str(), mqttHostPort); mqttWifiClient.setServer(config.mqttHostName.c_str(), config.mqttHostPort);
mqttWifiClient.setCallback(onMqttMessage); mqttWifiClient.setCallback(onMqttMessage);
} }
if (workMode == ESP_NOW_LAN) if (config.workMode == ESP_NOW_LAN)
{ {
ntpEthClient.begin(); ntpEthClient.begin();
mqttEthClient.setBufferSize(2048); mqttEthClient.setBufferSize(2048);
mqttEthClient.setServer(mqttHostName.c_str(), mqttHostPort); mqttEthClient.setServer(config.mqttHostName.c_str(), config.mqttHostPort);
mqttEthClient.setCallback(onMqttMessage); mqttEthClient.setCallback(onMqttMessage);
} }
@ -193,15 +193,15 @@ void setup()
void loop() void loop()
{ {
if (mqttAvailabilityCheckTimerSemaphore)
checkMqttAvailability();
if (keepAliveMessageTimerSemaphore) if (keepAliveMessageTimerSemaphore)
sendKeepAliveMessage(); sendKeepAliveMessage();
if (attributesMessageTimerSemaphore) if (attributesMessageTimerSemaphore)
sendAttributesMessage(); sendAttributesMessage();
if (mqttAvailabilityCheckTimerSemaphore) if (config.workMode == ESP_NOW_WIFI)
checkMqttAvailability();
if (workMode == ESP_NOW_WIFI)
mqttWifiClient.loop(); mqttWifiClient.loop();
if (workMode == ESP_NOW_LAN) if (config.workMode == ESP_NOW_LAN)
mqttEthClient.loop(); mqttEthClient.loop();
myNet.maintenance(); myNet.maintenance();
ArduinoOTA.handle(); ArduinoOTA.handle();
@ -214,180 +214,187 @@ void onEspnowMessage(const char *data, const uint8_t *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.payloadsType == ENPT_ATTRIBUTES) if (incomingData.payloadsType == ENPT_ATTRIBUTES)
mqttPublish((topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/" + getValueName(incomingData.payloadsType)).c_str(), incomingData.message, true); mqttPublish((config.topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/" + getValueName(incomingData.payloadsType)).c_str(), incomingData.message, true);
if (incomingData.payloadsType == ENPT_KEEP_ALIVE) if (incomingData.payloadsType == ENPT_KEEP_ALIVE)
mqttPublish((topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/" + getValueName(incomingData.payloadsType)).c_str(), "online", true); mqttPublish((config.topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/" + getValueName(incomingData.payloadsType)).c_str(), "online", true);
if (incomingData.payloadsType == ENPT_STATE) if (incomingData.payloadsType == ENPT_STATE)
mqttPublish((topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/" + getValueName(incomingData.payloadsType)).c_str(), incomingData.message, true); mqttPublish((config.topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/" + getValueName(incomingData.payloadsType)).c_str(), incomingData.message, true);
if (incomingData.payloadsType == ENPT_CONFIG) if (incomingData.payloadsType == ENPT_CONFIG)
{ {
if (incomingData.deviceType == ENDT_SWITCH) if (incomingData.deviceType == ENDT_SWITCH)
{ {
esp_now_payload_data_t configData; esp_now_payload_data_t configData;
memcpy(&configData.message, &incomingData.message, sizeof(esp_now_payload_data_t::message)); memcpy(&configData.message, &incomingData.message, sizeof(esp_now_payload_data_t::message));
StaticJsonDocument<sizeof(esp_now_payload_data_t::message)> json; DynamicJsonDocument json(sizeof(esp_now_payload_data_t::message));
deserializeJson(json, configData.message); deserializeJson(json, configData.message);
uint8_t unit = json["unit"].as<uint8_t>(); uint8_t unit = json[MCMT_DEVICE_UNIT].as<uint8_t>();
StaticJsonDocument<2048> jsonConfig; DynamicJsonDocument jsonConfig(2048); // Same as PubSubClient buffer size.
jsonConfig["platform"] = "mqtt"; jsonConfig["platform"] = "mqtt";
jsonConfig["name"] = json["name"]; jsonConfig["name"] = json[MCMT_DEVICE_NAME];
jsonConfig["unique_id"] = myNet.macToString(sender) + "-" + unit; jsonConfig["unique_id"] = myNet.macToString(sender) + "-" + unit;
jsonConfig["device_class"] = getValueName(json["class"].as<ha_switch_device_class_t>()); jsonConfig["device_class"] = getValueName(json[MCMT_DEVICE_CLASS].as<ha_switch_device_class_t>());
jsonConfig["state_topic"] = topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/state"; jsonConfig["state_topic"] = config.topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/state";
jsonConfig["value_template"] = "{{ value_json." + json["template"].as<String>() + " }}"; jsonConfig["value_template"] = "{{ value_json." + json[MCMT_VALUE_TEMPLATE].as<String>() + " }}";
jsonConfig["command_topic"] = topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/set"; jsonConfig["command_topic"] = config.topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/set";
jsonConfig["json_attributes_topic"] = topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/attributes"; jsonConfig["json_attributes_topic"] = config.topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/attributes";
jsonConfig["availability_topic"] = topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/status"; jsonConfig["availability_topic"] = config.topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/status";
jsonConfig["payload_on"] = json["payload_on"]; if (json[MCMT_PAYLOAD_ON])
jsonConfig["payload_off"] = json["payload_off"]; jsonConfig["payload_on"] = json[MCMT_PAYLOAD_ON];
if (json[MCMT_PAYLOAD_OFF])
jsonConfig["payload_off"] = json[MCMT_PAYLOAD_OFF];
jsonConfig["optimistic"] = "false"; jsonConfig["optimistic"] = "false";
jsonConfig["retain"] = "true"; jsonConfig["retain"] = "true";
char buffer[2048]{0}; char buffer[2048]{0};
serializeJsonPretty(jsonConfig, buffer); serializeJsonPretty(jsonConfig, buffer);
mqttPublish((topicPrefix + "/" + getValueName(json["type"].as<ha_component_type_t>()) + "/" + myNet.macToString(sender) + "-" + unit + "/config").c_str(), buffer, true); mqttPublish((config.topicPrefix + "/" + getValueName(json[MCMT_COMPONENT_TYPE].as<ha_component_type_t>()) + "/" + myNet.macToString(sender) + "-" + unit + "/config").c_str(), buffer, true);
} }
if (incomingData.deviceType == ENDT_LED) if (incomingData.deviceType == ENDT_LED)
{ {
esp_now_payload_data_t configData; esp_now_payload_data_t configData;
memcpy(&configData.message, &incomingData.message, sizeof(esp_now_payload_data_t::message)); memcpy(&configData.message, &incomingData.message, sizeof(esp_now_payload_data_t::message));
StaticJsonDocument<sizeof(esp_now_payload_data_t::message)> json; DynamicJsonDocument json(sizeof(esp_now_payload_data_t::message));
deserializeJson(json, configData.message); deserializeJson(json, configData.message);
uint8_t unit = json["unit"].as<uint8_t>(); uint8_t unit = json[MCMT_DEVICE_UNIT].as<uint8_t>();
esp_now_led_type_t ledClass = json["class"]; esp_now_led_type_t ledClass = json[MCMT_DEVICE_CLASS];
StaticJsonDocument<2048> jsonConfig; DynamicJsonDocument jsonConfig(2048); // Same as PubSubClient buffer size.
jsonConfig["platform"] = "mqtt"; jsonConfig["platform"] = "mqtt";
jsonConfig["name"] = json["name"]; jsonConfig["name"] = json[MCMT_DEVICE_NAME];
jsonConfig["unique_id"] = myNet.macToString(sender) + "-" + unit; jsonConfig["unique_id"] = myNet.macToString(sender) + "-" + unit;
jsonConfig["state_topic"] = topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/state"; jsonConfig["state_topic"] = config.topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/state";
jsonConfig["state_value_template"] = "{{ value_json.state }}"; jsonConfig["state_value_template"] = "{{ value_json.state }}";
jsonConfig["command_topic"] = topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/set"; jsonConfig["command_topic"] = config.topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/set";
jsonConfig["brightness_state_topic"] = topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/state"; jsonConfig["brightness_state_topic"] = config.topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/state";
jsonConfig["brightness_value_template"] = "{{ value_json.brightness }}"; jsonConfig["brightness_value_template"] = "{{ value_json.brightness }}";
jsonConfig["brightness_command_topic"] = topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/brightness"; jsonConfig["brightness_command_topic"] = config.topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/brightness";
if (ledClass == ENLT_RGB || ledClass == ENLT_RGBW || ledClass == ENLT_RGBWW) if (ledClass == ENLT_RGB || ledClass == ENLT_RGBW || ledClass == ENLT_RGBWW)
{ {
jsonConfig["rgb_state_topic"] = topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/state"; jsonConfig["rgb_state_topic"] = config.topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/state";
jsonConfig["rgb_value_template"] = "{{ value_json.rgb | join(',') }}"; jsonConfig["rgb_value_template"] = "{{ value_json.rgb | join(',') }}";
jsonConfig["rgb_command_topic"] = topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/rgb"; jsonConfig["rgb_command_topic"] = config.topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/rgb";
} }
if (ledClass == ENLT_WW || ledClass == ENLT_RGBWW) if (ledClass == ENLT_WW || ledClass == ENLT_RGBWW)
{ {
jsonConfig["color_temp_state_topic"] = topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/state"; jsonConfig["color_temp_state_topic"] = config.topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/state";
jsonConfig["color_temp_value_template"] = "{{ value_json.temperature }}"; jsonConfig["color_temp_value_template"] = "{{ value_json.temperature }}";
jsonConfig["color_temp_command_topic"] = topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/temperature"; jsonConfig["color_temp_command_topic"] = config.topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/temperature";
} }
jsonConfig["json_attributes_topic"] = topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/attributes"; jsonConfig["json_attributes_topic"] = config.topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/attributes";
jsonConfig["availability_topic"] = topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/status"; jsonConfig["availability_topic"] = config.topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/status";
jsonConfig["payload_on"] = json["payload_on"]; if (json[MCMT_PAYLOAD_ON])
jsonConfig["payload_off"] = json["payload_off"]; jsonConfig["payload_on"] = json[MCMT_PAYLOAD_ON];
if (json[MCMT_PAYLOAD_OFF])
jsonConfig["payload_off"] = json[MCMT_PAYLOAD_OFF];
jsonConfig["optimistic"] = "false"; jsonConfig["optimistic"] = "false";
jsonConfig["retain"] = "true"; jsonConfig["retain"] = "true";
char buffer[2048]{0}; char buffer[2048]{0};
serializeJsonPretty(jsonConfig, buffer); serializeJsonPretty(jsonConfig, buffer);
mqttPublish((topicPrefix + "/" + getValueName(json["type"].as<ha_component_type_t>()) + "/" + myNet.macToString(sender) + "-" + unit + "/config").c_str(), buffer, true); mqttPublish((config.topicPrefix + "/" + getValueName(json[MCMT_COMPONENT_TYPE].as<ha_component_type_t>()) + "/" + myNet.macToString(sender) + "-" + unit + "/config").c_str(), buffer, true);
} }
if (incomingData.deviceType == ENDT_SENSOR) if (incomingData.deviceType == ENDT_SENSOR)
{ {
esp_now_payload_data_t configData; esp_now_payload_data_t configData;
memcpy(&configData.message, &incomingData.message, sizeof(esp_now_payload_data_t::message)); memcpy(&configData.message, &incomingData.message, sizeof(esp_now_payload_data_t::message));
StaticJsonDocument<sizeof(esp_now_payload_data_t::message)> json; DynamicJsonDocument json(sizeof(esp_now_payload_data_t::message));
deserializeJson(json, configData.message); deserializeJson(json, configData.message);
uint8_t unit = json["unit"].as<uint8_t>(); uint8_t unit = json[MCMT_DEVICE_UNIT].as<uint8_t>();
ha_component_type_t type = json["type"].as<ha_component_type_t>(); ha_component_type_t type = json[MCMT_COMPONENT_TYPE].as<ha_component_type_t>();
StaticJsonDocument<2048> jsonConfig; DynamicJsonDocument jsonConfig(2048); // Same as PubSubClient buffer size.
jsonConfig["platform"] = "mqtt"; jsonConfig["platform"] = "mqtt";
jsonConfig["name"] = json["name"]; jsonConfig["name"] = json[MCMT_DEVICE_NAME];
jsonConfig["unique_id"] = myNet.macToString(sender) + "-" + unit; jsonConfig["unique_id"] = myNet.macToString(sender) + "-" + unit;
jsonConfig["state_topic"] = topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/state"; jsonConfig["state_topic"] = config.topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/state";
jsonConfig["value_template"] = "{{ value_json." + json["template"].as<String>() + " }}"; jsonConfig["value_template"] = "{{ value_json." + json[MCMT_VALUE_TEMPLATE].as<String>() + " }}";
jsonConfig["json_attributes_topic"] = topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/attributes"; jsonConfig["json_attributes_topic"] = config.topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/attributes";
jsonConfig["force_update"] = "true"; jsonConfig["force_update"] = "true";
jsonConfig["retain"] = "true"; jsonConfig["retain"] = "true";
if (type == HACT_SENSOR) if (type == HACT_SENSOR)
jsonConfig["device_class"] = getValueName(json["class"].as<ha_sensor_device_class_t>());
if (type == HACT_BINARY_SENSOR)
{ {
ha_binary_sensor_device_class_t deviceClass = json["class"].as<ha_binary_sensor_device_class_t>(); jsonConfig["device_class"] = getValueName(json[MCMT_DEVICE_CLASS].as<ha_sensor_device_class_t>());
if (deviceClass == HABSDC_BATTERY || deviceClass == HABSDC_WINDOW || deviceClass == HABSDC_DOOR) jsonConfig["unit_of_measurement"] = json[MCMT_UNIT_OF_MEASUREMENT];
jsonConfig["payload_off"] = json["payload_off"];
if (deviceClass == HABSDC_CONNECTIVITY)
jsonConfig["expire_after"] = json["expire_after"];
jsonConfig["device_class"] = getValueName(deviceClass);
jsonConfig["payload_on"] = json["payload_on"];
} }
if (type == HACT_BINARY_SENSOR)
jsonConfig["device_class"] = getValueName(json[MCMT_DEVICE_CLASS].as<ha_binary_sensor_device_class_t>());
if (json[MCMT_EXPIRE_AFTER])
jsonConfig["expire_after"] = json[MCMT_EXPIRE_AFTER];
if (json[MCMT_OFF_DELAY])
jsonConfig["off_delay"] = json[MCMT_OFF_DELAY];
if (json[MCMT_PAYLOAD_ON])
jsonConfig["payload_on"] = json[MCMT_PAYLOAD_ON];
if (json[MCMT_PAYLOAD_OFF])
jsonConfig["payload_off"] = json[MCMT_PAYLOAD_OFF];
char buffer[2048]{0}; char buffer[2048]{0};
serializeJsonPretty(jsonConfig, buffer); serializeJsonPretty(jsonConfig, buffer);
mqttPublish((topicPrefix + "/" + getValueName(type) + "/" + myNet.macToString(sender) + "-" + unit + "/config").c_str(), buffer, true); mqttPublish((config.topicPrefix + "/" + getValueName(type) + "/" + myNet.macToString(sender) + "-" + unit + "/config").c_str(), buffer, true);
} }
if (incomingData.deviceType == ENDT_RF_SENSOR) if (incomingData.deviceType == ENDT_RF_SENSOR)
{ {
esp_now_payload_data_t configData; esp_now_payload_data_t configData;
memcpy(&configData.message, &incomingData.message, sizeof(esp_now_payload_data_t::message)); memcpy(&configData.message, &incomingData.message, sizeof(esp_now_payload_data_t::message));
StaticJsonDocument<sizeof(esp_now_payload_data_t::message)> json; DynamicJsonDocument json(sizeof(esp_now_payload_data_t::message));
deserializeJson(json, configData.message); deserializeJson(json, configData.message);
uint8_t unit = json["u"].as<uint8_t>(); uint8_t unit = json[MCMT_DEVICE_UNIT].as<uint8_t>();
ha_component_type_t type = json["t"].as<ha_component_type_t>(); ha_component_type_t haComponentType = json[MCMT_COMPONENT_TYPE].as<ha_component_type_t>();
rf_sensor_type_t rf = json["r"].as<rf_sensor_type_t>(); rf_sensor_type_t rfSensorType = json[MCMT_RF_SENSOR_TYPE].as<rf_sensor_type_t>();
uint16_t id = json["i"].as<uint16_t>(); uint16_t rfSensorId = json[MCMT_RF_SENSOR_ID].as<uint16_t>();
String tmp = json["v"].as<String>(); String valueTemplate = json[MCMT_VALUE_TEMPLATE].as<String>();
StaticJsonDocument<2048> jsonConfig; DynamicJsonDocument jsonConfig(2048); // Same as PubSubClient buffer size.
jsonConfig["platform"] = "mqtt"; jsonConfig["platform"] = "mqtt";
jsonConfig["name"] = getValueName(rf) + " " + id + " " + tmp; jsonConfig["name"] = getValueName(rfSensorType) + " " + rfSensorId + " " + valueTemplate;
jsonConfig["unique_id"] = String(id) + "-" + unit; jsonConfig["unique_id"] = String(rfSensorId) + "-" + unit;
jsonConfig["state_topic"] = topicPrefix + "/rf_sensor/" + getValueName(rf) + "/" + id + "/state"; jsonConfig["state_topic"] = config.topicPrefix + "/rf_sensor/" + getValueName(rfSensorType) + "/" + rfSensorId + "/state";
jsonConfig["value_template"] = "{{ value_json." + tmp + " }}"; jsonConfig["value_template"] = "{{ value_json." + valueTemplate + " }}";
if (type == HACT_SENSOR)
{
jsonConfig["device_class"] = getValueName(json["h"].as<ha_sensor_device_class_t>());
jsonConfig["unit_of_measurement"] = json["m"];
jsonConfig["expire_after"] = json["e"];
}
if (type == HACT_BINARY_SENSOR)
{
ha_binary_sensor_device_class_t deviceClass = json["h"].as<ha_binary_sensor_device_class_t>();
if (deviceClass == HABSDC_MOISTURE)
jsonConfig["expire_after"] = json["e"];
jsonConfig["device_class"] = getValueName(deviceClass);
jsonConfig["payload_on"] = json["o"];
jsonConfig["payload_off"] = json["f"];
}
jsonConfig["force_update"] = "true"; jsonConfig["force_update"] = "true";
jsonConfig["retain"] = "true"; jsonConfig["retain"] = "true";
if (haComponentType == HACT_SENSOR)
{
jsonConfig["device_class"] = getValueName(json[MCMT_DEVICE_CLASS].as<ha_sensor_device_class_t>());
jsonConfig["unit_of_measurement"] = json[MCMT_UNIT_OF_MEASUREMENT];
}
if (haComponentType == HACT_BINARY_SENSOR)
jsonConfig["device_class"] = getValueName(json[MCMT_DEVICE_CLASS].as<ha_binary_sensor_device_class_t>());
if (json[MCMT_EXPIRE_AFTER])
jsonConfig["expire_after"] = json[MCMT_EXPIRE_AFTER];
if (json[MCMT_OFF_DELAY])
jsonConfig["off_delay"] = json[MCMT_OFF_DELAY];
if (json[MCMT_PAYLOAD_ON])
jsonConfig["payload_on"] = json[MCMT_PAYLOAD_ON];
if (json[MCMT_PAYLOAD_OFF])
jsonConfig["payload_off"] = json[MCMT_PAYLOAD_OFF];
char buffer[2048]{0}; char buffer[2048]{0};
serializeJsonPretty(jsonConfig, buffer); serializeJsonPretty(jsonConfig, buffer);
mqttPublish((topicPrefix + "/" + getValueName(type) + "/" + id + "-" + unit + "/config").c_str(), buffer, true); mqttPublish((config.topicPrefix + "/" + getValueName(haComponentType) + "/" + rfSensorId + "-" + unit + "/config").c_str(), buffer, true);
} }
if (incomingData.deviceType == ENDT_RF_GATEWAY) if (incomingData.deviceType == ENDT_RF_GATEWAY)
{ {
esp_now_payload_data_t configData; esp_now_payload_data_t configData;
memcpy(&configData.message, &incomingData.message, sizeof(esp_now_payload_data_t::message)); memcpy(&configData.message, &incomingData.message, sizeof(esp_now_payload_data_t::message));
StaticJsonDocument<sizeof(esp_now_payload_data_t::message)> json; DynamicJsonDocument json(sizeof(esp_now_payload_data_t::message));
deserializeJson(json, configData.message); deserializeJson(json, configData.message);
uint8_t unit = json["unit"].as<uint8_t>(); uint8_t unit = json[MCMT_DEVICE_UNIT].as<uint8_t>();
StaticJsonDocument<2048> jsonConfig; DynamicJsonDocument jsonConfig(2048); // Same as PubSubClient buffer size.
jsonConfig["platform"] = "mqtt"; jsonConfig["platform"] = "mqtt";
jsonConfig["name"] = json["name"]; jsonConfig["name"] = json[MCMT_DEVICE_NAME];
jsonConfig["unique_id"] = myNet.macToString(sender) + "-" + unit; jsonConfig["unique_id"] = myNet.macToString(sender) + "-" + unit;
jsonConfig["device_class"] = getValueName(json["class"].as<ha_binary_sensor_device_class_t>()); jsonConfig["device_class"] = getValueName(json[MCMT_DEVICE_CLASS].as<ha_binary_sensor_device_class_t>());
jsonConfig["state_topic"] = topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/status"; jsonConfig["state_topic"] = config.topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/status";
jsonConfig["json_attributes_topic"] = topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/attributes"; jsonConfig["json_attributes_topic"] = config.topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/attributes";
jsonConfig["payload_on"] = json["payload_on"]; jsonConfig["payload_on"] = json[MCMT_PAYLOAD_ON];
jsonConfig["expire_after"] = json["expire_after"]; jsonConfig["expire_after"] = json[MCMT_EXPIRE_AFTER];
jsonConfig["force_update"] = "true"; jsonConfig["force_update"] = "true";
jsonConfig["retain"] = "true"; jsonConfig["retain"] = "true";
char buffer[2048]{0}; char buffer[2048]{0};
serializeJsonPretty(jsonConfig, buffer); serializeJsonPretty(jsonConfig, buffer);
mqttPublish((topicPrefix + "/" + getValueName(json["type"].as<ha_component_type_t>()) + "/" + myNet.macToString(sender) + "-" + unit + "/config").c_str(), buffer, true); mqttPublish((config.topicPrefix + "/" + getValueName(json[MCMT_COMPONENT_TYPE].as<ha_component_type_t>()) + "/" + myNet.macToString(sender) + "-" + unit + "/config").c_str(), buffer, true);
} }
} }
if (incomingData.payloadsType == ENPT_FORWARD) if (incomingData.payloadsType == ENPT_FORWARD)
{ {
esp_now_payload_data_t forwardData; esp_now_payload_data_t forwardData;
memcpy(&forwardData.message, &incomingData.message, sizeof(esp_now_payload_data_t::message)); memcpy(&forwardData.message, &incomingData.message, sizeof(esp_now_payload_data_t::message));
StaticJsonDocument<sizeof(esp_now_payload_data_t::message)> json; DynamicJsonDocument json(sizeof(esp_now_payload_data_t::message));
deserializeJson(json, forwardData.message); deserializeJson(json, forwardData.message);
if (incomingData.deviceType == ENDT_RF_GATEWAY) if (incomingData.deviceType == ENDT_RF_GATEWAY)
mqttPublish((topicPrefix + "/rf_sensor/" + getValueName(json["type"].as<rf_sensor_type_t>()) + "/" + json["id"].as<uint16_t>() + "/state").c_str(), incomingData.message, false); mqttPublish((config.topicPrefix + "/rf_sensor/" + getValueName(json["type"].as<rf_sensor_type_t>()) + "/" + json["id"].as<uint16_t>() + "/state").c_str(), incomingData.message, false);
} }
} }
@ -402,29 +409,30 @@ void onMqttMessage(char *topic, byte *payload, unsigned int length)
} }
esp_now_payload_data_t outgoingData; esp_now_payload_data_t outgoingData;
outgoingData.deviceType = ENDT_GATEWAY; outgoingData.deviceType = ENDT_GATEWAY;
StaticJsonDocument<sizeof(esp_now_payload_data_t::message)> json; outgoingData.payloadsType = ENPT_SET;
DynamicJsonDocument json(sizeof(esp_now_payload_data_t::message));
if (message == "update" || message == "restart") if (message == "update" || message == "restart")
{ {
if (mac == myNet.getNodeMac() && message == "restart") if (mac == myNet.getNodeMac() && message == "restart")
ESP.restart(); ESP.restart();
flag = true; flag = true;
} }
if (String(topic) == topicPrefix + "/espnow_switch/" + mac + "/set" || String(topic) == topicPrefix + "/espnow_led/" + mac + "/set") if (String(topic) == config.topicPrefix + "/espnow_switch/" + mac + "/set" || String(topic) == config.topicPrefix + "/espnow_led/" + mac + "/set")
{ {
flag = true; flag = true;
json["set"] = message; json["set"] = message;
} }
if (String(topic) == topicPrefix + "/espnow_led/" + mac + "/brightness") if (String(topic) == config.topicPrefix + "/espnow_led/" + mac + "/brightness")
{ {
flag = true; flag = true;
json["brightness"] = message; json["brightness"] = message;
} }
if (String(topic) == topicPrefix + "/espnow_led/" + mac + "/temperature") if (String(topic) == config.topicPrefix + "/espnow_led/" + mac + "/temperature")
{ {
flag = true; flag = true;
json["temperature"] = message; json["temperature"] = message;
} }
if (String(topic) == topicPrefix + "/espnow_led/" + mac + "/rgb") if (String(topic) == config.topicPrefix + "/espnow_led/" + mac + "/rgb")
{ {
flag = true; flag = true;
json["rgb"] = message; json["rgb"] = message;
@ -433,8 +441,8 @@ void onMqttMessage(char *topic, byte *payload, unsigned int length)
{ {
if (message == "restart") if (message == "restart")
outgoingData.payloadsType = ENPT_RESTART; outgoingData.payloadsType = ENPT_RESTART;
else if (message == "update")
outgoingData.payloadsType = message == "update" ? ENPT_UPDATE : ENPT_SET; outgoingData.payloadsType = ENPT_UPDATE;
serializeJsonPretty(json, outgoingData.message); serializeJsonPretty(json, outgoingData.message);
char temp[sizeof(esp_now_payload_data_t)]{0}; char temp[sizeof(esp_now_payload_data_t)]{0};
memcpy(&temp, &outgoingData, sizeof(esp_now_payload_data_t)); memcpy(&temp, &outgoingData, sizeof(esp_now_payload_data_t));
@ -448,14 +456,14 @@ void sendKeepAliveMessage()
{ {
keepAliveMessageTimerSemaphore = false; keepAliveMessageTimerSemaphore = false;
if (isMqttAvailable) if (isMqttAvailable)
mqttPublish((topicPrefix + "/espnow_gateway/" + myNet.getNodeMac() + "/status").c_str(), "online", true); mqttPublish((config.topicPrefix + "/espnow_gateway/" + myNet.getNodeMac() + "/status").c_str(), "online", true);
esp_now_payload_data_t outgoingData; esp_now_payload_data_t outgoingData;
outgoingData.deviceType = ENDT_GATEWAY; outgoingData.deviceType = ENDT_GATEWAY;
outgoingData.payloadsType = ENPT_KEEP_ALIVE; outgoingData.payloadsType = ENPT_KEEP_ALIVE;
StaticJsonDocument<sizeof(esp_now_payload_data_t::message)> json; DynamicJsonDocument json(sizeof(esp_now_payload_data_t::message));
json["MQTT"] = isMqttAvailable ? "online" : "offline"; json["MQTT"] = isMqttAvailable ? "online" : "offline";
json["frequency"] = 10; // For compatibility with the previous version. Will be removed in future releases. json["frequency"] = 10; // For compatibility with the previous version. Will be removed in future releases.
if (workMode == ESP_NOW_WIFI) if (config.workMode == ESP_NOW_WIFI && WiFi.isConnected())
{ {
ntpWiFiClient.update(); ntpWiFiClient.update();
uint64_t epochTime = ntpWiFiClient.getEpochTime(); uint64_t epochTime = ntpWiFiClient.getEpochTime();
@ -463,7 +471,7 @@ void sendKeepAliveMessage()
json["time"] = ntpWiFiClient.getFormattedTime(); json["time"] = ntpWiFiClient.getFormattedTime();
json["date"] = String(time->tm_mday) + "." + String(time->tm_mon + 1) + "." + String(time->tm_year + 1900); json["date"] = String(time->tm_mday) + "." + String(time->tm_mon + 1) + "." + String(time->tm_year + 1900);
} }
if (workMode == ESP_NOW_LAN) if (config.workMode == ESP_NOW_LAN && Ethernet.linkStatus() == LinkON)
{ {
ntpEthClient.update(); ntpEthClient.update();
uint64_t epochTime = ntpEthClient.getEpochTime(); uint64_t epochTime = ntpEthClient.getEpochTime();
@ -488,7 +496,7 @@ void sendAttributesMessage()
uint32_t mins = secs / 60; uint32_t mins = secs / 60;
uint32_t hours = mins / 60; uint32_t hours = mins / 60;
uint32_t days = hours / 24; uint32_t days = hours / 24;
StaticJsonDocument<sizeof(esp_now_payload_data_t::message)> json; DynamicJsonDocument json(sizeof(esp_now_payload_data_t::message));
json["Type"] = "ESP-NOW gateway"; json["Type"] = "ESP-NOW gateway";
#if defined(ESP8266) #if defined(ESP8266)
json["MCU"] = "ESP8266"; json["MCU"] = "ESP8266";
@ -499,32 +507,32 @@ void sendAttributesMessage()
json["MAC"] = myNet.getNodeMac(); json["MAC"] = myNet.getNodeMac();
json["Firmware"] = firmware; json["Firmware"] = firmware;
json["Library"] = myNet.getFirmwareVersion(); json["Library"] = myNet.getFirmwareVersion();
if (workMode == ESP_NOW_WIFI) if (config.workMode == ESP_NOW_WIFI)
json["IP"] = WiFi.localIP().toString(); json["IP"] = WiFi.localIP().toString();
if (workMode == ESP_NOW_LAN) if (config.workMode == ESP_NOW_LAN)
json["IP"] = Ethernet.localIP().toString(); json["IP"] = Ethernet.localIP().toString();
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));
char buffer[sizeof(esp_now_payload_data_t::message)]{0}; char buffer[sizeof(esp_now_payload_data_t::message)]{0};
serializeJsonPretty(json, buffer); serializeJsonPretty(json, buffer);
mqttPublish((topicPrefix + "/espnow_gateway/" + myNet.getNodeMac() + "/attributes").c_str(), buffer, true); mqttPublish((config.topicPrefix + "/espnow_gateway/" + myNet.getNodeMac() + "/attributes").c_str(), buffer, true);
} }
void sendConfigMessage() void sendConfigMessage()
{ {
StaticJsonDocument<1024> json; DynamicJsonDocument json(2048); // Same as PubSubClient buffer size.
json["platform"] = "mqtt"; json["platform"] = "mqtt";
json["name"] = deviceName; json["name"] = config.deviceName;
json["unique_id"] = myNet.getNodeMac() + "-1"; json["unique_id"] = myNet.getNodeMac() + "-1";
json["device_class"] = "connectivity"; json["device_class"] = "connectivity";
json["state_topic"] = topicPrefix + "/espnow_gateway/" + myNet.getNodeMac() + "/status"; json["state_topic"] = config.topicPrefix + "/espnow_gateway/" + myNet.getNodeMac() + "/status";
json["json_attributes_topic"] = topicPrefix + "/espnow_gateway/" + myNet.getNodeMac() + "/attributes"; json["json_attributes_topic"] = config.topicPrefix + "/espnow_gateway/" + myNet.getNodeMac() + "/attributes";
json["payload_on"] = "online"; json["payload_on"] = "online";
json["expire_after"] = 30; json["expire_after"] = 30;
json["force_update"] = "true"; json["force_update"] = "true";
json["retain"] = "true"; json["retain"] = "true";
char buffer[1024]{0}; char buffer[1024]{0};
serializeJsonPretty(json, buffer); serializeJsonPretty(json, buffer);
mqttPublish((topicPrefix + "/binary_sensor/" + myNet.getNodeMac() + "-1" + "/config").c_str(), buffer, true); mqttPublish((config.topicPrefix + "/binary_sensor/" + myNet.getNodeMac() + "-1" + "/config").c_str(), buffer, true);
} }
String getValue(String data, char separator, uint8_t index) String getValue(String data, char separator, uint8_t index)
@ -544,47 +552,27 @@ String getValue(String data, char separator, uint8_t index)
void loadConfig() void loadConfig()
{ {
if (!LittleFS.exists("/config.json")) EEPROM.begin(4096);
if (EEPROM.read(4095) == 254)
{
EEPROM.get(0, config);
EEPROM.end();
}
else
{
EEPROM.end();
saveConfig(); saveConfig();
File file = LittleFS.open("/config.json", "r"); }
String jsonFile = file.readString(); delay(50);
StaticJsonDocument<1024> json;
deserializeJson(json, jsonFile);
espnowNetName = json["espnowNetName"].as<String>();
deviceName = json["deviceName"].as<String>();
ssid = json["ssid"].as<String>();
password = json["password"].as<String>();
mqttHostName = json["mqttHostName"].as<String>();
mqttHostPort = json["mqttHostPort"];
mqttUserLogin = json["mqttUserLogin"].as<String>();
mqttUserPassword = json["mqttUserPassword"].as<String>();
topicPrefix = json["topicPrefix"].as<String>();
workMode = json["workMode"];
ntpHostName = json["ntpHostName"].as<String>();
gmtOffset = json["gmtOffset"];
file.close();
} }
void saveConfig() void saveConfig()
{ {
StaticJsonDocument<1024> json; EEPROM.begin(4096);
json["firmware"] = firmware; EEPROM.write(4095, 254);
json["espnowNetName"] = espnowNetName; EEPROM.put(0, config);
json["deviceName"] = deviceName; EEPROM.end();
json["ssid"] = ssid; delay(50);
json["password"] = password;
json["mqttHostName"] = mqttHostName;
json["mqttHostPort"] = mqttHostPort;
json["mqttUserLogin"] = mqttUserLogin;
json["mqttUserPassword"] = mqttUserPassword;
json["topicPrefix"] = topicPrefix;
json["workMode"] = workMode;
json["ntpHostName"] = ntpHostName;
json["gmtOffset"] = gmtOffset;
json["system"] = "empty";
File file = LittleFS.open("/config.json", "w");
serializeJsonPretty(json, file);
file.close();
} }
String xmlNode(String tags, String data) String xmlNode(String tags, String data)
@ -606,7 +594,7 @@ void setupWebServer()
ssdpHeader = xmlNode("specVersion", ssdpHeader); ssdpHeader = xmlNode("specVersion", ssdpHeader);
ssdpHeader += xmlNode("URLBase", "http://" + WiFi.localIP().toString()); ssdpHeader += xmlNode("URLBase", "http://" + WiFi.localIP().toString());
String ssdpDescription = xmlNode("deviceType", "upnp:rootdevice"); String ssdpDescription = xmlNode("deviceType", "upnp:rootdevice");
ssdpDescription += xmlNode("friendlyName", deviceName); ssdpDescription += xmlNode("friendlyName", config.deviceName);
ssdpDescription += xmlNode("presentationURL", "/"); ssdpDescription += xmlNode("presentationURL", "/");
ssdpDescription += xmlNode("serialNumber", "0000000" + String(random(1000))); ssdpDescription += xmlNode("serialNumber", "0000000" + String(random(1000)));
ssdpDescription += xmlNode("modelName", "ESP-NOW gateway"); ssdpDescription += xmlNode("modelName", "ESP-NOW gateway");
@ -624,38 +612,57 @@ void setupWebServer()
webServer.on("/", HTTP_GET, [](AsyncWebServerRequest *request) webServer.on("/", HTTP_GET, [](AsyncWebServerRequest *request)
{ request->send(LittleFS, "/index.htm"); }); { request->send(LittleFS, "/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)
{ {
ssid = request->getParam("ssid")->value(); config.ssid = request->getParam("ssid")->value();
password = request->getParam("password")->value(); config.password = request->getParam("password")->value();
mqttHostName = request->getParam("host")->value(); config.mqttHostName = request->getParam("mqttHostName")->value();
mqttHostPort = request->getParam("port")->value().toInt(); config.mqttHostPort = request->getParam("mqttHostPort")->value().toInt();
mqttUserLogin = request->getParam("login")->value(); config.mqttUserLogin = request->getParam("mqttUserLogin")->value();
mqttUserPassword = request->getParam("pass")->value(); config.mqttUserPassword = request->getParam("mqttUserPassword")->value();
topicPrefix = request->getParam("prefix")->value(); config.topicPrefix = request->getParam("topicPrefix")->value();
deviceName = request->getParam("name")->value(); config.deviceName = request->getParam("deviceName")->value();
espnowNetName = request->getParam("net")->value(); config.espnowNetName = request->getParam("espnowNetName")->value();
workMode = request->getParam("mode")->value().toInt(); config.workMode = request->getParam("workMode")->value().toInt();
ntpHostName = request->getParam("ntp")->value(); config.ntpHostName = request->getParam("ntpHostName")->value();
gmtOffset = request->getParam("zone")->value().toInt(); config.gmtOffset = request->getParam("gmtOffset")->value().toInt();
request->send(200); request->send(200);
saveConfig(); }); saveConfig(); });
webServer.on("/restart", HTTP_GET, [](AsyncWebServerRequest *request) webServer.on("/config", HTTP_GET, [](AsyncWebServerRequest *request)
{ {
request->send(200); String configJson;
DynamicJsonDocument json(2048); // For overflow protection.
json["firmware"] = firmware;
json["espnowNetName"] = config.espnowNetName;
json["deviceName"] = config.deviceName;
json["ssid"] = config.ssid;
json["password"] = config.password;
json["mqttHostName"] = config.mqttHostName;
json["mqttHostPort"] = config.mqttHostPort;
json["mqttUserLogin"] = config.mqttUserLogin;
json["mqttUserPassword"] = config.mqttUserPassword;
json["topicPrefix"] = config.topicPrefix;
json["workMode"] = config.workMode;
json["ntpHostName"] = config.ntpHostName;
json["gmtOffset"] = config.gmtOffset;
serializeJsonPretty(json, configJson);
request->send(200, "application/json", configJson); });
webServer.on("/restart", HTTP_GET, [](AsyncWebServerRequest *request)
{request->send(200);
ESP.restart(); }); ESP.restart(); });
webServer.onNotFound([](AsyncWebServerRequest *request) webServer.onNotFound([](AsyncWebServerRequest *request)
{ { request->send(404, "text/plain", "File Not Found"); });
if (LittleFS.exists(request->url()))
request->send(LittleFS, request->url());
else
{
request->send(404, "text/plain", "File Not Found");
} });
if (workMode == ESP_NOW_WIFI) if (config.workMode == ESP_NOW_WIFI)
SSDP.begin(); SSDP.begin();
webServer.begin(); webServer.begin();
@ -665,18 +672,18 @@ void checkMqttAvailability()
{ {
mqttAvailabilityCheckTimerSemaphore = false; mqttAvailabilityCheckTimerSemaphore = false;
if (workMode == ESP_NOW_WIFI) if (config.workMode == ESP_NOW_WIFI)
if (WiFi.isConnected()) if (WiFi.isConnected())
if (!mqttWifiClient.connected()) if (!mqttWifiClient.connected())
{ {
isMqttAvailable = false; isMqttAvailable = false;
if (mqttWifiClient.connect(mqttUserID, mqttUserLogin.c_str(), mqttUserPassword.c_str())) if (mqttWifiClient.connect(mqttUserID, config.mqttUserLogin.c_str(), config.mqttUserPassword.c_str()))
{ {
isMqttAvailable = true; isMqttAvailable = true;
mqttWifiClient.subscribe((topicPrefix + "/espnow_gateway/#").c_str()); mqttWifiClient.subscribe((config.topicPrefix + "/espnow_gateway/#").c_str());
mqttWifiClient.subscribe((topicPrefix + "/espnow_switch/#").c_str()); mqttWifiClient.subscribe((config.topicPrefix + "/espnow_switch/#").c_str());
mqttWifiClient.subscribe((topicPrefix + "/espnow_led/#").c_str()); mqttWifiClient.subscribe((config.topicPrefix + "/espnow_led/#").c_str());
sendConfigMessage(); sendConfigMessage();
sendAttributesMessage(); sendAttributesMessage();
@ -684,18 +691,18 @@ void checkMqttAvailability()
} }
} }
if (workMode == ESP_NOW_LAN) if (config.workMode == ESP_NOW_LAN)
if (Ethernet.linkStatus() == LinkON) if (Ethernet.linkStatus() == LinkON)
if (!mqttEthClient.connected()) if (!mqttEthClient.connected())
{ {
isMqttAvailable = false; isMqttAvailable = false;
if (mqttEthClient.connect(mqttUserID, mqttUserLogin.c_str(), mqttUserPassword.c_str())) if (mqttEthClient.connect(mqttUserID, config.mqttUserLogin.c_str(), config.mqttUserPassword.c_str()))
{ {
isMqttAvailable = true; isMqttAvailable = true;
mqttEthClient.subscribe((topicPrefix + "/espnow_gateway/#").c_str()); mqttEthClient.subscribe((config.topicPrefix + "/espnow_gateway/#").c_str());
mqttEthClient.subscribe((topicPrefix + "/espnow_switch/#").c_str()); mqttEthClient.subscribe((config.topicPrefix + "/espnow_switch/#").c_str());
mqttEthClient.subscribe((topicPrefix + "/espnow_led/#").c_str()); mqttEthClient.subscribe((config.topicPrefix + "/espnow_led/#").c_str());
sendConfigMessage(); sendConfigMessage();
sendAttributesMessage(); sendAttributesMessage();
@ -706,9 +713,9 @@ void checkMqttAvailability()
void mqttPublish(const char *topic, const char *payload, bool retained) void mqttPublish(const char *topic, const char *payload, bool retained)
{ {
if (workMode == ESP_NOW_WIFI) if (config.workMode == ESP_NOW_WIFI)
mqttWifiClient.publish(topic, payload, retained); mqttWifiClient.publish(topic, payload, retained);
if (workMode == ESP_NOW_LAN) if (config.workMode == ESP_NOW_LAN)
mqttEthClient.publish(topic, payload, retained); mqttEthClient.publish(topic, payload, retained);
} }