mqtt.ino 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. #include <string.h>
  2. #include <ctype.h>
  3. char *strlwr(char *str) {
  4. unsigned char *p = (unsigned char *)str;
  5. while (*p) {
  6. *p = tolower((unsigned char) * p);
  7. p++;
  8. }
  9. return str;
  10. }
  11. // MQTT callback
  12. void mqttCallback(char* topic, byte* payload, unsigned int length) {
  13. // Serial.print("MQTT payload arrived [");
  14. // Serial.print(topic);
  15. // Serial.print("] ");
  16. // for (int i = 0; i < length; i++) {
  17. // Serial.print((char)payload[i]);
  18. // }
  19. // Serial.println();
  20. char tmp_topic_pub[51];
  21. char tmp_payload_pub[51];
  22. if (strcmp(topic, mqtt_topic_in_cmd) == 0) { //if topic = mqtt_topic_in_cmd
  23. int len;
  24. if (length < 101) len = length; // if input is bigger than dest buffer, cut
  25. else len = 100;
  26. for (int i = 0; i < len; i++) {
  27. cmdPayload[i] = (char)payload[i];
  28. }
  29. cmdPayload[len] = '\0';
  30. // Serial.print("cmdPayload:");
  31. // Serial.println(cmdPayload);
  32. if (serialdebug) {
  33. Serial.print("received MQTT ");
  34. Serial.print(mqtt_topic_in_cmd);
  35. Serial.print(" - \"");
  36. Serial.print(cmdPayload);
  37. Serial.println("\"");
  38. }
  39. if (mqttdebug) {
  40. sprintf(tmp_topic_pub, "%s/%s", mqtt_topic_out, "mqtt_received");
  41. sprintf(tmp_payload_pub, "%s: %s", mqtt_topic_in_cmd, cmdPayload);
  42. mqttclient.publish(tmp_topic_pub, tmp_payload_pub);
  43. }
  44. if (strncmp(cmdPayload, "HEARTBEAT", 9) == 0) {
  45. Serial.println("resetting HEARTBEAT");
  46. mqttLastHeartbeat = millis();
  47. mqttConnected = true;
  48. }
  49. else {
  50. cmdInQueue = true; // payload is processed in "commands"
  51. }
  52. }//if topic = mqtt_topic_in_cmd
  53. if (strcmp(topic, mqtt_topic_in_setTemp) == 0) { //if topic = mqtt_topic_in_setTemp
  54. int len;
  55. if (length < 101) len = length; // if input is bigger than dest buffer, cut
  56. else len = 100;
  57. for (int i = 0; i < len; i++) {
  58. cmdPayload[i] = (char)payload[i];
  59. }
  60. //cmdPayload[len + 1] = '\0';
  61. cmdPayload[len] = '\0';
  62. // Serial.print("cmdPayload:");
  63. // Serial.println(cmdPayload);
  64. char tmpPayload[11];
  65. strlcpy(tmpPayload, cmdPayload, 10);
  66. float valueFloat;
  67. valueFloat = round(atof(tmpPayload) * 2.0) / 2.0;
  68. setTempTo(valueFloat);
  69. if (serialdebug) {
  70. Serial.print("received MQTT ");
  71. Serial.print(mqtt_topic_in_setTemp);
  72. Serial.print(" - \"");
  73. Serial.print(cmdPayload);
  74. Serial.println("\"");
  75. }
  76. if (mqttdebug) {
  77. sprintf(tmp_topic_pub, "%s/%s", mqtt_topic_out, "mqtt_received");
  78. sprintf(tmp_payload_pub, "%s: %s", mqtt_topic_in_setTemp, cmdPayload);
  79. mqttclient.publish(tmp_topic_pub, tmp_payload_pub);
  80. }
  81. cmdInQueue = false; // payload is processed in "commands"
  82. }//if topic = mqtt_topic_in_setTemp
  83. if (strcmp(topic, mqtt_topic_in_setMode) == 0) { //if topic = mqtt_topic_in_setMode
  84. int len;
  85. if (length < 101) len = length; // if input is bigger than dest buffer, cut
  86. else len = 100;
  87. for (int i = 0; i < len; i++) {
  88. cmdPayload[i] = (char)payload[i];
  89. }
  90. //cmdPayload[len + 1] = '\0';
  91. cmdPayload[len] = '\0';
  92. // Serial.print("cmdPayload:");
  93. // Serial.println(cmdPayload);
  94. char tmpPayload[21];
  95. strlcpy(tmpPayload, cmdPayload, 20);
  96. strlwr(tmpPayload);
  97. byte tmpHeatMode;
  98. char tmpModename0[15];
  99. char tmpModename1[15];
  100. strlcpy(tmpModename0, modename0, 14);
  101. strlcpy(tmpModename1, modename1, 14);
  102. strlwr(tmpModename0);
  103. strlwr(tmpModename1);
  104. if (strcmp(tmpPayload, tmpModename0) == 0) tmpHeatMode = 0;
  105. else if (strcmp(tmpPayload, tmpModename1) == 0) tmpHeatMode = 1;
  106. else if (strcmp(tmpPayload, "off") == 0) tmpHeatMode = 0;
  107. else if (strcmp(tmpPayload, "aus") == 0) tmpHeatMode = 0;
  108. else if (strcmp(tmpPayload, "on") == 0) tmpHeatMode = 1;
  109. else if (strcmp(tmpPayload, "ein") == 0) tmpHeatMode = 1;
  110. else if (atoi(tmpPayload) == 0) tmpHeatMode = 0;
  111. else if (atoi(tmpPayload) == 1) tmpHeatMode = 1;
  112. if (serialdebug) {
  113. Serial.print("set heatmode to: ");
  114. Serial.println(tmpHeatMode);
  115. }
  116. setHeatingmodeTo(tmpHeatMode);
  117. if (serialdebug) {
  118. Serial.print("received MQTT ");
  119. Serial.print(mqtt_topic_in_setMode);
  120. Serial.print(" - \"");
  121. Serial.print(cmdPayload);
  122. Serial.println("\"");
  123. }
  124. if (mqttdebug) {
  125. sprintf(tmp_topic_pub, "%s/%s", mqtt_topic_out, "mqtt_received");
  126. sprintf(tmp_payload_pub, "%s: %s", mqtt_topic_in_setMode, cmdPayload);
  127. mqttclient.publish(tmp_topic_pub, tmp_payload_pub);
  128. }
  129. cmdInQueue = false; // payload is processed in "commands"
  130. }//if topic = mqtt_topic_in_setMode
  131. if (strcmp(topic, mqtt_topic_in_setPreset) == 0) { //if topic = mqtt_topic_in_setPreset
  132. int len;
  133. if (length < 101) len = length; // if input is bigger than dest buffer, cut
  134. else len = 100;
  135. for (int i = 0; i < len; i++) {
  136. cmdPayload[i] = (char)payload[i];
  137. }
  138. //cmdPayload[len + 1] = '\0';
  139. cmdPayload[len] = '\0';
  140. // Serial.print("cmdPayload:");
  141. // Serial.println(cmdPayload);
  142. char tmpPayload[21];
  143. strlcpy(tmpPayload, cmdPayload, 20);
  144. strlwr(tmpPayload);
  145. byte tmpPreset;
  146. char tmpPresetName0[15];
  147. char tmpPresetName1[15];
  148. char tmpPresetName2[15];
  149. strlcpy(tmpPresetName0, psetname0, 14);
  150. strlcpy(tmpPresetName1, psetname1, 14);
  151. strlcpy(tmpPresetName2, psetname2, 14);
  152. strlwr(tmpPresetName0);
  153. strlwr(tmpPresetName1);
  154. strlwr(tmpPresetName2);
  155. if (strcmp(tmpPayload, tmpPresetName0) == 0) tmpPreset = 0;
  156. else if (strcmp(tmpPayload, tmpPresetName1) == 0) tmpPreset = 1;
  157. else if (strcmp(tmpPayload, tmpPresetName2) == 0) tmpPreset = 2;
  158. else if (strcmp(tmpPayload, "none") == 0) tmpPreset = 0;
  159. else if (strcmp(tmpPayload, "red1") == 0) tmpPreset = 1;
  160. else if (strcmp(tmpPayload, "red2") == 0) tmpPreset = 2;
  161. else if (atoi(tmpPayload) == 0) tmpPreset = 0;
  162. else if (atoi(tmpPayload) == 1) tmpPreset = 1;
  163. else if (atoi(tmpPayload) == 2) tmpPreset = 2;
  164. if (serialdebug) {
  165. Serial.print("set preset to: ");
  166. Serial.println(tmpPreset);
  167. }
  168. setPresetTo(tmpPreset);
  169. if (serialdebug) {
  170. Serial.print("received MQTT ");
  171. Serial.print(mqtt_topic_in_setPreset);
  172. Serial.print(" - \"");
  173. Serial.print(cmdPayload);
  174. Serial.println("\"");
  175. }
  176. if (mqttdebug) {
  177. sprintf(tmp_topic_pub, "%s/%s", mqtt_topic_out, "mqtt_received");
  178. sprintf(tmp_payload_pub, "%s: %s", mqtt_topic_in_setPreset, cmdPayload);
  179. mqttclient.publish(tmp_topic_pub, tmp_payload_pub);
  180. }
  181. cmdInQueue = false; // payload is processed in "commands"
  182. }//if topic = mqtt_topic_in_setPreset
  183. if (strcmp(topic, outTemp_topic_in) == 0) { //if topic = outTemp_topic_in
  184. int len;
  185. if (length < 6) len = length; // if input is bigger than dest buffer, cut
  186. else len = 5;
  187. for (int i = 0; i < len; i++) {
  188. outTemp_newValue[i] = (char)payload[i];
  189. }
  190. //outTemp_newValue[len + 1] = '\0';
  191. outTemp_newValue[len] = '\0';
  192. outTemp_parseNewValue = true;
  193. }//if topic = outTemp_topic_in
  194. if (strcmp(topic, outHum_topic_in) == 0) { //if topic = outHum_topic_in
  195. int len;
  196. if (length < 4) len = length; // if input is bigger than dest buffer, cut
  197. else len = 3;
  198. for (int i = 0; i < len; i++) {
  199. outHum_newValue[i] = (char)payload[i];
  200. }
  201. //outHum_newValue[len + 1] = '\0';
  202. outHum_newValue[len] = '\0';
  203. outHum_parseNewValue = true;
  204. }//if topic = outHum_topic_in
  205. }//mqttCallback
  206. void mqttPrepareSubscribeTopics() {
  207. //char tmp_topic_out[50];
  208. sprintf(mqtt_topic_in_cmd, "%s/%s", mqtt_topic_in, "cmd");
  209. sprintf(mqtt_topic_in_setTemp, "%s/%s", mqtt_topic_in_cmd, "setTemp");
  210. sprintf(mqtt_topic_in_setMode, "%s/%s", mqtt_topic_in_cmd, "setMode");
  211. sprintf(mqtt_topic_in_setPreset, "%s/%s", mqtt_topic_in_cmd, "setPreset");
  212. }
  213. boolean mqttReconnect() {
  214. mqttclient.disconnect();
  215. delay(10);
  216. // Create MQTT client ID from device name
  217. String mqttClientId = "ESP8266Client-";
  218. //mqttClientId += String(random(0xffff), HEX); //or random
  219. mqttClientId += String(deviceName);
  220. if (serialdebug) Serial.print("connecting to MQTT broker with ");
  221. boolean connRes;
  222. mqttReconnectAttempts++;
  223. if (strlen(mqtt_user) > 0 && strlen(mqtt_willTopic) == 0) {
  224. // user and password, no Last Will
  225. if (serialdebug) Serial.println("user and password, no Last Will");
  226. connRes = mqttclient.connect(mqttClientId.c_str(), mqtt_user, mqtt_pass);
  227. }
  228. else if (strlen(mqtt_user) > 0 && strlen(mqtt_willTopic) > 0) {
  229. // user, password and Last Will
  230. if (serialdebug) Serial.println("user, password and Last Will");
  231. connRes = mqttclient.connect(mqttClientId.c_str(), mqtt_user, mqtt_pass, mqtt_willTopic, mqtt_willQos, mqtt_willRetain, mqtt_willMsg);
  232. }
  233. else if (strlen(mqtt_user) == 0 && strlen(mqtt_willTopic) > 0) {
  234. // Last Will but no user and password
  235. if (serialdebug) Serial.println("Last Will, no user and password");
  236. connRes = mqttclient.connect(mqttClientId.c_str(), mqtt_willTopic, mqtt_willQos, mqtt_willRetain, mqtt_willMsg);
  237. }
  238. else {
  239. // no user, password and no Last Will
  240. if (serialdebug) Serial.println("no user, password and no Last Will");
  241. connRes = mqttclient.connect(mqttClientId.c_str());
  242. }
  243. if (serialdebug) {
  244. Serial.print("... attempt: ");
  245. Serial.print(mqttReconnectAttempts);
  246. Serial.println();
  247. }
  248. if (connRes) { // if connection was successful
  249. if (serialdebug) {
  250. Serial.print("MQTT connected. Reconnects: ");
  251. Serial.println(mqttReconnects);
  252. }
  253. mqttConnected = true;
  254. mqttReconnects++;
  255. mqttOnConnect();
  256. if (serialdebug) Serial.println("Subscribed to:");
  257. if (strlen(mqtt_topic_in_cmd) > 0) {
  258. char mqtt_topic_in_subscribe[52];
  259. sprintf(mqtt_topic_in_subscribe, "%s/%s", mqtt_topic_in_cmd, "#");
  260. if (mqttclient.subscribe(mqtt_topic_in_subscribe)) {
  261. if (serialdebug) Serial.println(mqtt_topic_in_subscribe);
  262. mqttInTopicSubscribed = true;
  263. }
  264. }
  265. if (strlen(outTemp_topic_in) > 0) {
  266. if (mqttclient.subscribe(outTemp_topic_in)) {
  267. if (serialdebug) Serial.println(outTemp_topic_in);
  268. }
  269. }
  270. if (strlen(outHum_topic_in) > 0) {
  271. if (mqttclient.subscribe(outHum_topic_in)) {
  272. if (serialdebug) Serial.println(outHum_topic_in);
  273. }
  274. }
  275. mqttReconnectAttempts = 0;
  276. return mqttclient.connected();
  277. }
  278. else {
  279. int mqttConnRes = mqttclient.state();
  280. if (serialdebug) {
  281. Serial.print("MQTT connect FAILED, rc=");
  282. Serial.print(mqttConnRes);
  283. Serial.print(" (");
  284. switch(mqttConnRes) {
  285. case -4:
  286. Serial.print(F("MQTT_CONNECTION_TIMEOUT"));
  287. break;
  288. case -3:
  289. Serial.print(F("MQTT_CONNECTION_LOST"));
  290. break;
  291. case -2:
  292. Serial.print(F("MQTT_CONNECT_FAILED"));
  293. break;
  294. case -1:
  295. Serial.print(F("MQTT_DISCONNECTED"));
  296. break;
  297. case 0:
  298. Serial.print(F("MQTT_CONNECTED"));
  299. break;
  300. case 1:
  301. Serial.print(F("MQTT_CONNECT_BAD_PROTOCOL"));
  302. break;
  303. case 2:
  304. Serial.print(F("MQTT_CONNECT_BAD_CLIENT_ID"));
  305. break;
  306. case 3:
  307. Serial.print(F("MQTT_CONNECT_UNAVAILABLE"));
  308. break;
  309. case 4:
  310. Serial.print(F("MQTT_CONNECT_BAD_CREDENTIALS"));
  311. break;
  312. case 5:
  313. Serial.print(F("MQTT_CONNECT_UNAUTHORIZED"));
  314. break;
  315. }
  316. Serial.println(")");
  317. }
  318. if (mqttReconnectAttempts >= 3 && (mqttConnRes == 4 || mqttConnRes == 5)) {
  319. // MQTT credentials are invalid/rejected from the server - stop trying to reconnect until reboot
  320. mqtt_tempDisabled_credentialError = true;
  321. if(serialdebug) {
  322. Serial.println(F("MQTT disabled until reboot due to credential error"));
  323. }
  324. }
  325. mqttConnected = false;
  326. mqttOnDisconnect();
  327. }
  328. } //mqttReconnect
  329. void mqttClientInit() {
  330. if (mqtt_enable) {
  331. mqttclient.setServer(mqtt_server, mqtt_port);
  332. mqttclient.setCallback(mqttCallback);
  333. mqttLastReconnectAttempt = 0;
  334. mqttReconnectAttempts = 0;
  335. mqtt_tempDisabled_credentialError = false;
  336. }
  337. }
  338. int lastWifiStatus;
  339. void mqttHandleConnection() {
  340. int currWifiStatus = WiFi.status();
  341. if ( currWifiStatus != lastWifiStatus ) {
  342. lastWifiStatus = currWifiStatus;
  343. Serial.print("WiFi status changed to: ");
  344. Serial.println(currWifiStatus);
  345. }
  346. if ( mqtt_enable && !mqtt_tempDisabled_credentialError && currWifiStatus == WL_CONNECTED ) {
  347. // MQTT reconnect if not connected (nonblocking)
  348. boolean doReconnect = false;
  349. if (!mqttclient.connected()) doReconnect = true;
  350. if (mqttInTopicSubscribed && mqtt_heartbeat_maxage_reconnect > 0) { // if mqtt_topic_in is subscribed
  351. if ( (millis() - mqttLastHeartbeat) > mqtt_heartbeat_maxage_reconnect ) { // also reconnect if no HEARTBEAT was received for some time
  352. doReconnect = true;
  353. mqttConnected = false;
  354. mqttLastHeartbeat = millis();
  355. Serial.println("MQTT HEARTBEAT overdue. Force-Reconnecting MQTT...");
  356. }
  357. }
  358. if (doReconnect) {
  359. unsigned int mqttReconnectAttemptDelay;
  360. if (mqttReconnectAttempts < 3) mqttReconnectAttemptDelay = 15000; // if this is the 1-3rd attempt, try again in 15s
  361. else if (mqttReconnectAttempts < 10) mqttReconnectAttemptDelay = 60000; // if more than 3 attempts failed, try again every min
  362. else mqttReconnectAttemptDelay = 300000; // if more than 10 attempts failed, try again every 5 min
  363. if ( mqtt_heartbeat_maxage_reboot > 0 && (millis() - mqttLastHeartbeat) > mqtt_heartbeat_maxage_reboot) {
  364. // if no heartbeat was received for set time, reboot the ESP
  365. delay(100);
  366. ESP.restart();
  367. }
  368. if ((millis() - mqttLastReconnectAttempt) > mqttReconnectAttemptDelay) {
  369. mqttLastReconnectAttempt = millis();
  370. mqttReconnect();
  371. }
  372. mqttclient.loop();
  373. }
  374. else {
  375. mqttclient.loop();
  376. }
  377. }
  378. }
  379. void mqttPublishStatus() {
  380. char outMsg[60];
  381. if (mqtt_enable && mqttclient.state() == 0) {
  382. sprintf(outMsg, "MQTT connected, reconnects: %d, uptime: %s, free_heap: %d", mqttReconnects - 1, uptimeStr, ESP.getFreeHeap());
  383. mqttclient.publish(mqtt_topic_out, outMsg, mqtt_outRetain);
  384. }
  385. }
  386. void mqttSendLog(char* payload) {
  387. if (mqtt_enable && mqttclient.state() == 0) {
  388. char buf[101];
  389. strlcpy(buf, payload, 101);
  390. Serial.println(buf);
  391. mqttclient.publish(mqtt_topic_out, buf, mqtt_outRetain);
  392. yield();
  393. }
  394. }
  395. void mqttOnConnect() {
  396. mqttPublishConnectMsg();
  397. mqttPublishStatus();
  398. displayShowMQTTConnected();
  399. }
  400. void mqttOnDisconnect() {
  401. displayShowMQTTConnectionError();
  402. }
  403. void mqttPublishConnectMsg() {
  404. if (strlen(mqtt_willTopic) > 4) {
  405. if (mqtt_enable && mqttclient.state() == 0) {
  406. mqttclient.publish(mqtt_willTopic, mqtt_connMsg, mqtt_willRetain);
  407. }
  408. }
  409. }
  410. void mqttPublishHeartbeat() {
  411. if (mqtt_enable && mqttclient.state() == 0) {
  412. mqttclient.publish(mqtt_topic_in_cmd, "HEARTBEAT"); // publishes to IN-topic. MQTT will force-reconnect if it does not get a HEARTBEAT for 2 min
  413. }
  414. }