11 Commits
v1.01 ... v1.26

Author SHA1 Message Date
24ba0a09f4 Version 1.26
Changed FS from SPIFFS to LittleFS.
2023-02-04 10:52:52 +03:00
eebaca38b7 Minor changes 2023-01-28 14:07:38 +03:00
8e9082f05e Version 1.25
Fixed bug with ESP-NOW sensors not being added to HA via MQTT discovery.
2023-01-28 12:15:09 +03:00
1c306e031b Version 1.24
Added encrypting messages.
2023-01-22 12:46:58 +03:00
74c6279f50 Version 1.23
Added value template to config message.
2023-01-15 11:58:40 +03:00
8c3b51304e Version 1.22
Web interface minor redesign.
Main code minor changes.
2023-01-12 12:24:53 +03:00
7b60f9efb3 Readme update 2023-01-08 10:49:50 +03:00
06487167f4 Version 1.21
Fixed one minor bug.
2023-01-08 10:14:51 +03:00
219cf17855 Version 1.2
Fixed some minor bugs.
Added window/door sensor support.
2023-01-06 13:09:21 +03:00
3aca3b7bbd Minor changes 2023-01-05 12:34:42 +03:00
9a86f806e4 Version 1.1
To Do item 1 performed.
2023-01-04 14:02:05 +03:00
5 changed files with 179 additions and 59 deletions

View File

