Compare commits

...

29 Commits
v1.0 ... main

Author SHA1 Message Date
90133a7d67 Version 1.42
Fixed some bugs.
2023-03-15 16:37:19 +03:00
dd3cbb9633 Fixed one bug 2023-03-12 12:49:50 +03:00
0b64933ee7 Minor changes 2023-03-07 11:58:03 +03:00
1d8d8e3f7d Fixed one bug 2023-03-06 00:43:29 +03:00
Alexey Zholtikov
ceb80d8bd7 Minor changes 2023-03-04 13:28:32 +03:00
Alexey Zholtikov
53464acb22 Minor changes 2023-03-04 12:41:59 +03:00
Alexey Zholtikov
af8cc16675 Minor changes 2023-03-04 12:36:37 +03:00
Alexey Zholtikov
c248a08efe Version 1.41
Changed config data storage location to EEPROM.
2023-03-04 11:16:55 +03:00
651ade7334 Fixed one bug 2023-02-26 14:21:47 +03:00
98a082dd67 Version 1.4
Minimized of config message size.
Changed SDK version for 3.0.5
2023-02-26 11:13:18 +03:00
1aa5465687 Fixed one small bug 2023-02-19 12:30:38 +03:00
71ec165aca Version 1.32
Minor changes.
2023-02-19 12:23:25 +03:00
d1ddd9ecbb Minor changes 2023-02-19 11:03:13 +03:00
5d023b13c1 Minor changes 2023-02-19 09:59:58 +03:00
551866b040 Version 1.31
Fixed one minor bug.
2023-02-18 10:07:15 +03:00
b940f325f2 Minor changes 2023-02-17 17:01:52 +03:00
0b603489fd Version 1.3
Added relay work modes.
2023-02-17 09:28:23 +03:00
dc17e39ff6 Version 1.21
Minor changes.
2023-02-12 18:33:42 +03:00
e1d74e98eb Minor changes 2023-02-11 08:41:56 +03:00
4ece7281d3 Minor changes 2023-02-09 21:30:13 +03:00
4bf392c380 Version 1.2
Updated "Tested on".
Changed FS from SPIFFS to LittleFS.
Added support one external sensor.
2023-02-05 13:11:31 +03:00
ac58f4dc00 Updated "Tested on" 2023-01-25 22:00:39 +03:00
3953473ea8 Minor changes 2023-01-24 19:40:00 +03:00
619b3a6cdf Version 1.14
Added encrypting messages.
2023-01-22 12:22:34 +03:00
ef625740d9 Version 1.13
Added value template to config message.
2023-01-15 11:47:04 +03:00
549d9cf916 Version 1.12
Main code refactoring.
2023-01-14 11:16:48 +03:00
82e736dc8b Version 1.11
Web interface minor redesign.
Main code minor changes.
2023-01-12 12:30:16 +03:00
439722511f Updated "Tested on" 2023-01-10 11:32:08 +03:00
5d9784c9ae Version 1.1
Fixed one minor bug.
2023-01-06 13:00:46 +03:00
32 changed files with 455 additions and 195 deletions

View File

