13 #include <ArduinoJson.h>
14 #include <ESPAsyncWebServer.h>
17 #include <PubSubClient.h>
22 #include "esp_system.h"
23 #include "esp_event.h"
24 #include "mqtt_client.h"
26 #elif defined(ESP8266)
27 #include <ESP8266WiFi.h>
28 #include <ESPAsyncTCP.h>
32 #include <WiFiClientSecure.h>
34 #include <WiFiClient.h>
48 mqttPortParam =
new AsyncWiFiManagerParameter (
"mqttport",
"MQTT Port", port, 6,
"required type=\"number\" min=\"0\" max=\"65535\" step=\"1\"");
50 mqttPassParam =
new AsyncWiFiManagerParameter (
"mqttpass",
"MQTT Password",
"", 41,
"type=\"password\" maxlength=40");
60 if (!FILESYSTEM.begin ()) {
61 DEBUG_WARN (
"Error opening filesystem");
63 DEBUG_DBG (
"Filesystem opened");
65 File configFile = FILESYSTEM.open (
CONFIG_FILE,
"w");
67 DEBUG_WARN (
"Failed to open config file %s for writing",
CONFIG_FILE);
73 const size_t capacity = JSON_OBJECT_SIZE (4) + 110;
74 DynamicJsonDocument doc (capacity);
81 if (serializeJson (doc, configFile) == 0) {
82 DEBUG_ERROR (
"Failed to write to file");
89 serializeJsonPretty (doc, output);
91 DEBUG_DBG (
"%s", output.c_str ());
97 DEBUG_DBG (
"Gateway configuration saved to flash. %u bytes", configFile.size ());
103 bool json_correct =
false;
105 if (!FILESYSTEM.begin ()) {
106 DEBUG_WARN (
"Error starting filesystem. Formatting");
107 FILESYSTEM.format ();
114 File configFile = FILESYSTEM.open (
CONFIG_FILE,
"r");
117 DEBUG_DBG (
"%s opened. %u bytes",
CONFIG_FILE, configFile.size ());
119 const size_t capacity = JSON_OBJECT_SIZE (4) + 110;
120 DynamicJsonDocument doc (capacity);
122 DeserializationError error = deserializeJson (doc, configFile);
125 DEBUG_ERROR (
"Failed to parse file");
127 DEBUG_DBG (
"JSON file parsed");
130 if (doc.containsKey (
"mqtt_server") && doc.containsKey (
"mqtt_port")
131 && doc.containsKey (
"mqtt_user") && doc.containsKey (
"mqtt_pass")) {
142 DEBUG_INFO (
"MQTT output module configuration successfuly read");
144 DEBUG_DBG (
"==== MQTT Configuration ====");
151 serializeJsonPretty (doc, output);
153 DEBUG_DBG (
"JSON file %s", output.c_str ());
167 DEBUG_INFO (
"==== Config Portal MQTTGW result ====");
171 DEBUG_INFO (
"MQTT password: %s",
mqttPassParam->getValue ());
172 DEBUG_INFO (
"Status: %s",
status ?
"true" :
"false");
181 if (mqtt_pass && (mqtt_pass[0] !=
'\0')) {
185 DEBUG_INFO (
"MQTT password field empty. Keeping the old one");
189 DEBUG_ERROR (
"Error writting MQTT config to filesystem.");
191 DEBUG_INFO (
"Configuration stored");
194 DEBUG_DBG (
"Configuration does not need to be saved");
206 randomSeed (micros ());
209 #elif defined(ESP8266)
210 espClient.setTrustAnchors (&certificate);
212 DEBUG_INFO (
"CA store set");
213 #endif // SECURE_MQTT
220 uint64_t chipid = ESP.getEfuseMac ();
222 #elif defined(ESP8266)
239 DEBUG_INFO (
"Attempting MQTT connection...");
240 for (
int i = 1; i < 5; i++) {
241 DEBUG_WARN (
"Connecting to WiFi %s", WiFi.SSID ().c_str ());
243 if (WiFi.isConnected ()) {
244 DEBUG_WARN (
"WiFi is connected");
255 DEBUG_DBG (
"Clock set.");
256 DEBUG_DBG (
"Connect to MQTT server: user %s, pass %s, topic %s",
260 DEBUG_WARN (
"MQTT connected");
264 String dlTopic =
netName + String (
"/+/set/#");
266 dlTopic =
netName + String (
"/+/get/#");
272 DEBUG_ERROR (
"failed, rc=%d try again in 5 seconds",
mqtt_client.state ());
276 int errorCode =
espClient.getLastSSLError (error, 100);
278 int errorCode =
espClient.lastError (error, 100);
280 DEBUG_ERROR (
"Connect error %d: %s", errorCode, error);
284 const TickType_t xDelay = 5000 / portTICK_PERIOD_MS;
297 char* start = strchr (topic,
'/') + 1;
301 end = strchr (start,
'/');
310 len = strlen (topic) - (start - topic);
317 DEBUG_DBG (
"Type topic: %s",
data.c_str ());
327 DEBUG_WARN (
"IDENTIFY MESSAGE %s",
data.c_str ());
330 DEBUG_WARN (
"RESET CONFIG MESSAGE %s",
data.c_str ());
333 DEBUG_INFO (
"GET RSSI MESSAGE %s",
data.c_str ());
336 DEBUG_INFO (
"USER DATA %s",
data.c_str ());
339 DEBUG_INFO (
"USER DATA %s",
data.c_str ());
342 DEBUG_INFO (
"GET NODE NAME AND ADDRESS");
345 DEBUG_INFO (
"SET NODE NAME %s",
data.c_str ());
348 DEBUG_INFO (
"RESET MCU");
361 char* start = strchr (topic,
'/') + 1;
363 start = strchr (start,
'/') + 1;
367 if ((
int)start > 0x01) {
368 command = String (start);
387 char* nodeName =
nullptr;
390 DEBUG_DBG (
"Topic %s", topic);
392 unsigned int addressLen;
398 DEBUG_DBG (
"Address %.*s", addressLen, addressStr);
399 if (!
str2mac (addressStr, addr)) {
400 DEBUG_INFO (
"Not a mac address. Treating it as a node name");
402 nodeName = (
char*)calloc (addressLen + 1,
sizeof (
char));
403 memcpy (nodeName, addressStr, addressLen);
405 DEBUG_WARN (
"Invalid address");
417 DEBUG_DBG (
"User command: %s", userCommand);
418 DEBUG_DBG (
"MsgType 0x%02X", msgType);
419 DEBUG_DBG (
"Data: %.*s\n", len,
data);
424 DEBUG_WARN (
"Invalid message");
440 static time_t statusLastUpdated;
450 statusLastUpdated = millis ();
457 DEBUG_INFO (
"Publish MQTT. %s : %.*s", topic, len, payload);
459 return mqtt_client.publish (topic, (uint8_t*)payload, len, retain);
461 DEBUG_WARN (
"MQTT client not connected");
468 #if DEBUG_LEVEL >= INFO
469 DEBUG_INFO (
"\nWaiting for NTP time sync: ");
470 time_t now = time (
nullptr);
471 while (now < 8 * 3600 * 2) {
474 now = time (
nullptr);
478 gmtime_r (&now, &timeinfo);
479 DEBUG_INFO (
"Current time: %s", asctime (&timeinfo));
499 DEBUG_DBG (
"%d MQTT messages queued Len:%d %s %.*s",
mqtt_queue.
size (),
509 DEBUG_DBG (
"MQTT message got from queue");
521 if (message->
topic) {
523 message->
topic[0] = 0;
537 #if SUPPORT_HA_DISCOVERY
538 bool GwOutput_MQTT::rawMsgSend (
const char* topic,
char* payload,
size_t len,
bool retain) {
541 if ((result =
addMQTTqueue (topic, payload, len, retain))) {
542 DEBUG_INFO (
"MQTT queued %s. Length %d", topic, len);
544 DEBUG_WARN (
"Error queuing MQTT %s", topic);
552 const int TOPIC_SIZE = 64;
553 char topic[TOPIC_SIZE];
557 snprintf (topic, TOPIC_SIZE,
"%s/%s/%s",
netName.c_str (), address,
NODE_DATA);
567 DEBUG_INFO (
"MQTT queued %s. Length %d", topic, length);
569 DEBUG_WARN (
"Error queuing MQTT %s", topic);
575 const int TOPIC_SIZE = 64;
576 const int PAYLOAD_SIZE = 512;
577 char topic[TOPIC_SIZE];
578 char payload[PAYLOAD_SIZE];
586 pld_size = snprintf (payload, PAYLOAD_SIZE,
"{\"version\":\"%d.%d.%d\"}",
data[1],
data[2],
data[3]);
589 DEBUG_INFO (
"Published MQTT %s %s", topic, payload);
595 memcpy (&sleepTime,
data + 1,
sizeof (sleepTime));
597 pld_size = snprintf (payload, PAYLOAD_SIZE,
"{\"sleeptime\":%u}", sleepTime);
599 DEBUG_INFO (
"Published MQTT %s %s", topic, payload);
605 pld_size = snprintf (payload, PAYLOAD_SIZE,
"{\"result\":\"OK\"}");
607 DEBUG_INFO (
"Published MQTT %s %s", topic, payload);
613 pld_size = snprintf (payload, PAYLOAD_SIZE,
"{\"rssi\":%d,\"channel\":%u}", (int8_t)
data[1],
data[2]);
616 DEBUG_INFO (
"Published MQTT %s %s", topic, payload);
625 DEBUG_INFO (
"Published MQTT %s %s", topic, payload);
632 pld_size = snprintf (payload, PAYLOAD_SIZE,
"{\"reason\":%d}", (int8_t)
data[1]);
635 DEBUG_INFO (
"Published MQTT %s %s", topic, payload);
643 pld_size = snprintf (payload, PAYLOAD_SIZE,
"{\"result\":\"OTA Started\",\"status\":%u}",
data[1]);
646 pld_size = snprintf (payload, PAYLOAD_SIZE,
"{\"result\":\"OTA Start error\",\"status\":%u}",
data[1]);
649 uint16_t lastGoodIdx;
650 memcpy ((uint8_t*)&lastGoodIdx,
data + 2,
sizeof (uint16_t));
651 pld_size = snprintf (payload, PAYLOAD_SIZE,
"{\"last_chunk\":%d,\"result\":\"OTA out of sequence error\",\"status\":%u}", lastGoodIdx,
data[1]);
654 pld_size = snprintf (payload, PAYLOAD_SIZE,
"{\"result\":\"OTA check OK\",\"status\":%u}",
data[1]);
657 pld_size = snprintf (payload, PAYLOAD_SIZE,
"{\"result\":\"OTA check failed\",\"status\":%u}",
data[1]);
660 pld_size = snprintf (payload, PAYLOAD_SIZE,
"{\"result\":\"OTA timeout\",\"status\":%u}",
data[1]);
663 pld_size = snprintf (payload, PAYLOAD_SIZE,
"{\"result\":\"OTA finished OK\",\"status\":%u}",
data[1]);
667 DEBUG_INFO (
"Published MQTT %s %s", topic, payload);
672 DEBUG_WARN (
"Unknown control message. Code: 0x%02X",
data[0]);
679 const int TOPIC_SIZE = 64;
681 char topic[TOPIC_SIZE];
690 snprintf (topic, TOPIC_SIZE,
"%s/%s/hello",
netName.c_str (), address);
692 DEBUG_INFO (
"Published MQTT %s", topic);
697 const int TOPIC_SIZE = 64;
698 const int PAYLOAD_SIZE = 64;
700 char topic[TOPIC_SIZE];
701 char payload[PAYLOAD_SIZE];
704 snprintf (topic, TOPIC_SIZE,
"%s/%s/bye",
netName.c_str (), address);
705 pld_size = snprintf (payload, PAYLOAD_SIZE,
"{\"reason\":%d}", reason);
707 DEBUG_INFO (
"Published MQTT %s result = %s", topic, result ?
"OK" :
"Fail");