17 #include <WiFiClientSecure.h>
19 #include <WiFiClient.h>
26 #include "soc/rtc_cntl_reg.h"
28 #include <ESP8266WiFi.h>
31 #include <ArduinoOTA.h>
33 #include <CayenneLPP.h>
39 #include <ArduinoJson.h>
40 #include <ESPAsyncWiFiManager.h>
45 #include <DallasTemperature.h>
47 const time_t statusPeriod = 300 * 1000;
48 const int DS18B20_PIN = 16;
49 const int DS18B20_PREC = 12;
50 OneWire ow (DS18B20_PIN);
51 DallasTemperature ds18b20 (&ow);
52 DeviceAddress dsAddress;
60 #define BLUE_LED LED_BUILTIN
61 #define RED_LED LED_BUILTIN
64 TimerHandle_t connectionLedTimer;
65 #elif defined(ESP8266)
66 ETSTimer connectionLedTimer;
85 connectionLedTimer = xTimerCreate (
"led_flash", pdMS_TO_TICKS (period), pdTRUE, (
void*)0,
flashConnectionLed);
86 xTimerStart (connectionLedTimer, 0);
88 #elif defined (ESP8266)
89 ets_timer_disarm (&connectionLedTimer);
92 ets_timer_arm_new (&connectionLedTimer, period,
true,
true);
101 xTimerStop (connectionLedTimer, 0);
102 xTimerDelete (connectionLedTimer, 0);
104 #elif defined(ESP8266)
107 ets_timer_disarm (&connectionLedTimer);
127 ArduinoOTA.onStart ([] () {
128 if (ArduinoOTA.getCommand () == U_FLASH) {
129 DEBUG_WARN (
"Start updating sketch");
131 DEBUG_WARN (
"Start updating filesystem");
135 ArduinoOTA.onEnd ([] () {
136 DEBUG_WARN (
"OTA Finished");
138 ArduinoOTA.onProgress ([] (
unsigned int progress,
unsigned int total) {
139 static bool printed =
false;
140 unsigned int percent = progress / (total / 100);
145 if (!(percent % 20) && !printed && percent != 0) {
146 DEBUG_WARN (
" %d%%\n", percent);
148 }
else if (percent % 20) {
151 if (progress == total) {
152 DEBUG_WARN (
"OTA transfer finished");
155 ArduinoOTA.onError ([] (ota_error_t error) {
156 DEBUG_WARN (
"OTA Error[%u]: ", error);
157 if (error == OTA_AUTH_ERROR) { DEBUG_WARN (
"OTA Auth Failed"); }
else if (error == OTA_BEGIN_ERROR) { DEBUG_WARN (
"OTA Begin Failed"); }
else if (error == OTA_CONNECT_ERROR) { DEBUG_WARN (
"OTA Connect Failed"); }
else if (error == OTA_RECEIVE_ERROR) { DEBUG_WARN (
"OTA Receive Failed"); }
else if (error == OTA_END_ERROR) { DEBUG_WARN (
"OTA End Failed"); }
174 DEBUG_INFO (
"Version message: %d.%d.%d",
data[1],
data[2],
data[3]);
185 DEBUG_WARN (
"Restart requested");
186 const size_t capacity = JSON_OBJECT_SIZE (1);
190 DynamicJsonDocument doc (capacity);
192 doc[
"action"] =
"restart";
194 len = measureJson (doc) + 1;
195 payload = (
char*)malloc (len);
196 serializeJson (doc, (
char*)payload, len);
197 char addr[] =
"gateway";
206 #if SUPPORT_HA_DISCOVERY
207 void processHADiscovery (
const char* topic,
char* message,
size_t len) {
208 DEBUG_INFO (
"About to process HA discovery. Len: %d - %s --> %.*s", len, topic, len, message);
209 GwOutput.rawMsgSend (topic, message, len,
true);
216 const int PAYLOAD_SIZE = 1024;
218 char payload[PAYLOAD_SIZE];
229 DEBUG_INFO (
"CayenneLPP message");
230 const int capacity = JSON_ARRAY_SIZE (25) + 25 * JSON_OBJECT_SIZE (4);
231 DynamicJsonDocument jsonBuffer (capacity);
232 JsonArray root = jsonBuffer.createNestedArray ();
235 cayennelpp.decode ((uint8_t*)buffer, length, root);
236 uint8_t error = cayennelpp.getError ();
237 if (error != LPP_ERROR_OK) {
238 DEBUG_ERROR (
"Error decoding CayenneLPP data: %d", error);
241 pld_size = serializeJson (root, payload, PAYLOAD_SIZE);
242 }
else if (payload_type ==
MSG_PACK) {
243 DEBUG_INFO (
"MsgPack message");
244 const int capacity = JSON_ARRAY_SIZE (25) + 25 * JSON_OBJECT_SIZE (4);
245 DynamicJsonDocument jsonBuffer (capacity);
246 DeserializationError error = deserializeMsgPack (jsonBuffer, buffer, length);
247 if (error != DeserializationError::Ok) {
248 DEBUG_ERROR (
"Error decoding MSG Pack data: %s", error.c_str ());
251 pld_size = serializeJson (jsonBuffer, payload, PAYLOAD_SIZE);
252 }
else if (payload_type ==
RAW) {
253 DEBUG_INFO (
"RAW message");
254 if (length <= PAYLOAD_SIZE) {
255 memcpy (payload, buffer, length);
258 memcpy (payload, buffer, PAYLOAD_SIZE);
259 pld_size = PAYLOAD_SIZE;
264 DEBUG_INFO (
"Published data message from %s, length %d: %s, Encoding 0x%02X", nodeName ? nodeName : mac_str, pld_size, payload, payload_type);
265 if (lostMessages > 0) {
266 pld_size = snprintf (payload, PAYLOAD_SIZE,
"{\"lostMessages\":%u}", lostMessages);
268 DEBUG_INFO (
"Published MQTT from %s: %s", nodeName ? nodeName : mac_str, payload);
270 #if ENABLE_STATUS_MESSAGES
271 pld_size = snprintf (payload, PAYLOAD_SIZE,
"{\"per\":%e,\"lostmessages\":%u,\"totalmessages\":%u,\"packetshour\":%.2f}",
277 DEBUG_INFO (
"Published MQTT from %s: %s", nodeName ? nodeName : mac_str, payload);
283 unsigned int bufferLen = len;
287 DEBUG_INFO (
"DL Message for %s. Type 0x%02X", nodeName, msgType);
289 DEBUG_INFO (
"DL Message for " MACSTR ". Type 0x%02X", MAC2STR (address), msgType);
291 DEBUG_DBG (
"Data: %.*s Length: %d", len,
data, len);
294 const int capacity = JSON_ARRAY_SIZE (25) + 25 * JSON_OBJECT_SIZE (4);
295 DynamicJsonDocument json (capacity);
296 DeserializationError error = deserializeJson (json,
data, len, DeserializationOption::NestingLimit (3));
297 if (error == DeserializationError::Ok) {
298 DEBUG_INFO (
"JSON Message. Result %s", error.c_str ());
299 bufferLen = measureMsgPack (json) + 1;
300 buffer = (uint8_t*)malloc (bufferLen);
301 bufferLen = serializeMsgPack (json, (
char*)buffer, bufferLen);
304 DEBUG_INFO (
"Not JSON Message. Error %s", error.c_str ());
306 buffer = (uint8_t*)malloc (bufferLen);
307 sprintf ((
char*)buffer,
"%.*s", len,
data);
312 buffer = (uint8_t*)calloc (
sizeof (uint8_t), bufferLen);
313 memcpy (buffer,
data, len);
319 DEBUG_WARN (
"Error sending esp_now message to %s", nodeName);
321 DEBUG_WARN (
"Error sending esp_now message to " MACSTR, MAC2STR (address));
324 DEBUG_DBG (
"Esp-now message sent or queued correctly");
336 DEBUG_WARN (
"Error sending new node %s", nodeName);
338 DEBUG_DBG (
"New node %s message sent", nodeName);
344 DEBUG_WARN (
"Error sending new node %s", macstr);
346 DEBUG_DBG (
"New node %s message sent", macstr);
357 DEBUG_WARN (
"Error sending node disconnected %s reason %d", macstr, reason);
359 DEBUG_DBG (
"Node %s disconnected message sent. Reason %d", macstr, reason);
383 Serial.begin (921600); Serial.println (); Serial.println ();
388 WRITE_PERI_REG (RTC_CNTL_BROWN_OUT_REG, 0);
402 DEBUG_WARN (
"Found %u sensors", ds18b20.getDeviceCount ());
404 if (ds18b20.getAddress (dsAddress, 0)) {
405 DEBUG_WARN (
"DS18B20 address: %02X %02X %02X %02X %02X %02X %02X %02X",
406 dsAddress[0], dsAddress[1], dsAddress[2], dsAddress[3],
407 dsAddress[4], dsAddress[5], dsAddress[6], dsAddress[7]);
409 DEBUG_WARN (
"No DS18B20 found");
411 ds18b20.setWaitForConversion (
false);
412 ds18b20.setResolution (DS18B20_PREC);
418 DEBUG_WARN (
"Error reading config file");
428 #if SUPPORT_HA_DISCOVERY
435 WiFi.mode (WIFI_AP_STA);
443 DEBUG_INFO (
"STA MAC Address: %s", WiFi.macAddress ().c_str ());
444 DEBUG_INFO (
"AP MAC Address: %s", WiFi.softAPmacAddress ().c_str ());
445 DEBUG_INFO (
"BSSID Address: %s", WiFi.BSSIDstr ().c_str ());
447 DEBUG_INFO (
"IP address: %s", WiFi.localIP ().toString ().c_str ());
448 DEBUG_INFO (
"WiFi Channel: %d", WiFi.channel ());
449 DEBUG_INFO (
"WiFi SSID: %s", WiFi.SSID ().c_str ());
465 void sendStatus (
float temperature) {
466 const size_t capacity = JSON_OBJECT_SIZE (1) + JSON_OBJECT_SIZE (3) + 30;;
470 DynamicJsonDocument doc (capacity);
472 JsonObject
status = doc.createNestedObject (
"status");
473 if (temperature > -100) {
474 status[
"temp"] = temperature;
477 status[
"mem"] = ESP.getFreeHeap ();
479 len = measureJson (doc) + 1;
480 payload = (
char*)malloc (len);
481 serializeJson (doc, (
char*)payload, len);
482 char addr[] =
"gateway";
491 ArduinoOTA.handle ();
494 static bool tempRequested =
false;
495 static time_t lastTempTime = 0;
497 if (ds18b20.validAddress (dsAddress)) {
498 if ((millis () - lastTempTime > statusPeriod && !tempRequested) || !lastTempTime) {
499 if (ds18b20.requestTemperaturesByIndex (0)) {
500 DEBUG_INFO (
"Temperature requested");
501 lastTempTime = millis ();
502 tempRequested =
true;
504 DEBUG_WARN (
"Temperature request error");
508 if (ds18b20.isConversionComplete ()) {
509 temperature = ds18b20.getTempC (dsAddress);
510 sendStatus (temperature);
511 DEBUG_WARN (
"Temperature: %f", temperature);
512 tempRequested =
false;