mqtt.ino 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674
  1. /*#include <Arduino.h>*/
  2. #define MQTT_RECONNECT_INTERVAL_3_TRIES 15000
  3. #define MQTT_RECONNECT_INTERVAL_10_TRIES 60000
  4. #define MQTT_RECONNECT_INTERVAL_LONG 300000
  5. bool mqtt_heartbeatReceived = false;
  6. // MQTT callback
  7. void mqttCallback(char *topic, unsigned char *payload, uint16_t length)
  8. {
  9. // Serial.print("MQTT payload arrived [");
  10. // Serial.print(topic);
  11. // Serial.print("] ");
  12. // for (int i = 0; i < length; i++) {
  13. // Serial.print((char)payload[i]);
  14. // }
  15. // Serial.println();
  16. //char tmp_topic_pub[51];
  17. //char tmp_payload_pub[51];
  18. if (strcmp(topic, mqtt_topic_in_cmd) == 0)
  19. { //if topic = mqtt_topic_in_cmd
  20. int _len;
  21. if (length < sizeof(cmdPayload))
  22. _len = length; // if input is bigger than dest buffer, cut
  23. else
  24. _len = sizeof(cmdPayload) - 1;
  25. for (int i = 0; i < _len; i++)
  26. {
  27. cmdPayload[i] = (char)payload[i];
  28. }
  29. cmdPayload[_len] = '\0';
  30. // Serial.print("cmdPayload:");
  31. // Serial.println(cmdPayload);
  32. //if (serialdebug)
  33. //{
  34. // Serial.print("MQTT: received '");
  35. // Serial.print(mqtt_topic_in_cmd);
  36. // Serial.print("' - '");
  37. // Serial.print(cmdPayload);
  38. // Serial.println("'");
  39. //}
  40. //if (mqttdebug)
  41. //{
  42. // sprintf(tmp_topic_pub, "%s/%s", confMqtt.mqtt_topic_out, "mqtt_received");
  43. // sprintf(tmp_payload_pub, "%s: %s", mqtt_topic_in_cmd, cmdPayload);
  44. // mqttclient.publish(tmp_topic_pub, tmp_payload_pub);
  45. //}
  46. if (strncmp(cmdPayload, "HEARTBEAT", 9) == 0)
  47. {
  48. mqtt_lastHeartbeat = millis();
  49. mqtt_heartbeatReceived = true;
  50. mqtt_connected = true;
  51. }
  52. else
  53. {
  54. cmdInQueue = true; // payload is processed in "commands"
  55. }
  56. } //if topic = mqtt_topic_in_cmd
  57. #ifdef FIRMWARE_VARIANT_THERMOSTAT
  58. if (strcmp(topic, mqtt_topic_in_setTemp) == 0) {
  59. int len;
  60. if (length < sizeof(cmdPayload))
  61. len = length; // if input is bigger than dest buffer, cut
  62. else
  63. len = sizeof(cmdPayload) - 1;
  64. for (int i = 0; i < len; i++)
  65. {
  66. cmdPayload[i] = (char)payload[i];
  67. }
  68. //cmdPayload[len + 1] = '\0';
  69. cmdPayload[len] = '\0';
  70. // Serial.print("cmdPayload:");
  71. // Serial.println(cmdPayload);
  72. char tmpPayload[11];
  73. strlcpy(tmpPayload, cmdPayload, 10);
  74. float valueFloat;
  75. valueFloat = round(atof(tmpPayload) * 2.0) / 2.0;
  76. thermostat_setTempTo(valueFloat);
  77. //if (serialdebug)
  78. //{
  79. // Serial.print("MQTT: received '");
  80. // Serial.print(mqtt_topic_in_setTemp);
  81. // Serial.print("' - '");
  82. // Serial.print(cmdPayload);
  83. // Serial.println("'");
  84. //}
  85. //if (mqttdebug)
  86. //{
  87. // sprintf(tmp_topic_pub, "%s/%s", confMqtt.mqtt_topic_out, "mqtt_received");
  88. // sprintf(tmp_payload_pub, "%s: %s", mqtt_topic_in_setTemp, cmdPayload);
  89. // mqttclient.publish(tmp_topic_pub, tmp_payload_pub);
  90. //}
  91. char buf[50];
  92. sprintf(buf, "MQTT IN: setTemp to %2.1f", valueFloat);
  93. sendLog(buf, LOGLEVEL_INFO);
  94. cmdInQueue = false; // payload is processed in "commands"
  95. } //if topic = mqtt_topic_in_setTemp
  96. if (strcmp(topic, mqtt_topic_in_setMode) == 0)
  97. { //if topic = mqtt_topic_in_setMode
  98. uint8_t len;
  99. if (length < sizeof(cmdPayload))
  100. len = length; // if input is bigger than dest buffer, cut
  101. else
  102. len = sizeof(cmdPayload) - 1;
  103. for (int i = 0; i < len; i++)
  104. {
  105. cmdPayload[i] = (char)payload[i];
  106. }
  107. //cmdPayload[len + 1] = '\0';
  108. cmdPayload[len] = '\0';
  109. // Serial.print("cmdPayload:");
  110. // Serial.println(cmdPayload);
  111. char tmpPayload[21];
  112. strlcpy(tmpPayload, cmdPayload, sizeof(tmpPayload));
  113. strlwr(tmpPayload);
  114. unsigned char tmpHeatMode = 100;
  115. char tmpModename0[15];
  116. char tmpModename1[15];
  117. strlcpy(tmpModename0, confTherm.modeName0, sizeof(tmpModename0));
  118. strlcpy(tmpModename1, confTherm.modeName1, sizeof(tmpModename1));
  119. strlwr(tmpModename0);
  120. strlwr(tmpModename1);
  121. if (strcmp(tmpPayload, tmpModename0) == 0)
  122. tmpHeatMode = 0;
  123. else if (strcmp(tmpPayload, tmpModename1) == 0)
  124. tmpHeatMode = 1;
  125. else if (strcmp(tmpPayload, "off") == 0)
  126. tmpHeatMode = 0;
  127. else if (strcmp(tmpPayload, "aus") == 0)
  128. tmpHeatMode = 0;
  129. else if (strcmp(tmpPayload, "on") == 0)
  130. tmpHeatMode = 1;
  131. else if (strcmp(tmpPayload, "ein") == 0)
  132. tmpHeatMode = 1;
  133. else if (strcmp(tmpPayload, "heat") == 0)
  134. tmpHeatMode = 1;
  135. else if (atoi(tmpPayload) == 0)
  136. tmpHeatMode = 0;
  137. else if (atoi(tmpPayload) == 1)
  138. tmpHeatMode = 1;
  139. if (tmpHeatMode == 0 || tmpHeatMode == 1)
  140. {
  141. thermostat_setHeatingmodeTo(tmpHeatMode);
  142. //if (serialdebug)
  143. //{
  144. // Serial.print(F("set heatmode to: "));
  145. // Serial.println(tmpHeatMode);
  146. //}
  147. //if (serialdebug)
  148. //{
  149. // Serial.print("MQTT: received '");
  150. // Serial.print(mqtt_topic_in_setMode);
  151. // Serial.print("' - '");
  152. // Serial.print(cmdPayload);
  153. // Serial.println("'");
  154. //}
  155. //if (mqttdebug)
  156. //{
  157. // sprintf(tmp_topic_pub, "%s/%s", confMqtt.mqtt_topic_out, "mqtt_received");
  158. // sprintf(tmp_payload_pub, "%s: %s", mqtt_topic_in_setMode, cmdPayload);
  159. // mqttclient.publish(tmp_topic_pub, tmp_payload_pub);
  160. //}
  161. char buf[50];
  162. sprintf(buf, "MQTT IN: setMode to %u", tmpHeatMode);
  163. sendLog(buf, LOGLEVEL_INFO);
  164. }
  165. cmdInQueue = false; // payload is processed in "commands"
  166. } //if topic = mqtt_topic_in_setMode
  167. if (strcmp(topic, mqtt_topic_in_setPause) == 0)
  168. { //if topic = mqtt_topic_in_setMode
  169. uint8_t len;
  170. uint8_t _setTo = 255;
  171. if (length < sizeof(cmdPayload))
  172. len = length; // if input is bigger than dest buffer, cut
  173. else
  174. len = sizeof(cmdPayload) - 1;
  175. for (int i = 0; i < len; i++)
  176. {
  177. cmdPayload[i] = (char)payload[i];
  178. }
  179. //cmdPayload[len + 1] = '\0';
  180. cmdPayload[len] = '\0';
  181. // Serial.print("cmdPayload:");
  182. // Serial.println(cmdPayload);
  183. char tmpPayload[21];
  184. strlcpy(tmpPayload, cmdPayload, sizeof(tmpPayload));
  185. strlwr(tmpPayload);
  186. if (strcmp(tmpPayload, "1") == 0) _setTo = 1;
  187. else if (strcmp(tmpPayload, "0") == 0) _setTo = 0;
  188. if(_setTo == 1 || _setTo == 0) {
  189. thermostat_setHeatingPause(_setTo);
  190. char buf[50];
  191. sprintf(buf, "MQTT IN: setPause to %u", _setTo);
  192. sendLog(buf, LOGLEVEL_INFO);
  193. }
  194. cmdInQueue = false; // payload is processed in "commands"
  195. } //if topic = mqtt_topic_in_setPause
  196. if (strcmp(topic, mqtt_topic_in_setPreset) == 0)
  197. { //if topic = mqtt_topic_in_setPreset
  198. char tmpPayload[21];
  199. char tmpPresetName0[15];
  200. char tmpPresetName1[15];
  201. char tmpPresetName2[15];
  202. uint16_t len;
  203. unsigned char tmpPreset = 100;
  204. if (length < sizeof(cmdPayload))
  205. len = length; // if input is bigger than dest buffer, cut
  206. else
  207. len = sizeof(cmdPayload) - 1;
  208. for (unsigned char i = 0; i < len; i++)
  209. {
  210. cmdPayload[i] = (char)payload[i];
  211. }
  212. //cmdPayload[len + 1] = '\0';
  213. cmdPayload[len] = '\0';
  214. // Serial.print("cmdPayload:");
  215. // Serial.println(cmdPayload);
  216. strlcpy(tmpPayload, cmdPayload, sizeof(tmpPayload));
  217. strlwr(tmpPayload);
  218. strlcpy(tmpPresetName0, confTherm.psetName0, sizeof(tmpPresetName0));
  219. strlcpy(tmpPresetName1, confTherm.psetName1, sizeof(tmpPresetName1));
  220. strlcpy(tmpPresetName2, confTherm.psetName2, sizeof(tmpPresetName2));
  221. strlwr(tmpPresetName0);
  222. strlwr(tmpPresetName1);
  223. strlwr(tmpPresetName2);
  224. if (strcmp(tmpPayload, tmpPresetName0) == 0)
  225. tmpPreset = 0;
  226. else if (strcmp(tmpPayload, tmpPresetName1) == 0)
  227. tmpPreset = 1;
  228. else if (strcmp(tmpPayload, tmpPresetName2) == 0)
  229. tmpPreset = 2;
  230. else if (strcmp(tmpPayload, "none") == 0)
  231. tmpPreset = 0;
  232. else if (strcmp(tmpPayload, "norm") == 0)
  233. tmpPreset = 0;
  234. else if (strcmp(tmpPayload, "red1") == 0)
  235. tmpPreset = 1;
  236. else if (strcmp(tmpPayload, "red2") == 0)
  237. tmpPreset = 2;
  238. else if (atoi(tmpPayload) == 0)
  239. tmpPreset = 0;
  240. else if (atoi(tmpPayload) == 1)
  241. tmpPreset = 1;
  242. else if (atoi(tmpPayload) == 2)
  243. tmpPreset = 2;
  244. if (tmpPreset <= 2)
  245. {
  246. thermostat_setPresetTo(tmpPreset);
  247. //if (serialdebug)
  248. //{
  249. // Serial.print(F("set preset to: "));
  250. // Serial.println(tmpPreset);
  251. //}
  252. //if (serialdebug)
  253. //{
  254. // Serial.print(F("MQTT: received '"));
  255. // Serial.print(mqtt_topic_in_setPreset);
  256. // Serial.print("' - '");
  257. // Serial.print(cmdPayload);
  258. // Serial.println("'");
  259. //}
  260. //if (mqttdebug)
  261. //{
  262. // sprintf(tmp_topic_pub, "%s/%s", confMqtt.mqtt_topic_out, "mqtt_received");
  263. // sprintf(tmp_payload_pub, "%s: %s", mqtt_topic_in_setPreset, cmdPayload);
  264. // mqttclient.publish(tmp_topic_pub, tmp_payload_pub);
  265. //}
  266. char buf[50];
  267. sprintf(buf, "MQTT IN: setPreset to %s", cmdPayload);
  268. sendLog(buf, LOGLEVEL_INFO);
  269. }
  270. cmdInQueue = false; // payload is processed in "commands"
  271. } //if topic = mqtt_topic_in_setPreset
  272. #endif // Thermostat
  273. // outside temp/hum via MQTT
  274. if (strcmp(topic, confAdd.outTemp_topic_in) == 0) {
  275. int len;
  276. if (length < 6)
  277. len = length; // if input is bigger than dest buffer, cut
  278. else
  279. len = 5;
  280. for (int i = 0; i < len; i++)
  281. {
  282. outTemp_newValue[i] = (char)payload[i];
  283. }
  284. //outTemp_newValue[len + 1] = '\0';
  285. outTemp_newValue[len] = '\0';
  286. outTemp_parseNewValue = true;
  287. } //if topic = outTemp_topic_in
  288. if (strcmp(topic, confAdd.outHum_topic_in) == 0) {
  289. int len;
  290. if (length < 4)
  291. len = length; // if input is bigger than dest buffer, cut
  292. else
  293. len = 3;
  294. for (int i = 0; i < len; i++)
  295. {
  296. outHum_newValue[i] = (char)payload[i];
  297. }
  298. //outHum_newValue[len + 1] = '\0';
  299. outHum_newValue[len] = '\0';
  300. outHum_parseNewValue = true;
  301. } //if topic = outHum_topic_in
  302. } //mqttCallback
  303. void mqttPrepareSubscribeTopics()
  304. {
  305. //char tmp_topic_out[50];
  306. sprintf(mqtt_topic_in_cmd, "%s/%s", confMqtt.mqtt_topic_in, "cmd");
  307. #ifdef FIRMWARE_VARIANT_THERMOSTAT
  308. sprintf(mqtt_topic_in_setTemp, "%s/%s", mqtt_topic_in_cmd, "setTemp");
  309. sprintf(mqtt_topic_in_setMode, "%s/%s", mqtt_topic_in_cmd, "setMode");
  310. sprintf(mqtt_topic_in_setPreset, "%s/%s", mqtt_topic_in_cmd, "setPreset");
  311. sprintf(mqtt_topic_in_setPause, "%s/%s", mqtt_topic_in_cmd, "setPause");
  312. #endif
  313. }
  314. bool mqttReconnect(void)
  315. {
  316. mqttclient.disconnect();
  317. delay(10);
  318. // Create MQTT client ID from device name
  319. //String mqttClientId = "ESP8266Client-";
  320. String mqttClientId = FIRMWARE_SHORTNAME;
  321. mqttClientId += "-";
  322. //mqttClientId += String(random(0xffff), HEX); //or random
  323. mqttClientId += String(confDevWiFi.deviceName);
  324. //if (serialdebug)
  325. // Serial.print(F("MQTT: connecting to broker '"));
  326. // Serial.print(confMqtt.mqtt_server);
  327. // Serial.print(F("' with "));
  328. boolean connRes;
  329. mqttReconnectAttempts++;
  330. char connectMode[20];
  331. if (strlen(confSecrets.mqtt_user) > 0 && strlen(confMqtt.mqtt_willTopic) == 0)
  332. {
  333. // user and password, no Last Will
  334. //if (serialdebug)
  335. // Serial.print(F("Auth, no LWT"));
  336. strlcpy(connectMode, "Auth, no LWT", sizeof(connectMode));
  337. connRes = mqttclient.connect(mqttClientId.c_str(), confSecrets.mqtt_user, confSecrets.mqtt_pass);
  338. }
  339. else if (strlen(confSecrets.mqtt_user) > 0 && strlen(confMqtt.mqtt_willTopic) > 0)
  340. {
  341. // user, password and Last Will
  342. //if (serialdebug)
  343. // Serial.print(F("Auth and LWT"));
  344. strlcpy(connectMode, "Auth and LWT", sizeof(connectMode));
  345. connRes = mqttclient.connect(mqttClientId.c_str(), confSecrets.mqtt_user, confSecrets.mqtt_pass, confMqtt.mqtt_willTopic, confMqtt.mqtt_willQos, confMqtt.mqtt_willRetain, confMqtt.mqtt_willMsg);
  346. }
  347. else if (strlen(confSecrets.mqtt_user) == 0 && strlen(confMqtt.mqtt_willTopic) > 0)
  348. {
  349. // Last Will but no user and password
  350. //if (serialdebug)
  351. // Serial.print(F("LWT, no Auth"));
  352. strlcpy(connectMode, "LWT, no Auth", sizeof(connectMode));
  353. connRes = mqttclient.connect(mqttClientId.c_str(), confMqtt.mqtt_willTopic, confMqtt.mqtt_willQos, confMqtt.mqtt_willRetain, confMqtt.mqtt_willMsg);
  354. }
  355. else
  356. {
  357. // no user, password and no Last Will
  358. //if (serialdebug)
  359. // Serial.print(F("no Auth, no LWT"));
  360. strlcpy(connectMode, "no Auth, no LWT", sizeof(connectMode));
  361. connRes = mqttclient.connect(mqttClientId.c_str());
  362. }
  363. //if (serialdebug)
  364. //{
  365. // Serial.print(F(", attempt: "));
  366. // Serial.print(mqttReconnectAttempts);
  367. // Serial.println();
  368. //}
  369. snprintf(logBuf, LOG_BUFFER_SIZE, "MQTT: connecting to %s:%u w/ %s, attempt: %u", confMqtt.mqtt_server, confMqtt.mqtt_port, connectMode, mqttReconnectAttempts);
  370. sendLog(logBuf, LOGLEVEL_INFO);
  371. if (connRes)
  372. { // if connection was successful
  373. // if (serialdebug)
  374. // {
  375. // Serial.print(F("MQTT: connected. Reconnects: "));
  376. // Serial.println(mqtt_reconnects);
  377. // }
  378. //char logBuf2[50];
  379. //sprintf(logBuf2, "MQTT: connected to %s:%u, Reconnects: %u", confMqtt.mqtt_server, confMqtt.mqtt_port, mqtt_reconnects);
  380. //sendLog(logBuf2, LOGLEVEL_INFO);
  381. //sendLog(F("MQTT: connected. Reconnects: "), LOGLEVEL_INFO);
  382. mqtt_connected = true;
  383. mqtt_reconnects++;
  384. mqttOnConnect();
  385. //if (serialdebug)
  386. //Serial.println("MQTT: subscribed topics:");
  387. sendLog("MQTT: subscribed topics:", LOGLEVEL_INFO);
  388. if (strlen(mqtt_topic_in_cmd) > 0)
  389. {
  390. char mqtt_topic_in_subscribe[52];
  391. sprintf(mqtt_topic_in_subscribe, "%s/%s", mqtt_topic_in_cmd, "#");
  392. if (mqttclient.subscribe(mqtt_topic_in_subscribe))
  393. {
  394. //if (serialdebug) {
  395. // Serial.print(" ");
  396. // Serial.println(mqtt_topic_in_subscribe);
  397. //}
  398. char buf[60];
  399. sprintf(buf, " %s", mqtt_topic_in_subscribe);
  400. sendLog(buf, LOGLEVEL_INFO);
  401. mqttInTopicSubscribed = true;
  402. }
  403. }
  404. if (strlen(confAdd.outTemp_topic_in) > 0)
  405. {
  406. if (mqttclient.subscribe(confAdd.outTemp_topic_in))
  407. {
  408. //if (serialdebug) {
  409. // Serial.print(" ");
  410. // Serial.println(confAdd.outTemp_topic_in);
  411. //}
  412. char buf[60];
  413. sprintf(buf, " %s", confAdd.outTemp_topic_in);
  414. sendLog(buf, LOGLEVEL_INFO);
  415. }
  416. }
  417. if (strlen(confAdd.outHum_topic_in) > 0)
  418. {
  419. if (mqttclient.subscribe(confAdd.outHum_topic_in))
  420. {
  421. //if (serialdebug) {
  422. // Serial.print(" ");
  423. // Serial.println(confAdd.outHum_topic_in);
  424. //}
  425. char buf[60];
  426. sprintf(buf, " %s", confAdd.outHum_topic_in);
  427. sendLog(buf, LOGLEVEL_INFO);
  428. }
  429. }
  430. mqttReconnectAttempts = 0;
  431. return mqttclient.connected();
  432. }
  433. else {
  434. int mqttConnRes = mqttclient.state();
  435. mqtt_updateCurrentStateName();
  436. sprintf_P(logBuf, "%s: %s, rc=%d (%s)", PGMStr_MQTT, PGMStr_connectedFailed, mqttConnRes, mqttCurrentStateName);
  437. sendLog(logBuf, LOGLEVEL_INFO);
  438. if (mqttReconnectAttempts >= 3 && (mqttConnRes == 4 || mqttConnRes == 5))
  439. {
  440. // MQTT credentials are invalid/rejected from the server - stop trying to reconnect until reboot
  441. mqtt_tempDisabled_credentialError = true;
  442. if (confLog.logLevelSerial >= LOGLEVEL_VERBOSE)
  443. {
  444. //Serial.println(F("MQTT disabled until reboot due to credential error"));
  445. sendLog(F("MQTT disabled until reboot due to credential error"), LOGLEVEL_ERROR);
  446. }
  447. }
  448. mqtt_connected = false;
  449. mqttOnDisconnect();
  450. return mqttclient.connected();
  451. }
  452. } //mqttReconnect
  453. void mqttClientInit()
  454. {
  455. if (confMqtt.mqtt_enable)
  456. {
  457. mqttclient.setServer(confMqtt.mqtt_server, confMqtt.mqtt_port);
  458. mqttclient.setCallback(mqttCallback);
  459. mqttLastReconnectAttempt = 0;
  460. mqttReconnectAttempts = 0;
  461. mqtt_tempDisabled_credentialError = false;
  462. snprintf(mqtt_topic_log, 50, "%s/%s", confMqtt.mqtt_topic_in, "log");
  463. }
  464. }
  465. int _lastWifiStatus;
  466. void mqttHandleConnection()
  467. {
  468. if (mqtt_heartbeatReceived)
  469. {
  470. mqtt_heartbeatReceived = false;
  471. sendLog(F("MQTT: received HEARTBEAT - resetting timer..."), LOGLEVEL_VERBOSE);
  472. }
  473. int _currWifiStatus = WiFi.status();
  474. if (_currWifiStatus != _lastWifiStatus)
  475. {
  476. _lastWifiStatus = _currWifiStatus;
  477. //Serial.print("WiFi status changed to: ");
  478. //Serial.println(_currWifiStatus);
  479. }
  480. if (confMqtt.mqtt_enable && !mqtt_tempDisabled_credentialError && _currWifiStatus == WL_CONNECTED)
  481. {
  482. // MQTT reconnect if not connected (nonblocking)
  483. boolean _doReconnect = false;
  484. if (!mqttclient.connected())
  485. _doReconnect = true;
  486. if (mqttInTopicSubscribed && confMqtt.mqtt_heartbeat_maxage_reconnect > 0)
  487. { // if mqtt_topic_in is subscribed
  488. unsigned long _maxage_reconn = confMqtt.mqtt_heartbeat_maxage_reconnect * 60000;
  489. if (confMqtt.mqtt_enable_heartbeat && confMqtt.mqtt_heartbeat_maxage_reconnect > 0 && ((millis() - mqtt_lastHeartbeat) > _maxage_reconn))
  490. { // also reconnect if no HEARTBEAT was received for some time
  491. _doReconnect = true;
  492. mqtt_connected = false;
  493. mqtt_lastHeartbeat = millis();
  494. //Serial.println(F("MQTT: HEARTBEAT overdue. Force-Reconnecting MQTT..."));
  495. sendLog(F("MQTT: HEARTBEAT overdue. Force-Reconnecting MQTT..."), LOGLEVEL_WARN);
  496. }
  497. }
  498. if (_doReconnect)
  499. {
  500. unsigned long mqttReconnectAttemptDelay;
  501. if (mqttReconnectAttempts < 3)
  502. mqttReconnectAttemptDelay = MQTT_RECONNECT_INTERVAL_3_TRIES; // if this is the 1-3rd attempt, try again in 15s
  503. else if (mqttReconnectAttempts < 10)
  504. mqttReconnectAttemptDelay = MQTT_RECONNECT_INTERVAL_10_TRIES; // if more than 3 attempts failed, try again every min
  505. else
  506. mqttReconnectAttemptDelay = MQTT_RECONNECT_INTERVAL_LONG; // if more than 10 attempts failed, try again every 5 min
  507. unsigned long _maxage_reboot = confMqtt.mqtt_heartbeat_maxage_reboot * 60000;
  508. if (confMqtt.mqtt_enable_heartbeat && confMqtt.mqtt_heartbeat_maxage_reboot > 0 && ((millis() - mqtt_lastHeartbeat) > _maxage_reboot))
  509. {
  510. // if no heartbeat was received for set time, reboot the ESP
  511. //Serial.println(F("MQTT: HEARTBEAT_MAXAGE_REBOOT overdue. Restarting..."));
  512. sendLog(F("MQTT: HEARTBEAT_MAXAGE_REBOOT overdue. Restarting..."), LOGLEVEL_WARN);
  513. restart();
  514. }
  515. if ((millis() - mqttLastReconnectAttempt) > mqttReconnectAttemptDelay)
  516. {
  517. mqttLastReconnectAttempt = millis();
  518. //#ifdef USE_MQTT_TLS
  519. // verifytls();
  520. //#endif
  521. mqttReconnect();
  522. }
  523. mqttclient.loop();
  524. }
  525. else
  526. {
  527. mqttclient.loop();
  528. }
  529. }
  530. }
  531. void mqtt_publishStatus()
  532. {
  533. if (confMqtt.mqtt_enable && mqttclient.state() == 0)
  534. {
  535. char outMsg[60];
  536. sprintf_P(outMsg, "%s: %s: %s:%u, %s: %d", PGMStr_MQTT, PGMStr_connectedTo, confMqtt.mqtt_server, confMqtt.mqtt_port, PGMStr_reconnects, mqtt_reconnects - 1);
  537. //mqttclient.publish(confMqtt.mqtt_topic_out, outMsg, confMqtt.mqtt_outRetain);
  538. sendLog(outMsg, LOGLEVEL_INFO);
  539. }
  540. }
  541. void mqttOnConnect()
  542. {
  543. mqtt_publishConnectMsg();
  544. mqtt_publishStatus();
  545. #ifdef ENABLE_LCD_I2C
  546. if(!confMqtt.mqtt_reconnect_silent || mqtt_reconnects <= 1) {
  547. display_showMQTTConnected();
  548. }
  549. #endif
  550. }
  551. void mqttOnDisconnect()
  552. {
  553. #ifdef ENABLE_LCD_I2C
  554. if(!confMqtt.mqtt_reconnect_silent || mqtt_reconnects <= 1) {
  555. display_showMQTTConnectionError();
  556. }
  557. #endif
  558. }
  559. void mqtt_publishConnectMsg()
  560. {
  561. if (strlen(confMqtt.mqtt_willTopic) > 4)
  562. {
  563. if (confMqtt.mqtt_enable && mqttclient.state() == 0)
  564. {
  565. mqttclient.publish(confMqtt.mqtt_willTopic, confMqtt.mqtt_connMsg, confMqtt.mqtt_willRetain);
  566. //sendLog(F("MQTT: connected"), LOGLEVEL_INFO);
  567. }
  568. }
  569. }
  570. void mqttPublishHeartbeat()
  571. {
  572. if (confMqtt.mqtt_enable && confMqtt.mqtt_enable_heartbeat && mqttclient.state() == 0)
  573. {
  574. mqttclient.publish(mqtt_topic_in_cmd, "HEARTBEAT", false); // publishes to IN-topic. MQTT will force-reconnect if it does not get a HEARTBEAT for 2 min
  575. }
  576. }
  577. void mqtt_updateCurrentStateName()
  578. {
  579. if (confMqtt.mqtt_enable)
  580. {
  581. sprintf_P(mqttCurrentStateName, "%s", PGMStr_MQTTStates[mqttclient.state() + 4]);
  582. }
  583. else
  584. sprintf_P(mqttCurrentStateName, "%s", PGMStr_MQTTState_DIS);
  585. }
  586. void mqttResetConnection()
  587. {
  588. sendLog(F("MQTT: resetting connection..."));
  589. if (!confMqtt.mqtt_enable)
  590. mqttclient.disconnect();
  591. else
  592. {
  593. mqttclient.disconnect();
  594. mqttPrepareSubscribeTopics();
  595. mqttClientInit();
  596. }
  597. configChangedMqttConnResetRequired = false;
  598. }