@ -4,41 +4,43 @@ Gateway for data exchange between ESP-NOW devices and MQTT broker via WiFi.
## Features ## Features
1. Creates an access point named "ESP-NOW Gateway XXXXXXXXXXXX" with password "12345678" (IP 192.168.4.1). 1. Creates an access point named "ESP-NOW gateway XXXXXXXXXXXX" with password "12345678" (IP 192.168.4.1).
2. Possibility a device search through the Windows Network Environment via SSDP. 2. Possibility a device search through the Windows Network Environment via SSDP.
3. Periodically transmission of system information to the MQTT broker (every 60 seconds) and availability status to the ESP-NOW network and to the MQTT broker (every 10 seconds). 3. Periodically transmission of system information to the MQTT broker (every 60 seconds) and availability status to the ESP-NOW network and to the MQTT broker (every 10 seconds).
4. Automatically adds gateway configuration to Home Assistan via MQTT discovery as a binary_sensor. 4. Automatically adds gateway configuration to Home Assistan via MQTT discovery as a binary_sensor.
5. Possibility firmware update over OTA. 5. Automatically adds supported ESP-NOW devices configurations to Home Assistan via MQTT discovery.
6. Web interface for settings. 6. Possibility firmware update over OTA.
7. Web interface for settings.
## Notes ## Notes
1. ESP-NOW mesh network based on the library [ZHNetwork](https://github.com/aZholtikov/ZHNetwork). 1. ESP-NOW mesh network based on the library [ZHNetwork](https://github.com/aZholtikov/ZHNetwork).
2. Regardless of the status of connections to WiFi or MQTT the device perform ESP-NOW node function. 2. Regardless of the status of connections to WiFi or MQTT the device perform ESP-NOW node function.
3. For restart the device (without using the Web interface and only if MQTT connection established) send an "restart" command to the device's root topic (example - "homeassistant/gateway/70039F44BEF7"). 3. For restart the device (without using the Web interface and only if MQTT connection established) send an "restart" command to the device's root topic (example - "homeassistant/espnow_gateway/70039F44BEF7").
## Attention ## Attention
1. ESP-NOW network name must be set same of all another ESP-NOW devices in network. 1. ESP-NOW network name must be set same of all another ESP-NOW devices in network.
2. Upload the "data" folder (with web interface) into the filesystem before flashing. 2. If encryption is used, the key must be set same of all another ESP-NOW devices in network.
3. WiFi router must be set on channel 1. 3. Upload the "data" folder (with web interface) into the filesystem before flashing.
4. WiFi router must be set on channel 1.
## Tested on ## Tested on
1. NodeMCU 1.0 (ESP-12E Module). Unstable work. 1. NodeMCU 1.0 (ESP-12E Module). ESP-NOW + WiFi mode. Unstable work.
2. AZ-Delivery ESP-32 Dev Kit C V4. Stable work. 2. AZ-Delivery ESP-32 Dev Kit C V4. ESP-NOW + WiFi mode. Stable work.
## Supported devices ## Supported devices
1. [RF - Gateway](https://github.com/aZholtikov/RF-Gateway) (coming soon) 1. [RF Gateway](https://github.com/aZholtikov/RF-Gateway) (coming soon)
2. [ESP-NOW Switch](https://github.com/aZholtikov/ESP-NOW-Switch) (coming soon) 2. [ESP-NOW Switch](https://github.com/aZholtikov/ESP-NOW-Switch)
3. [ESP-NOW Led Light/Strip](https://github.com/aZholtikov/ESP-NOW-Led-Light-Strip) (coming soon) 3. [ESP-NOW Light/Led Strip](https://github.com/aZholtikov/ESP-NOW-Light-Led-Strip)
4. [ESP-NOW Window/Door Sensor](https://github.com/aZholtikov/ESP-NOW-Window-Door-Sensor) (coming soon) 4. [ESP-NOW Window/Door Sensor](https://github.com/aZholtikov/ESP-NOW-Window-Door-Sensor)
5. [ESP-NOW Water Leakage Sensor](https://github.com/aZholtikov/ESP-NOW-Water-Leakage-Sensor) (coming soon) 5. [ESP-NOW Water Leakage Sensor](https://github.com/aZholtikov/ESP-NOW-Water-Leakage-Sensor)
## To Do ## To Do
- [ ] Automatically add ESP-NOW devices configurations to Home Assistan via MQTT discovery. - [X] Automatically add ESP-NOW devices configurations to Home Assistan via MQTT discovery.
- [ ] LAN connection support. - [ ] LAN connection support.
- [ ] nRF24 device support (in current time uses "RF Gateway"). - [ ] nRF24 device support (in current time uses "RF Gateway").
- [ ] BLE device support (for ESP32). - [ ] BLE device support (for ESP32).

View File

@ -31,20 +31,20 @@
<p class="text">WiFi settings</p> <p class="text">WiFi settings</p>
<div class="wrapper"> <div class="wrapper">
<input id="ssid" value="{{ssid}}" placeholder="SSID" label title="WiFi network name" /> <input class="text-inp" id="ssid" value="{{ssid}}" placeholder="SSID" label title="WiFi network name" />
<input id="password" value="{{password}}" onfocus="this.type='text'" type="password" placeholder="Password" <input id="password" value="{{password}}" onfocus="this.type='text'" type="password" placeholder="Password"
autocomplete="off" label title="WiFi password" /> autocomplete="off" label title="WiFi password" />
</div> </div>
<p class="text">MQTT settings</p> <p class="text">MQTT settings</p>
<div class="wrapper"> <div class="wrapper">
<input id="mqttHostName" value="{{mqttHostName}}" placeholder="URL or IP" label <input class="text-inp" id="mqttHostName" value="{{mqttHostName}}" placeholder="URL or IP" label
title="MQTT server URL or IP" /> title="MQTT server URL or IP" />
<input id="mqttHostPort" value="{{mqttHostPort}}" placeholder="Port" label title="MQTT server port" /> <input id="mqttHostPort" value="{{mqttHostPort}}" placeholder="Port" label title="MQTT server port" />
</div> </div>
<div class="wrapper"> <div class="wrapper">
<input id="mqttUserLogin" value="{{mqttUserLogin}}" placeholder="Login" label <input class="text-inp" id="mqttUserLogin" value="{{mqttUserLogin}}" placeholder="Login" label
title="MQTT server user login" /> title="MQTT server user login" />
<input id="mqttUserPassword" value="{{mqttUserPassword}}" onfocus="this.type='text'" type="password" <input id="mqttUserPassword" value="{{mqttUserPassword}}" onfocus="this.type='text'" type="password"
placeholder="Password" autocomplete="off" label title="MQTT server user password" /> placeholder="Password" autocomplete="off" label title="MQTT server user password" />

View File

@ -1,3 +1,7 @@
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);
@ -21,6 +25,21 @@ 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-inp {
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;
margin-left: 0;
} }
.wrapper { .wrapper {
@ -39,6 +58,7 @@ input {
color: rgb(0, 0, 0); color: rgb(0, 0, 0);
background: #a3e0f1; background: #a3e0f1;
transition: .5s; transition: .5s;
margin-left: 10px;
} }
input:hover { input:hover {
@ -51,6 +71,8 @@ input: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 {
@ -65,6 +87,10 @@ input:hover {
width: 100%; width: 100%;
} }
#espnowNetName {
margin-bottom: 10px;
}
.wrapper.wrapper--end { .wrapper.wrapper--end {
align-items: baseline; align-items: baseline;
} }

View File

@ -1,49 +1,53 @@
[env:esp8266] [env:ESP8266]
platform = espressif8266 platform = espressif8266
board = nodemcuv2 board = nodemcuv2
framework = arduino framework = arduino
board_build.filesystem = littlefs
lib_deps = lib_deps =
https://github.com/aZholtikov/ZHNetwork https://github.com/aZholtikov/ZHNetwork
https://github.com/aZholtikov/ZHConfig https://github.com/aZholtikov/ZHConfig
bblanchon/ArduinoJson@^6.19.4 https://github.com/aZholtikov/Async-Web-Server
me-no-dev/ESP Async WebServer@^1.2.3 https://github.com/bblanchon/ArduinoJson
marvinroger/AsyncMqttClient@^0.9.0 https://github.com/marvinroger/async-mqtt-client
[env:esp8266-ota] [env:ESP8266-OTA]
platform = espressif8266 platform = espressif8266
board = nodemcuv2 board = nodemcuv2
framework = arduino framework = arduino
board_build.filesystem = littlefs
upload_port = 192.168.1.113 upload_port = 192.168.1.113
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
bblanchon/ArduinoJson@^6.19.4 https://github.com/aZholtikov/Async-Web-Server
me-no-dev/ESP Async WebServer@^1.2.3 https://github.com/bblanchon/ArduinoJson
marvinroger/AsyncMqttClient@^0.9.0 https://github.com/marvinroger/async-mqtt-client
[env:esp32] [env:ESP32]
platform = espressif32 platform = espressif32
board = az-delivery-devkit-v4 board = az-delivery-devkit-v4
framework = arduino framework = arduino
board_build.filesystem = littlefs
lib_deps = lib_deps =
https://github.com/aZholtikov/ZHNetwork https://github.com/aZholtikov/ZHNetwork
https://github.com/aZholtikov/ZHConfig https://github.com/aZholtikov/ZHConfig
bblanchon/ArduinoJson@^6.19.4 https://github.com/aZholtikov/Async-Web-Server
me-no-dev/ESP Async WebServer@^1.2.3 https://github.com/bblanchon/ArduinoJson
marvinroger/AsyncMqttClient@^0.9.0 https://github.com/marvinroger/async-mqtt-client
luc-github/ESP32SSDP@^1.2.0 https://github.com/luc-github/ESP32SSDP
[env:esp32-ota] [env:ESP32-OTA]
platform = espressif32 platform = espressif32
board = az-delivery-devkit-v4 board = az-delivery-devkit-v4
framework = arduino framework = arduino
upload_port = 192.168.1.144 board_build.filesystem = littlefs
upload_port = 192.168.1.110
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
bblanchon/ArduinoJson@^6.19.4 https://github.com/aZholtikov/Async-Web-Server
me-no-dev/ESP Async WebServer@^1.2.3 https://github.com/bblanchon/ArduinoJson
marvinroger/AsyncMqttClient@^0.9.0 https://github.com/marvinroger/async-mqtt-client
luc-github/ESP32SSDP@^1.2.0 https://github.com/luc-github/ESP32SSDP

View File

@ -1,7 +1,8 @@
#include "ArduinoJson.h" #include "ArduinoJson.h"
#include "ArduinoOTA.h" #include "ArduinoOTA.h"
#include "ESPAsyncWebServer.h" #include "ESPAsyncWebServer.h" // https://github.com/aZholtikov/Async-Web-Server
#include "AsyncMQTTClient.h" #include "AsyncMQTTClient.h"
#include "LittleFS.h"
#include "Ticker.h" #include "Ticker.h"
#include "ZHNetwork.h" #include "ZHNetwork.h"
#include "ZHConfig.h" #include "ZHConfig.h"
@ -9,7 +10,6 @@
#include "ESP8266SSDP.h" #include "ESP8266SSDP.h"
#endif #endif
#if defined(ESP32) #if defined(ESP32)
#include "SPIFFS.h"
#include "ESP32SSDP.h" #include "ESP32SSDP.h"
#endif #endif
@ -34,11 +34,16 @@ void setupWebServer(void);
void connectToMqtt(void); void connectToMqtt(void);
const String firmware{"1.01"}; const String firmware{"1.26"};
String espnowNetName{"DEFAULT"}; String espnowNetName{"DEFAULT"};
String deviceName{"ESP-NOW gateway"}; #if defined(ESP8266)
String deviceName = "ESP-NOW gateway " + String(ESP.getChipId(), HEX);
#endif
#if defined(ESP32)
String deviceName = "ESP-NOW gateway " + String(ESP.getEfuseMac(), HEX);
#endif
String ssid{"SSID"}; String ssid{"SSID"};
String password{"PASSWORD"}; String password{"PASSWORD"};
@ -67,11 +72,12 @@ void attributesMessageTimerCallback(void);
void setup() void setup()
{ {
SPIFFS.begin(); LittleFS.begin();
loadConfig(); loadConfig();
WiFi.onEvent(onWifiEvent); WiFi.onEvent(onWifiEvent);
#if defined(ESP8266) #if defined(ESP8266)
WiFi.setSleepMode(WIFI_NONE_SLEEP); WiFi.setSleepMode(WIFI_NONE_SLEEP);
#endif #endif
@ -84,11 +90,18 @@ void setup()
WiFi.setAutoReconnect(true); WiFi.setAutoReconnect(true);
myNet.begin(espnowNetName.c_str(), true); myNet.begin(espnowNetName.c_str(), true);
// 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);
myNet.setOnUnicastReceivingCallback(onEspnowMessage); myNet.setOnUnicastReceivingCallback(onEspnowMessage);
WiFi.softAP(("ESP-NOW Gateway " + myNet.getNodeMac()).c_str(), "12345678"); #if defined(ESP8266)
WiFi.softAP(("ESP-NOW gateway " + String(ESP.getChipId(), HEX)).c_str(), "12345678");
#endif
#if defined(ESP32)
WiFi.softAP(("ESP-NOW gateway " + String(ESP.getEfuseMac(), HEX)).c_str(), "12345678");
#endif
uint8_t scan = WiFi.scanNetworks(false, false, 1); uint8_t scan = WiFi.scanNetworks(false, false, 1);
String name; String name;
int32_t rssi; int32_t rssi;
@ -157,6 +170,7 @@ void onEspnowMessage(const char *data, const uint8_t *sender)
if (incomingData.payloadsType == ENPT_STATE) if (incomingData.payloadsType == ENPT_STATE)
mqttClient.publish((topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/" + getValueName(incomingData.payloadsType)).c_str(), 2, true, incomingData.message); mqttClient.publish((topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/" + getValueName(incomingData.payloadsType)).c_str(), 2, true, incomingData.message);
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;
@ -164,26 +178,99 @@ void onEspnowMessage(const char *data, const uint8_t *sender)
StaticJsonDocument<sizeof(esp_now_payload_data_t::message)> json; StaticJsonDocument<sizeof(esp_now_payload_data_t::message)> json;
deserializeJson(json, configData.message); deserializeJson(json, configData.message);
uint8_t unit = json["unit"].as<uint8_t>(); uint8_t unit = json["unit"].as<uint8_t>();
String type = json["type"]; ha_component_type_t type = json["type"].as<ha_component_type_t>();
StaticJsonDocument<1024> jsonConfig; StaticJsonDocument<2048> jsonConfig;
jsonConfig["platform"] = "mqtt"; jsonConfig["platform"] = "mqtt";
jsonConfig["name"] = json["name"]; jsonConfig["name"] = json["name"];
jsonConfig["unique_id"] = myNet.macToString(sender) + "-" + unit; jsonConfig["unique_id"] = myNet.macToString(sender) + "-" + unit;
jsonConfig["device_class"] = json["class"]; jsonConfig["device_class"] = getValueName(json["class"].as<ha_switch_device_class_t>());
jsonConfig["state_topic"] = topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/state"; jsonConfig["state_topic"] = topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/state";
jsonConfig["value_template"] = "{{ value_json.state }}"; jsonConfig["value_template"] = "{{ value_json." + json["template"].as<String>() + " }}";
jsonConfig["command_topic"] = topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/set"; jsonConfig["command_topic"] = topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/set";
jsonConfig["json_attributes_topic"] = topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/attributes"; jsonConfig["json_attributes_topic"] = topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/attributes";
jsonConfig["availability_topic"] = topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/status"; jsonConfig["availability_topic"] = topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/status";
jsonConfig["payload_on"] = json["reverse"] == "true" ? "OFF" : "ON"; jsonConfig["payload_on"] = json["payload_on"];
jsonConfig["payload_off"] = json["reverse"] == "true" ? "ON" : "OFF"; jsonConfig["payload_off"] = json["payload_off"];
jsonConfig["optimistic"] = "false"; jsonConfig["optimistic"] = "false";
jsonConfig["qos"] = 2; jsonConfig["qos"] = 2;
jsonConfig["retain"] = "true"; jsonConfig["retain"] = "true";
char buffer[1024]{0}; char buffer[2048]{0};
serializeJsonPretty(jsonConfig, buffer); serializeJsonPretty(jsonConfig, buffer);
mqttClient.publish((topicPrefix + "/" + type + "/" + myNet.macToString(sender) + "-" + unit + "/config").c_str(), 2, true, buffer); mqttClient.publish((topicPrefix + "/" + getValueName(type) + "/" + myNet.macToString(sender) + "-" + unit + "/config").c_str(), 2, true, buffer);
} }
if (incomingData.deviceType == ENDT_LED)
{
esp_now_payload_data_t configData;
memcpy(&configData.message, &incomingData.message, sizeof(esp_now_payload_data_t::message));
StaticJsonDocument<sizeof(esp_now_payload_data_t::message)> json;
deserializeJson(json, configData.message);
uint8_t unit = json["unit"].as<uint8_t>();
ha_component_type_t type = json["type"].as<ha_component_type_t>();
esp_now_led_type_t ledClass = json["class"];
StaticJsonDocument<2048> jsonConfig;
jsonConfig["platform"] = "mqtt";
jsonConfig["name"] = json["name"];
jsonConfig["unique_id"] = myNet.macToString(sender) + "-" + unit;
jsonConfig["state_topic"] = topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/state";
jsonConfig["state_value_template"] = "{{ value_json.state }}";
jsonConfig["command_topic"] = topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/set";
jsonConfig["brightness_state_topic"] = topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/state";
jsonConfig["brightness_value_template"] = "{{ value_json.brightness }}";
jsonConfig["brightness_command_topic"] = topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/brightness";
if (ledClass == ENLT_RGB || ledClass == ENLT_RGBW || ledClass == ENLT_RGBWW)
{
jsonConfig["rgb_state_topic"] = topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/state";
jsonConfig["rgb_value_template"] = "{{ value_json.rgb | join(',') }}";
jsonConfig["rgb_command_topic"] = topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/rgb";
}
if (ledClass == ENLT_WW || ledClass == ENLT_RGBWW)
{
jsonConfig["color_temp_state_topic"] = topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/state";
jsonConfig["color_temp_value_template"] = "{{ value_json.temperature }}";
jsonConfig["color_temp_command_topic"] = topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/temperature";
}
jsonConfig["json_attributes_topic"] = topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/attributes";
jsonConfig["availability_topic"] = topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/status";
jsonConfig["payload_on"] = json["payload_on"];
jsonConfig["payload_off"] = json["payload_off"];
jsonConfig["optimistic"] = "false";
jsonConfig["qos"] = 2;
jsonConfig["retain"] = "true";
char buffer[2048]{0};
serializeJsonPretty(jsonConfig, buffer);
mqttClient.publish((topicPrefix + "/" + getValueName(type) + "/" + myNet.macToString(sender) + "-" + unit + "/config").c_str(), 2, true, buffer);
}
if (incomingData.deviceType == ENDT_SENSOR)
{
esp_now_payload_data_t configData;
memcpy(&configData.message, &incomingData.message, sizeof(esp_now_payload_data_t::message));
StaticJsonDocument<sizeof(esp_now_payload_data_t::message)> json;
deserializeJson(json, configData.message);
uint8_t unit = json["unit"].as<uint8_t>();
ha_component_type_t type = json["type"].as<ha_component_type_t>();
StaticJsonDocument<2048> jsonConfig;
jsonConfig["platform"] = "mqtt";
jsonConfig["name"] = json["name"];
jsonConfig["unique_id"] = myNet.macToString(sender) + "-" + unit;
jsonConfig["state_topic"] = topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/state";
jsonConfig["value_template"] = "{{ value_json." + json["template"].as<String>() + " }}";
jsonConfig["json_attributes_topic"] = topicPrefix + "/" + getValueName(incomingData.deviceType) + "/" + myNet.macToString(sender) + "/attributes";
jsonConfig["force_update"] = "true";
jsonConfig["qos"] = 2;
jsonConfig["retain"] = "true";
if (type == HACT_SENSOR)
jsonConfig["device_class"] = getValueName(json["class"].as<ha_sensor_device_class_t>());
if (type == HACT_BINARY_SENSOR)
{
jsonConfig["device_class"] = getValueName(json["class"].as<ha_binary_sensor_device_class_t>());
jsonConfig["payload_on"] = json["payload_on"];
jsonConfig["payload_off"] = json["payload_off"];
}
char buffer[2048]{0};
serializeJsonPretty(jsonConfig, buffer);
mqttClient.publish((topicPrefix + "/" + getValueName(type) + "/" + myNet.macToString(sender) + "-" + unit + "/config").c_str(), 2, true, buffer);
}
}
if (incomingData.payloadsType == ENPT_FORWARD) if (incomingData.payloadsType == ENPT_FORWARD)
{ {
esp_now_payload_data_t forwardData; esp_now_payload_data_t forwardData;
@ -251,7 +338,7 @@ void onMqttMessage(char *topic, char *payload, AsyncMqttClientMessageProperties
if (String(topic) == topicPrefix + "/espnow_switch/" + mac + "/set" || String(topic) == topicPrefix + "/espnow_led/" + mac + "/set") if (String(topic) == topicPrefix + "/espnow_switch/" + mac + "/set" || String(topic) == topicPrefix + "/espnow_led/" + mac + "/set")
{ {
flag = true; flag = true;
json["set"] = message == "ON" ? "ON" : "OFF"; json["set"] = message;
} }
if (String(topic) == topicPrefix + "/espnow_led/" + mac + "/brightness") if (String(topic) == topicPrefix + "/espnow_led/" + mac + "/brightness")
{ {
@ -295,6 +382,7 @@ void sendKeepAliveMessage()
outgoingData.payloadsType = ENPT_KEEP_ALIVE; outgoingData.payloadsType = ENPT_KEEP_ALIVE;
StaticJsonDocument<sizeof(esp_now_payload_data_t::message)> json; StaticJsonDocument<sizeof(esp_now_payload_data_t::message)> json;
json["MQTT"] = mqttClient.connected() ? "online" : "offline"; json["MQTT"] = mqttClient.connected() ? "online" : "offline";
json["frequency"] = 10; // For compatibility with the previous version. Will be removed in future releases.
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);
memcpy(&outgoingData.message, &buffer, sizeof(esp_now_payload_data_t::message)); memcpy(&outgoingData.message, &buffer, sizeof(esp_now_payload_data_t::message));
@ -311,7 +399,7 @@ void sendAttributesMessage()
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; StaticJsonDocument<sizeof(esp_now_payload_data_t::message)> json;
json["Type"] = "ESP-NOW Gateway"; json["Type"] = "ESP-NOW gateway";
#if defined(ESP8266) #if defined(ESP8266)
json["MCU"] = "ESP8266"; json["MCU"] = "ESP8266";
#endif #endif
@ -345,9 +433,9 @@ String getValue(String data, char separator, uint8_t index)
void loadConfig() void loadConfig()
{ {
if (!SPIFFS.exists("/config.json")) if (!LittleFS.exists("/config.json"))
saveConfig(); saveConfig();
File file = SPIFFS.open("/config.json", "r"); File file = LittleFS.open("/config.json", "r");
String jsonFile = file.readString(); String jsonFile = file.readString();
StaticJsonDocument<1024> json; StaticJsonDocument<1024> json;
deserializeJson(json, jsonFile); deserializeJson(json, jsonFile);
@ -377,7 +465,7 @@ void saveConfig()
json["mqttUserPassword"] = mqttUserPassword; json["mqttUserPassword"] = mqttUserPassword;
json["topicPrefix"] = topicPrefix; json["topicPrefix"] = topicPrefix;
json["system"] = "empty"; json["system"] = "empty";
File file = SPIFFS.open("/config.json", "w"); File file = LittleFS.open("/config.json", "w");
serializeJsonPretty(json, file); serializeJsonPretty(json, file);
file.close(); file.close();
} }
@ -404,7 +492,7 @@ void setupWebServer()
ssdpDescription += xmlNode("friendlyName", deviceName); ssdpDescription += xmlNode("friendlyName", 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");
ssdpDescription += xmlNode("modelNumber", firmware); ssdpDescription += xmlNode("modelNumber", firmware);
ssdpDescription += xmlNode("modelURL", "https://github.com/aZholtikov/ESP-NOW-Gateway"); ssdpDescription += xmlNode("modelURL", "https://github.com/aZholtikov/ESP-NOW-Gateway");
ssdpDescription += xmlNode("manufacturer", "Alexey Zholtikov"); ssdpDescription += xmlNode("manufacturer", "Alexey Zholtikov");
@ -417,7 +505,7 @@ void setupWebServer()
request->send(200, "text/xml", ssdpSend); }); request->send(200, "text/xml", ssdpSend); });
webServer.on("/", HTTP_GET, [](AsyncWebServerRequest *request) webServer.on("/", HTTP_GET, [](AsyncWebServerRequest *request)
{ request->send(SPIFFS, "/index.htm"); }); { request->send(LittleFS, "/index.htm"); });
webServer.on("/setting", HTTP_GET, [](AsyncWebServerRequest *request) webServer.on("/setting", HTTP_GET, [](AsyncWebServerRequest *request)
{ {
@ -440,8 +528,8 @@ void setupWebServer()
webServer.onNotFound([](AsyncWebServerRequest *request) webServer.onNotFound([](AsyncWebServerRequest *request)
{ {
if (SPIFFS.exists(request->url())) if (LittleFS.exists(request->url()))
request->send(SPIFFS, request->url()); request->send(LittleFS, request->url());
else else
{ {
request->send(404, "text/plain", "File Not Found"); request->send(404, "text/plain", "File Not Found");