13 #include <ArduinoJson.h>
14 #include <ESPAsyncWebServer.h>
17 #include <PubSubClient.h>
23 #include "esp_system.h"
24 #include "esp_event.h"
25 #include "mqtt_client.h"
27 #elif defined(ESP8266)
28 #include <ESP8266WiFi.h>
29 #include <ESPAsyncTCP.h>
33 #include <WiFiClientSecure.h>
35 #include <WiFiClient.h>
49 mqttPortParam =
new AsyncWiFiManagerParameter (
"mqttport",
"MQTT Port", port, 6,
"required type=\"number\" min=\"0\" max=\"65535\" step=\"1\"");
51 mqttPassParam =
new AsyncWiFiManagerParameter (
"mqttpass",
"MQTT Password",
"", 41,
"type=\"password\" maxlength=40");
61 if (!SPIFFS.begin ()) {
62 DEBUG_WARN (
"Error opening filesystem");
64 DEBUG_DBG (
"Filesystem opened");
68 DEBUG_WARN (
"Failed to open config file %s for writing",
CONFIG_FILE);
74 const size_t capacity = JSON_OBJECT_SIZE (4) + 110;
75 DynamicJsonDocument doc (capacity);
82 if (serializeJson (doc, configFile) == 0) {
83 DEBUG_ERROR (
"Failed to write to file");
90 serializeJsonPretty (doc, output);
92 DEBUG_DBG (
"%s", output.c_str ());
95 size_t size = configFile.size ();
98 DEBUG_DBG (
"Gateway configuration saved to flash. %u bytes", size);
104 bool json_correct =
false;
106 if (!SPIFFS.begin ()) {
107 DEBUG_WARN (
"Error starting filesystem. Formatting");
117 size_t size = configFile.size ();
118 DEBUG_DBG (
"%s opened. %u bytes",
CONFIG_FILE, size);
120 const size_t capacity = JSON_OBJECT_SIZE (4) + 110;
121 DynamicJsonDocument doc (capacity);
123 DeserializationError error = deserializeJson (doc, configFile);
126 DEBUG_ERROR (
"Failed to parse file");
128 DEBUG_DBG (
"JSON file parsed");
131 if (doc.containsKey (
"mqtt_server") && doc.containsKey (
"mqtt_port")
132 && doc.containsKey (
"mqtt_user") && doc.containsKey (
"mqtt_pass")) {
143 DEBUG_INFO (
"MQTT output module configuration successfuly read");
145 DEBUG_DBG (
"==== MQTT Configuration ====");
152 serializeJsonPretty (doc, output);
154 DEBUG_DBG (
"JSON file %s", output.c_str ());
168 DEBUG_INFO (
"==== Config Portal MQTTGW result ====");
172 DEBUG_INFO (
"MQTT password: %s",
mqttPassParam->getValue ());
173 DEBUG_INFO (
"Status: %s",
status ?
"true" :
"false");
182 if (mqtt_pass && (mqtt_pass[0] !=
'\0')) {
186 DEBUG_INFO (
"MQTT password field empty. Keeping the old one");
190 DEBUG_ERROR (
"Error writting MQTT config to filesystem.");
192 DEBUG_INFO (
"Configuration stored");
195 DEBUG_DBG (
"Configuration does not need to be saved");
207 randomSeed (micros ());
210 #elif defined(ESP8266)
211 espClient.setTrustAnchors (&certificate);
213 DEBUG_INFO (
"CA store set");
214 #endif // SECURE_MQTT
221 uint64_t chipid = ESP.getEfuseMac ();
223 #elif defined(ESP8266)
235 DEBUG_INFO (
"Attempting MQTT connection...");
241 DEBUG_DBG (
"Clock set.");
242 DEBUG_DBG (
"Connect to MQTT server: user %s, pass %s, topic %s",
246 DEBUG_WARN (
"MQTT connected");
250 String dlTopic =
netName + String (
"/+/set/#");
252 dlTopic =
netName + String (
"/+/get/#");
258 DEBUG_ERROR (
"failed, rc=%d try again in 5 seconds",
mqtt_client.state ());
262 int errorCode =
espClient.getLastSSLError (error, 100);
264 int errorCode =
espClient.lastError (error, 100);
266 DEBUG_ERROR (
"Connect error %d: %s", errorCode, error);
270 const TickType_t xDelay = 5000 / portTICK_PERIOD_MS;
283 char* start = strchr (topic,
'/') + 1;
287 end = strchr (start,
'/');
296 len = strlen (topic) - (start - topic);
312 DEBUG_WARN (
"IDENTIFY MESSAGE %s",
data.c_str ());
315 DEBUG_WARN (
"RESET CONFIG MESSAGE %s",
data.c_str ());
318 DEBUG_INFO (
"GET RSSI MESSAGE %s",
data.c_str ());
321 DEBUG_INFO (
"USER DATA %s",
data.c_str ());
324 DEBUG_INFO (
"USER DATA %s",
data.c_str ());
327 DEBUG_INFO (
"GET NODE NAME AND ADDRESS");
330 DEBUG_INFO (
"SET NODE NAME %",
data.c_str ());
343 char* start = strchr (topic,
'/') + 1;
345 start = strchr (start,
'/') + 1;
349 if ((
int)start > 0x01) {
350 command = String (start);
369 char* nodeName = NULL;
372 DEBUG_DBG (
"Topic %s", topic);
374 unsigned int addressLen;
380 DEBUG_DBG (
"Address %.*s", addressLen, addressStr);
381 if (!
str2mac (addressStr, addr)) {
382 DEBUG_INFO (
"Not a mac address. Treating it as a node name");
384 nodeName = (
char*)calloc (addressLen + 1,
sizeof (
char));
385 memcpy (nodeName, addressStr, addressLen);
387 DEBUG_WARN (
"Invalid address");
399 DEBUG_DBG (
"User command: %s", userCommand);
400 DEBUG_DBG (
"MsgType 0x%02X", msgType);
401 DEBUG_DBG (
"Data: %.*s\n", len,
data);
406 DEBUG_WARN (
"Invalid message");
432 DEBUG_INFO (
"Publish MQTT. %s : %.*s", topic, len, payload);
434 return mqtt_client.publish (topic, (uint8_t*)payload, len, retain);
436 DEBUG_WARN (
"MQTT client not connected");
442 void GwOutput_MQTT::setClock () {
443 configTime (1 * 3600, 0,
"pool.ntp.org",
"time.nist.gov");
444 #if DEBUG_LEVEL >= INFO
445 DEBUG_INFO (
"\nWaiting for NTP time sync: ");
446 time_t now = time (
nullptr);
447 while (now < 8 * 3600 * 2) {
450 now = time (
nullptr);
454 gmtime_r (&now, &timeinfo);
455 DEBUG_INFO (
"Current time: %s", asctime (&timeinfo));
467 message->
topic = (
char*)malloc (strlen (topic) + 1);
468 strcpy (message->
topic, topic);
470 message->
payload = (
char*)malloc (len);
471 memcpy (message->
payload, payload, len);
475 DEBUG_DBG (
"%d MQTT messages queued Len:%d %s %.*s",
mqtt_queue.size (),
485 DEBUG_DBG (
"MQTT message got from queue");
497 if (message->
topic) {
498 delete(message->
topic);
506 DEBUG_DBG (
"MQTT message pop. Size %d",
mqtt_queue.size ());
511 const int TOPIC_SIZE = 64;
512 char topic[TOPIC_SIZE];
516 snprintf (topic, TOPIC_SIZE,
"%s/%s/%s",
netName.c_str (), address,
NODE_DATA);
526 DEBUG_INFO (
"MQTT queued %s. Length %d", topic, length);
528 DEBUG_WARN (
"Error queuing MQTT %s", topic);
534 const int TOPIC_SIZE = 64;
535 const int PAYLOAD_SIZE = 512;
536 char topic[TOPIC_SIZE];
537 char payload[PAYLOAD_SIZE];
544 pld_size = snprintf (payload, PAYLOAD_SIZE,
"{\"version\":\"%.*s\"}", length - 1,
data + 1);
546 DEBUG_INFO (
"Published MQTT %s %s", topic, payload);
552 memcpy (&sleepTime,
data + 1,
sizeof (sleepTime));
554 pld_size = snprintf (payload, PAYLOAD_SIZE,
"{\"sleeptime\":%d}", sleepTime);
556 DEBUG_INFO (
"Published MQTT %s %s", topic, payload);
562 pld_size = snprintf (payload, PAYLOAD_SIZE,
"{}");
564 DEBUG_INFO (
"Published MQTT %s %s", topic, payload);
570 pld_size = snprintf (payload, PAYLOAD_SIZE,
"{\"rssi\":%d,\"channel\":%u}", (int8_t)
data[1],
data[2]);
572 DEBUG_INFO (
"Published MQTT %s %s", topic, payload);
581 DEBUG_INFO (
"Published MQTT %s %s", topic, payload);
589 pld_size = snprintf (payload, PAYLOAD_SIZE,
"{\"result\":\"OTA Started\",\"status\":%u}\n",
data[1]);
592 pld_size = snprintf (payload, PAYLOAD_SIZE,
"{\"result\":\"OTA Start error\",\"status\":%u}\n",
data[1]);
595 uint16_t lastGoodIdx;
596 memcpy ((uint8_t*)&lastGoodIdx,
data + 2,
sizeof (uint16_t));
597 pld_size = snprintf (payload, PAYLOAD_SIZE,
"{\"last_chunk\":%d,\"result\":\"OTA out of sequence error\",\"status\":%u}\n", lastGoodIdx,
data[1]);
600 pld_size = snprintf (payload, PAYLOAD_SIZE,
"{\"result\":\"OTA check OK\",\"status\":%u}\n",
data[1]);
603 pld_size = snprintf (payload, PAYLOAD_SIZE,
"{\"result\":\"OTA check failed\",\"status\":%u}\n",
data[1]);
606 pld_size = snprintf (payload, PAYLOAD_SIZE,
"{\"result\":\"OTA timeout\",\"status\":%u}\n",
data[1]);
609 pld_size = snprintf (payload, PAYLOAD_SIZE,
"{\"result\":\"OTA finished OK\",\"status\":%u}\n",
data[1]);
613 DEBUG_INFO (
"Published MQTT %s %s", topic, payload);
618 DEBUG_WARN (
"Unknown control message. Code: 0x%02X",
data[0]);
625 const int TOPIC_SIZE = 64;
627 char topic[TOPIC_SIZE];
636 snprintf (topic, TOPIC_SIZE,
"%s/%s/hello",
netName.c_str (), address);
638 DEBUG_INFO (
"Published MQTT %s", topic);
643 const int TOPIC_SIZE = 64;
644 const int PAYLOAD_SIZE = 64;
646 char topic[TOPIC_SIZE];
647 char payload[PAYLOAD_SIZE];
650 snprintf (topic, TOPIC_SIZE,
"%s/%s/bye",
netName.c_str (), address);
651 pld_size = snprintf (payload, PAYLOAD_SIZE,
"{\"reason\":%u}", reason);
653 DEBUG_INFO (
"Published MQTT %s result = %s", topic, result ?
"OK" :
"Fail");