@ -1,15 +1,17 @@
# ESP-NOW switch for ESP8266 # ESP-NOW switch for ESP8266
ESP-NOW based switch for ESP8266. Alternate firmware for Tuya/SmartLife WiFi switches. ESP-NOW based switch for ESP8266. Alternate firmware for Tuya/SmartLife/eWeLink WiFi switches.
## Features ## Features
1. After turn on (or after rebooting) creates an access point named "ESP-NOW Switch 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 switch 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 switch configuration to Home Assistan via MQTT discovery as a switch. 4. Automatically adds switch configuration to Home Assistan via MQTT discovery as a switch.
5. Possibility firmware update over OTA (if is allows the size of the flash memory). 5. Possibility firmware update over OTA (if is allows the size of the flash memory).
6. Web interface for settings. 6. Web interface for settings.
7. Optionally support one external one wire digital climate sensor (DS18B20, DHT11 or DHT22) with automatically added sensor configuration to Home Assistan via MQTT discovery as a sensor. Periodically transmission sensor status (every 300 seconds) to the gateway.
8. Normal or reverse relay mode (normal by default).
## Notes ## Notes
@ -19,11 +21,14 @@ ESP-NOW based switch for ESP8266. Alternate firmware for Tuya/SmartLife WiFi swi
## Tested on ## Tested on
Coming soon. See [here](https://github.com/aZholtikov/ESP-NOW-Switch/tree/main/hardware).
## 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. Upload the "data" folder (with web interface) into the filesystem before flashing. 3. If encryption is used, the key must be set same of all another ESP-NOW devices in network.
4. For using this firmware on Tuya/SmartLife WiFi switches, the WiFi module must be replaced with an ESP8266 compatible module (if necessary). 4. Upload the "data" folder (with web interface) into the filesystem before flashing.
5. For using this firmware on Tuya/SmartLife/eWeLink WiFi switches, 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('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);
@ -29,6 +29,7 @@ function loadBlock() {
} }
document.getElementsByTagName('body')[0].innerHTML = newString; document.getElementsByTagName('body')[0].innerHTML = newString;
setFirmvareValue('version', 'firmware'); setFirmvareValue('version', 'firmware');
setGpioValue('workModeSelect', 'workMode');
setGpioValue('relayPinSelect', 'relayPin'); setGpioValue('relayPinSelect', 'relayPin');
setGpioValue('relayPinTypeSelect', 'relayPinType'); setGpioValue('relayPinTypeSelect', 'relayPinType');
setGpioValue('ledPinSelect', 'ledPin'); setGpioValue('ledPinSelect', 'ledPin');
@ -37,6 +38,8 @@ function loadBlock() {
setGpioValue('buttonPinTypeSelect', 'buttonPinType'); setGpioValue('buttonPinTypeSelect', 'buttonPinType');
setGpioValue('extButtonPinSelect', 'extButtonPin'); setGpioValue('extButtonPinSelect', 'extButtonPin');
setGpioValue('extButtonPinTypeSelect', 'extButtonPinType'); setGpioValue('extButtonPinTypeSelect', 'extButtonPinType');
setGpioValue('sensorPinSelect', 'sensorPin');
setGpioValue('sensorTypeSelect', 'sensorType');
handleServerResponse(); handleServerResponse();
} }
@ -67,7 +70,10 @@ function saveSetting(submit) {
+ "&buttonPin=" + getSelectValue('buttonPinSelect') + "&buttonPin=" + getSelectValue('buttonPinSelect')
+ "&buttonPinType=" + getSelectValue('buttonPinTypeSelect') + "&buttonPinType=" + getSelectValue('buttonPinTypeSelect')
+ "&extButtonPin=" + getSelectValue('extButtonPinSelect') + "&extButtonPin=" + getSelectValue('extButtonPinSelect')
+ "&extButtonPinType=" + getSelectValue('extButtonPinTypeSelect'); + "&extButtonPinType=" + getSelectValue('extButtonPinTypeSelect')
+ "&sensorPin=" + getSelectValue('sensorPinSelect')
+ "&sensorType=" + getSelectValue('sensorTypeSelect')
+ "&workMode=" + getSelectValue('workModeSelect');
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 Switch </h1> <h1>ESP-NOW Switch</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>
@ -29,6 +29,15 @@
title="ESP-NOW network name (1 to 20 characters)" /> title="ESP-NOW network name (1 to 20 characters)" />
</div> </div>
<div class="wrapper">
<p class="text-select">Work mode:</p>
<input id="workMode" value="{{workMode}}" hidden />
<p><select id="workModeSelect">
<option value="0">NORMAL</option>
<option value="1">REVERSE</option>
</select></p>
</div>
<div class="wrapper"> <div class="wrapper">
<p class="text-select">Relay GPIO:</p> <p class="text-select">Relay GPIO:</p>
<input id="relayPin" value="{{relayPin}}" hidden /> <input id="relayPin" value="{{relayPin}}" hidden />
@ -145,6 +154,37 @@
</select></p> </select></p>
</div> </div>
<div class="wrapper">
<p class="text-select">Ext sensor GPIO:</p>
<input id="sensorPin" value="{{sensorPin}}" hidden />
<input id="sensorType" value="{{sensorType}}" hidden />
<p><select id="sensorPinSelect">
<option value="0">NONE</option>
<option value="1">GPIO01</option>
<option value="2">GPIO02</option>
<option value="3">GPIO03</option>
<option value="4">GPIO04</option>
<option value="5">GPIO05</option>
<option value="6">GPIO06</option>
<option value="7">GPIO07</option>
<option value="8">GPIO08</option>
<option value="9">GPIO09</option>
<option value="10">GPIO10</option>
<option value="11">GPIO11</option>
<option value="12">GPIO12</option>
<option value="13">GPIO13</option>
<option value="14">GPIO14</option>
<option value="15">GPIO15</option>
<option value="16">GPIO16</option>
</select></p>
<p><select id="sensorTypeSelect">
<option value="0">NONE</option>
<option value="1">DS18B20</option>
<option value="2">DHT11</option>
<option value="3">DHT22</option>
</select></p>
</div>
<div class="wrapper"> <div class="wrapper">
<input class="btn" type="submit" value="Save" onclick="saveSetting(this);"> <input class="btn" type="submit" value="Save" onclick="saveSetting(this);">
<input class="btn" type="submit" value="Restart" onclick="restart(this);"> <input class="btn" type="submit" value="Restart" onclick="restart(this);">

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,8 @@ 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 {
@ -42,6 +48,7 @@ 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;
@ -76,6 +83,8 @@ 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 {
@ -89,6 +98,10 @@ 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.

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

28
hardware/README.md Normal file
View File

@ -0,0 +1,28 @@
# Tested on
1. MOES 1CH 10A. Built on Tuya WiFi module WA2 (WB2S) (BK7231T chip). Replacement required. Performed replacement with ESP-02S (analogue of TYWE2S but with 2Mb flash). [Photo](https://github.com/aZholtikov/ESP-NOW-Switch/tree/main/hardware/MOES_1CH_10A).
```text
Relay GPIO GPIO12 HIGH
Led GPIO GPIO04 LOW
Button GPIO GPIO13 RISING
```
2. MINI 1CH 16A. Built on Tuya WiFi module WB2S (BK7231T chip). Replacement required. Performed replacement with ESP-02S (analogue of TYWE2S but with 2Mb flash). [Photo](https://github.com/aZholtikov/ESP-NOW-Switch/tree/main/hardware/MINI_1CH_16A).
```text
Relay GPIO GPIO13 HIGH
Led GPIO GPIO04 LOW
Button GPIO GPIO03 RISING
Ext button GPIO GPIO14 FALLING
```
3. TH 1CH 16A + SENSOR. Built on ITEAD WiFi module PSF-B85 (ESP8285 chip). Replacement not required. [Photo](https://github.com/aZholtikov/ESP-NOW-Switch/tree/main/hardware/TH_1CH_16A). Attention! Because the button is connected to GPIO00 and the firmware does not work with GPIO00 required connect GPIO00 to GPIO04 on the module.
```text
Relay GPIO GPIO12 HIGH
Button GPIO GPIO04 RISING
Ext sensor GPIO GPIO14 DS18B20
```
4. LIGHT E27 SOCKET (Coming soon)

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 987 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 MiB

View File

@ -1,47 +1,78 @@
[env:esp8266] [env:ESP-12E]
platform = espressif8266 platform = espressif8266
board = esp12e board = esp12e
framework = arduino framework = arduino
lib_extra_dirs = 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
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
https://github.com/milesburton/Arduino-Temperature-Control-Library
https://github.com/beegee-tokyo/DHTesp
[env:esp8266-ota] [env:ESP-12E-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_extra_dirs =
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
https://github.com/milesburton/Arduino-Temperature-Control-Library
https://github.com/beegee-tokyo/DHTesp
[env:esp8285] [env:ESP-02S]
platform = espressif8266 platform = espressif8266
board = esp8285 board = esp8285
framework = arduino framework = arduino
lib_extra_dirs = build_flags = -D PIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK305
board_build.filesystem = littlefs
board_build.ldscript = eagle.flash.2m64.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
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
https://github.com/milesburton/Arduino-Temperature-Control-Library
https://github.com/beegee-tokyo/DHTesp
[env:esp8285-ota] [env:ESP-02S-OTA]
platform = espressif8266 platform = espressif8266
board = esp8285 board = esp8285
framework = arduino framework = arduino
build_flags = -D PIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK305
board_build.filesystem = littlefs
board_build.ldscript = eagle.flash.2m64.ld
upload_port = 192.168.4.1 upload_port = 192.168.4.1
upload_protocol = espota upload_protocol = espota
lib_extra_dirs =
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
https://github.com/milesburton/Arduino-Temperature-Control-Library
https://github.com/beegee-tokyo/DHTesp
[env:PSF-B85]
platform = espressif8266
board = esp8285
framework = arduino
build_flags = -D PIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK305
board_build.filesystem = littlefs
board_build.ldscript = eagle.flash.1m64.ld
lib_deps =
https://github.com/aZholtikov/ZHNetwork
https://github.com/aZholtikov/ZHConfig
https://github.com/aZholtikov/Async-Web-Server
https://github.com/bblanchon/ArduinoJson
https://github.com/milesburton/Arduino-Temperature-Control-Library
https://github.com/beegee-tokyo/DHTesp

View File

@ -1,41 +1,60 @@
#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 "LittleFS.h"
#include "EEPROM.h"
#include "Ticker.h" #include "Ticker.h"
#include "DallasTemperature.h"
#include "DHTesp.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 bool status); void onConfirmReceiving(const uint8_t *target, const uint16_t id, 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 buttonInterrupt(void); void buttonInterrupt(void);
void switchingRelay(void); void switchingRelay(void);
void sendAttributesMessage(void); void sendAttributesMessage(const uint8_t type = ENST_NONE);
void sendKeepAliveMessage(void); void sendKeepAliveMessage(void);
void sendConfigMessage(void); void sendConfigMessage(const uint8_t type = ENST_NONE);
void sendStatusMessage(void); void sendStatusMessage(const uint8_t type = ENST_NONE);
const String firmware{"1.0"}; typedef struct
{
uint16_t id{0};
char message[200]{0};
} espnow_message_t;
String espnowNetName{"DEFAULT"}; struct deviceConfig
{
String espnowNetName{"DEFAULT"};
uint8_t workMode{0};
String deviceName = "ESP-NOW switch " + String(ESP.getChipId(), HEX);
uint8_t relayPin{0};
uint8_t relayPinType{1};
uint8_t buttonPin{0};
uint8_t buttonPinType{0};
uint8_t extButtonPin{0};
uint8_t extButtonPinType{0};
uint8_t ledPin{0};
uint8_t ledPinType{0};
uint8_t sensorPin{0};
uint8_t sensorType{0};
} config;
String deviceName{"ESP-NOW switch"}; std::vector<espnow_message_t> espnowMessage;
const String firmware{"1.42"};
bool relayStatus{false}; bool relayStatus{false};
uint8_t relayPin{0};
uint8_t relayPinType{1};
uint8_t buttonPin{0};
uint8_t buttonPinType{0};
uint8_t extButtonPin{0};
uint8_t extButtonPinType{0};
uint8_t ledPin{0};
uint8_t ledPinType{0};
bool wasMqttAvailable{false}; bool wasMqttAvailable{false};
@ -44,6 +63,11 @@ uint8_t gatewayMAC[6]{0};
ZHNetwork myNet; ZHNetwork myNet;
AsyncWebServer webServer(80); AsyncWebServer webServer(80);
OneWire oneWire;
DallasTemperature ds18b20(&oneWire);
DHTesp dht;
Ticker buttonInterruptTimer; Ticker buttonInterruptTimer;
Ticker gatewayAvailabilityCheckTimer; Ticker gatewayAvailabilityCheckTimer;
@ -56,54 +80,57 @@ 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()
{ {
SPIFFS.begin(); LittleFS.begin();
loadConfig(); loadConfig();
loadStatus();
if (relayPin) if (config.sensorPin)
{ {
pinMode(relayPin, OUTPUT); if (config.sensorType == ENST_DS18B20)
digitalWrite(relayPin, relayPinType ? relayStatus : !relayStatus); oneWire.begin(config.sensorPin);
if (config.sensorType == ENST_DHT11 || config.sensorType == ENST_DHT22)
dht.setup(config.sensorPin, DHTesp::AUTO_DETECT);
} }
if (ledPin) if (config.relayPin)
{ {
pinMode(ledPin, OUTPUT); pinMode(config.relayPin, OUTPUT);
digitalWrite(ledPin, ledPinType ? relayStatus : !relayStatus); if (config.workMode)
digitalWrite(config.relayPin, config.relayPinType ? !relayStatus : relayStatus);
else
digitalWrite(config.relayPin, config.relayPinType ? relayStatus : !relayStatus);
} }
if (buttonPin) if (config.ledPin)
attachInterrupt(buttonPin, buttonInterrupt, buttonPinType ? RISING : FALLING); {
if (extButtonPin) pinMode(config.ledPin, OUTPUT);
attachInterrupt(extButtonPin, buttonInterrupt, extButtonPinType ? RISING : FALLING); digitalWrite(config.ledPin, config.ledPinType ? relayStatus : !relayStatus);
}
if (config.buttonPin)
attachInterrupt(config.buttonPin, buttonInterrupt, config.buttonPinType ? RISING : FALLING);
if (config.extButtonPin)
attachInterrupt(config.extButtonPin, buttonInterrupt, config.extButtonPinType ? RISING : FALLING);
WiFi.setSleepMode(WIFI_NONE_SLEEP); WiFi.setSleepMode(WIFI_NONE_SLEEP);
myNet.begin(espnowNetName.c_str()); myNet.begin(config.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 Switch " + myNet.getNodeMac()).c_str(), "12345678", 1, 0); WiFi.softAP(("ESP-NOW switch " + String(ESP.getChipId(), HEX)).c_str(), "12345678", 1, 0);
apModeHideTimer.once(300, apModeHideTimerCallback); apModeHideTimer.once(300, apModeHideTimerCallback);
setupWebServer(); setupWebServer();
@ -118,11 +145,19 @@ void setup()
void loop() void loop()
{ {
if (attributesMessageTimerSemaphore) if (attributesMessageTimerSemaphore)
{
sendAttributesMessage(); sendAttributesMessage();
if (config.sensorPin)
sendAttributesMessage(config.sensorType);
}
if (keepAliveMessageTimerSemaphore) if (keepAliveMessageTimerSemaphore)
sendKeepAliveMessage(); sendKeepAliveMessage();
if (statusMessageTimerSemaphore) if (statusMessageTimerSemaphore)
{
sendStatusMessage(); sendStatusMessage();
if (config.sensorPin)
sendStatusMessage(config.sensorType);
}
myNet.maintenance(); myNet.maintenance();
ArduinoOTA.handle(); ArduinoOTA.handle();
} }
@ -134,18 +169,28 @@ void onBroadcastReceiving(const char *data, const uint8_t *sender)
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;
StaticJsonDocument<sizeof(esp_now_payload_data_t::message)> json; DynamicJsonDocument json(sizeof(esp_now_payload_data_t::message));
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();
if (config.sensorPin)
sendConfigMessage(config.sensorType);
sendAttributesMessage();
if (config.sensorPin)
sendAttributesMessage(config.sensorType);
sendStatusMessage();
if (config.sensorPin)
sendStatusMessage(config.sensorType);
}
} }
gatewayAvailabilityCheckTimer.once(15, gatewayAvailabilityCheckTimerCallback); gatewayAvailabilityCheckTimer.once(15, gatewayAvailabilityCheckTimerCallback);
} }
@ -157,130 +202,169 @@ void onUnicastReceiving(const char *data, const uint8_t *sender)
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;
StaticJsonDocument<sizeof(esp_now_payload_data_t::message)> json; DynamicJsonDocument json(sizeof(esp_now_payload_data_t::message));
if (incomingData.payloadsType == ENPT_SET) if (incomingData.payloadsType == ENPT_SET)
{ {
deserializeJson(json, incomingData.message); deserializeJson(json, incomingData.message);
relayStatus = json["set"] == "ON" ? true : false; relayStatus = json["set"] == "ON" ? true : false;
if (relayPin) if (config.relayPin)
digitalWrite(relayPin, relayPinType ? relayStatus : !relayStatus); {
if (ledPin) if (config.workMode)
digitalWrite(ledPin, ledPinType ? relayStatus : !relayStatus); digitalWrite(config.relayPin, config.relayPinType ? !relayStatus : relayStatus);
saveConfig(); else
digitalWrite(config.relayPin, config.relayPinType ? relayStatus : !relayStatus);
}
if (config.ledPin)
{
if (config.workMode)
digitalWrite(config.ledPin, config.ledPinType ? !relayStatus : relayStatus);
else
digitalWrite(config.ledPin, config.ledPinType ? relayStatus : !relayStatus);
}
saveStatus();
sendStatusMessage(); sendStatusMessage();
} }
if (incomingData.payloadsType == ENPT_UPDATE) if (incomingData.payloadsType == ENPT_UPDATE)
{ {
WiFi.softAP(("ESP-NOW Switch " + myNet.getNodeMac()).c_str(), "12345678", 1, 0); WiFi.softAP(("ESP-NOW switch " + String(ESP.getChipId(), HEX)).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 bool status) void onConfirmReceiving(const uint8_t *target, const uint16_t id, const bool status)
{ {
for (uint16_t i{0}; i < espnowMessage.size(); ++i)
{
espnow_message_t message = espnowMessage[i];
if (message.id == id)
{
if (status) if (status)
espnowMessage.erase(espnowMessage.begin() + i);
else
{ {
if (attributesMessageResendTimerSemaphore) message.id = myNet.sendUnicastMessage(message.message, gatewayMAC, true);
{ espnowMessage.at(i) = message;
attributesMessageResendTimerSemaphore = false;
attributesMessageResendTimer.detach();
} }
if (keepAliveMessageResendTimerSemaphore)
{
keepAliveMessageResendTimerSemaphore = false;
keepAliveMessageResendTimer.detach();
}
if (configMessageResendTimerSemaphore)
{
configMessageResendTimerSemaphore = false;
configMessageResendTimer.detach();
}
if (statusMessageResendTimerSemaphore)
{
statusMessageResendTimerSemaphore = false;
statusMessageResendTimer.detach();
} }
} }
} }
void loadConfig() void loadConfig()
{ {
if (!SPIFFS.exists("/config.json")) ETS_GPIO_INTR_DISABLE();
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"); }
String jsonFile = file.readString(); delay(50);
StaticJsonDocument<512> json; ETS_GPIO_INTR_ENABLE();
deserializeJson(json, jsonFile);
espnowNetName = json["espnowNetName"].as<String>();
deviceName = json["deviceName"].as<String>();
relayStatus = json["relayStatus"];
relayPin = json["relayPin"];
relayPinType = json["relayPinType"];
buttonPin = json["buttonPin"];
buttonPinType = json["buttonPinType"];
extButtonPin = json["extButtonPin"];
extButtonPinType = json["extButtonPinType"];
ledPin = json["ledPin"];
ledPinType = json["ledPinType"];
file.close();
} }
void saveConfig() void saveConfig()
{ {
StaticJsonDocument<512> json; ETS_GPIO_INTR_DISABLE();
json["firmware"] = firmware; EEPROM.begin(4096);
json["espnowNetName"] = espnowNetName; EEPROM.write(4095, 254);
json["deviceName"] = deviceName; EEPROM.put(0, config);
json["relayStatus"] = relayStatus; EEPROM.end();
json["relayPin"] = relayPin; delay(50);
json["relayPinType"] = relayPinType; ETS_GPIO_INTR_ENABLE();
json["buttonPin"] = buttonPin; }
json["buttonPinType"] = buttonPinType;
json["extButtonPin"] = extButtonPin; void loadStatus(void)
json["extButtonPinType"] = extButtonPinType; {
json["ledPin"] = ledPin; ETS_GPIO_INTR_DISABLE();
json["ledPinType"] = ledPinType; if (!LittleFS.exists("/status.json"))
saveStatus();
File file = LittleFS.open("/status.json", "r");
String jsonFile = file.readString();
DynamicJsonDocument json(64); // To calculate the buffer size uses https://arduinojson.org/v6/assistant.
deserializeJson(json, jsonFile);
relayStatus = json["status"];
file.close();
delay(50);
ETS_GPIO_INTR_ENABLE();
}
void saveStatus(void)
{
ETS_GPIO_INTR_DISABLE();
DynamicJsonDocument json(48); // To calculate the buffer size uses https://arduinojson.org/v6/assistant.
json["status"] = relayStatus;
json["system"] = "empty"; json["system"] = "empty";
File file = SPIFFS.open("/config.json", "w"); File file = LittleFS.open("/status.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(SPIFFS, "/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)
{ {
relayPin = request->getParam("relayPin")->value().toInt(); config.relayPin = request->getParam("relayPin")->value().toInt();
relayPinType = request->getParam("relayPinType")->value().toInt(); config.relayPinType = request->getParam("relayPinType")->value().toInt();
buttonPin = request->getParam("buttonPin")->value().toInt(); config.buttonPin = request->getParam("buttonPin")->value().toInt();
buttonPinType = request->getParam("buttonPinType")->value().toInt(); config.buttonPinType = request->getParam("buttonPinType")->value().toInt();
extButtonPin = request->getParam("extButtonPin")->value().toInt(); config.extButtonPin = request->getParam("extButtonPin")->value().toInt();
extButtonPinType = request->getParam("extButtonPinType")->value().toInt(); config.extButtonPinType = request->getParam("extButtonPinType")->value().toInt();
ledPin = request->getParam("ledPin")->value().toInt(); config.ledPin = request->getParam("ledPin")->value().toInt();
ledPinType = request->getParam("ledPinType")->value().toInt(); config.ledPinType = request->getParam("ledPinType")->value().toInt();
deviceName = request->getParam("deviceName")->value(); config.sensorPin = request->getParam("sensorPin")->value().toInt();
espnowNetName = request->getParam("espnowNetName")->value(); config.sensorType = request->getParam("sensorType")->value().toInt();
config.workMode = request->getParam("workMode")->value().toInt();
config.deviceName = request->getParam("deviceName")->value();
config.espnowNetName = request->getParam("espnowNetName")->value();
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(384); // To calculate the buffer size uses https://arduinojson.org/v6/assistant.
json["firmware"] = firmware;
json["espnowNetName"] = config.espnowNetName;
json["deviceName"] = config.deviceName;
json["relayPin"] = config.relayPin;
json["relayPinType"] = config.relayPinType;
json["buttonPin"] = config.buttonPin;
json["buttonPinType"] = config.buttonPinType;
json["extButtonPin"] = config.extButtonPin;
json["extButtonPinType"] = config.extButtonPinType;
json["ledPin"] = config.ledPin;
json["ledPinType"] = config.ledPinType;
json["sensorPin"] = config.sensorPin;
json["sensorType"] = config.sensorType;
json["workMode"] = config.workMode;
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 (SPIFFS.exists(request->url()))
request->send(SPIFFS, request->url());
else
{
request->send(404, "text/plain", "File Not Found");
} });
webServer.begin(); webServer.begin();
} }
@ -288,22 +372,32 @@ void setupWebServer()
void IRAM_ATTR buttonInterrupt() void IRAM_ATTR buttonInterrupt()
{ {
ETS_GPIO_INTR_DISABLE(); ETS_GPIO_INTR_DISABLE();
buttonInterruptTimer.once_ms(50, switchingRelay); // For prevent contact chatter. buttonInterruptTimer.once_ms(500, switchingRelay); // For prevent contact chatter.
} }
void switchingRelay() void switchingRelay()
{ {
relayStatus = !relayStatus;
if (relayPin)
digitalWrite(relayPin, relayPinType ? relayStatus : !relayStatus);
if (ledPin)
digitalWrite(ledPin, ledPinType ? relayStatus : !relayStatus);
saveConfig();
sendStatusMessage();
ETS_GPIO_INTR_ENABLE(); ETS_GPIO_INTR_ENABLE();
relayStatus = !relayStatus;
if (config.relayPin)
{
if (config.workMode)
digitalWrite(config.relayPin, config.relayPinType ? !relayStatus : relayStatus);
else
digitalWrite(config.relayPin, config.relayPinType ? relayStatus : !relayStatus);
}
if (config.ledPin)
{
if (config.workMode)
digitalWrite(config.ledPin, config.ledPinType ? !relayStatus : relayStatus);
else
digitalWrite(config.ledPin, config.ledPinType ? relayStatus : !relayStatus);
}
saveStatus();
sendStatusMessage();
} }
void sendAttributesMessage() void sendAttributesMessage(const uint8_t type)
{ {
if (!isGatewayAvailable) if (!isGatewayAvailable)
return; return;
@ -313,22 +407,25 @@ 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_SWITCH, ENPT_ATTRIBUTES}; esp_now_payload_data_t outgoingData{ENDT_SWITCH, ENPT_ATTRIBUTES};
StaticJsonDocument<sizeof(esp_now_payload_data_t::message)> json; espnow_message_t message;
json["Type"] = "ESP-NOW Switch"; DynamicJsonDocument json(sizeof(esp_now_payload_data_t::message));
if (type == ENST_NONE)
json["Type"] = "ESP-NOW switch";
else
{
outgoingData.deviceType = ENDT_SENSOR;
json["Type"] = getValueName(esp_now_sensor_type_t(type));
}
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));
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);
attributesMessageResendTimerSemaphore = true; espnowMessage.push_back(message);
attributesMessageResendTimer.once(1, sendAttributesMessage);
} }
void sendKeepAliveMessage() void sendKeepAliveMessage()
@ -337,64 +434,104 @@ void sendKeepAliveMessage()
return; return;
keepAliveMessageTimerSemaphore = false; keepAliveMessageTimerSemaphore = false;
esp_now_payload_data_t outgoingData{ENDT_SWITCH, ENPT_KEEP_ALIVE}; esp_now_payload_data_t outgoingData{ENDT_SWITCH, ENPT_KEEP_ALIVE};
char temp[sizeof(esp_now_payload_data_t)]{0}; espnow_message_t message;
memcpy(&temp, &outgoingData, sizeof(esp_now_payload_data_t)); memcpy(&message.message, &outgoingData, sizeof(esp_now_payload_data_t));
myNet.sendUnicastMessage(temp, gatewayMAC, true); message.id = myNet.sendUnicastMessage(message.message, gatewayMAC, true);
keepAliveMessageResendTimerSemaphore = true; espnowMessage.push_back(message);
keepAliveMessageResendTimer.once(1, sendKeepAliveMessage);
} }
void sendConfigMessage() void sendConfigMessage(const uint8_t type)
{ {
if (!isGatewayAvailable) if (!isGatewayAvailable)
return; return;
esp_now_payload_data_t outgoingData{ENDT_SWITCH, ENPT_CONFIG}; esp_now_payload_data_t outgoingData{ENDT_SWITCH, ENPT_CONFIG};
StaticJsonDocument<sizeof(esp_now_payload_data_t::message)> json; espnow_message_t message;
json["name"] = deviceName; DynamicJsonDocument json(sizeof(esp_now_payload_data_t::message));
json["unit"] = 1; if (type == ENST_NONE)
json["type"] = getValueName(HACT_SWITCH); {
json["class"] = getValueName(HASWDC_SWITCH); json[MCMT_DEVICE_NAME] = config.deviceName;
json["reverse"] = "false"; json[MCMT_DEVICE_UNIT] = 1;
char buffer[sizeof(esp_now_payload_data_t::message)]{0}; json[MCMT_COMPONENT_TYPE] = HACT_SWITCH;
serializeJsonPretty(json, buffer); json[MCMT_DEVICE_CLASS] = HASWDC_SWITCH;
memcpy(outgoingData.message, buffer, sizeof(esp_now_payload_data_t::message)); json[MCMT_VALUE_TEMPLATE] = "state";
char temp[sizeof(esp_now_payload_data_t)]{0}; }
memcpy(&temp, &outgoingData, sizeof(esp_now_payload_data_t)); if (type == ENST_DS18B20 || type == ENST_DHT11 || type == ENST_DHT22)
myNet.sendUnicastMessage(temp, gatewayMAC, true); {
outgoingData.deviceType = ENDT_SENSOR;
json[MCMT_DEVICE_NAME] = config.deviceName + " temperature";
json[MCMT_DEVICE_UNIT] = 2;
json[MCMT_COMPONENT_TYPE] = HACT_SENSOR;
json[MCMT_DEVICE_CLASS] = HASDC_TEMPERATURE;
json[MCMT_VALUE_TEMPLATE] = "temperature";
json[MCMT_UNIT_OF_MEASUREMENT] = "°C";
json[MCMT_EXPIRE_AFTER] = 900;
}
serializeJsonPretty(json, outgoingData.message);
memcpy(&message.message, &outgoingData, sizeof(esp_now_payload_data_t));
message.id = myNet.sendUnicastMessage(message.message, gatewayMAC, true);
configMessageResendTimerSemaphore = true; espnowMessage.push_back(message);
configMessageResendTimer.once(5, sendConfigMessage);
if (type == ENST_DHT11 || type == ENST_DHT22)
{
outgoingData.deviceType = ENDT_SENSOR;
json[MCMT_DEVICE_NAME] = config.deviceName + " humidity";
json[MCMT_DEVICE_UNIT] = 3;
json[MCMT_COMPONENT_TYPE] = HACT_SENSOR;
json[MCMT_DEVICE_CLASS] = HASDC_HUMIDITY;
json[MCMT_VALUE_TEMPLATE] = "humidity";
json[MCMT_UNIT_OF_MEASUREMENT] = "%";
json[MCMT_EXPIRE_AFTER] = 900;
serializeJsonPretty(json, outgoingData.message);
memcpy(&message.message, &outgoingData, sizeof(esp_now_payload_data_t));
message.id = myNet.sendUnicastMessage(message.message, gatewayMAC, true);
espnowMessage.push_back(message);
}
} }
void sendStatusMessage() void sendStatusMessage(const uint8_t type)
{ {
if (!isGatewayAvailable) if (!isGatewayAvailable)
return; return;
statusMessageTimerSemaphore = false; statusMessageTimerSemaphore = false;
esp_now_payload_data_t outgoingData{ENDT_SWITCH, ENPT_STATE}; esp_now_payload_data_t outgoingData{ENDT_SWITCH, ENPT_STATE};
StaticJsonDocument<sizeof(esp_now_payload_data_t::message)> json; espnow_message_t message;
DynamicJsonDocument json(sizeof(esp_now_payload_data_t::message));
if (type == ENST_NONE)
json["state"] = relayStatus ? "ON" : "OFF"; json["state"] = relayStatus ? "ON" : "OFF";
char buffer[sizeof(esp_now_payload_data_t::message)]{0}; if (type == ENST_DS18B20)
serializeJsonPretty(json, buffer); {
memcpy(&outgoingData.message, &buffer, sizeof(esp_now_payload_data_t::message)); outgoingData.deviceType = ENDT_SENSOR;
char temp[sizeof(esp_now_payload_data_t)]{0}; ds18b20.requestTemperatures();
memcpy(&temp, &outgoingData, sizeof(esp_now_payload_data_t)); json["temperature"] = int8_t(ds18b20.getTempCByIndex(0));
myNet.sendUnicastMessage(temp, gatewayMAC, true); }
if (type == ENST_DHT11 || type == ENST_DHT22)
{
outgoingData.deviceType = ENDT_SENSOR;
json["temperature"] = int8_t(dht.getTemperature());
json["humidity"] = int8_t(dht.getHumidity());
}
serializeJsonPretty(json, outgoingData.message);
memcpy(&message.message, &outgoingData, sizeof(esp_now_payload_data_t));
message.id = myNet.sendUnicastMessage(message.message, gatewayMAC, true);
statusMessageResendTimerSemaphore = true; espnowMessage.push_back(message);
statusMessageResendTimer.once(1, sendStatusMessage);
} }
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 Switch " + myNet.getNodeMac()).c_str(), "12345678", 1, 1); WiFi.softAP(("ESP-NOW switch " + String(ESP.getChipId(), HEX)).c_str(), "12345678", 1, 1);
webServer.end();
} }
void attributesMessageTimerCallback() void attributesMessageTimerCallback()