mqtt.ino 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520
  1. // MQTT callback
  2. void mqttCallback(char* topic, byte* payload, unsigned int length) {
  3. // Serial.print("MQTT payload arrived [");
  4. // Serial.print(topic);
  5. // Serial.print("] ");
  6. // for (int i = 0; i < length; i++) {
  7. // Serial.print((char)payload[i]);
  8. // }
  9. // Serial.println();
  10. char tmp_topic_pub[51];
  11. char tmp_payload_pub[51];
  12. if (strcmp(topic, mqtt_topic_in_cmd) == 0) { //if topic = mqtt_topic_in_cmd
  13. int len;
  14. if (length < 101) len = length; // if input is bigger than dest buffer, cut
  15. else len = 100;
  16. for (int i = 0; i < len; i++) {
  17. cmdPayload[i] = (char)payload[i];
  18. }
  19. //cmdPayload[len + 1] = '\0';
  20. cmdPayload[len] = '\0';
  21. // Serial.print("cmdPayload:");
  22. // Serial.println(cmdPayload);
  23. if (serialdebug) {
  24. Serial.print("received MQTT ");
  25. Serial.print(mqtt_topic_in_cmd);
  26. Serial.print(" - \"");
  27. Serial.print(cmdPayload);
  28. Serial.println("\"");
  29. }
  30. if (mqttdebug) {
  31. sprintf(tmp_topic_pub, "%s/%s", mqtt_topic_out, "mqtt_received");
  32. sprintf(tmp_payload_pub, "%s: %s", mqtt_topic_in_cmd, cmdPayload);
  33. mqttclient.publish(tmp_topic_pub, tmp_payload_pub);
  34. }
  35. cmdInQueue = true; // payload is processed in "commands"
  36. }//if topic = mqtt_topic_in_cmd
  37. if (strcmp(topic, mqtt_topic_in_setTemp) == 0) { //if topic = mqtt_topic_in_setTemp
  38. int len;
  39. if (length < 101) len = length; // if input is bigger than dest buffer, cut
  40. else len = 100;
  41. for (int i = 0; i < len; i++) {
  42. cmdPayload[i] = (char)payload[i];
  43. }
  44. //cmdPayload[len + 1] = '\0';
  45. cmdPayload[len] = '\0';
  46. // Serial.print("cmdPayload:");
  47. // Serial.println(cmdPayload);
  48. char tmpPayload[11];
  49. strlcpy(tmpPayload, cmdPayload, 10);
  50. float valueFloat;
  51. valueFloat = round(atof(tmpPayload) * 2.0) / 2.0;
  52. setTempTo(valueFloat);
  53. if (serialdebug) {
  54. Serial.print("received MQTT ");
  55. Serial.print(mqtt_topic_in_setTemp);
  56. Serial.print(" - \"");
  57. Serial.print(cmdPayload);
  58. Serial.println("\"");
  59. }
  60. if (mqttdebug) {
  61. sprintf(tmp_topic_pub, "%s/%s", mqtt_topic_out, "mqtt_received");
  62. sprintf(tmp_payload_pub, "%s: %s", mqtt_topic_in_setTemp, cmdPayload);
  63. mqttclient.publish(tmp_topic_pub, tmp_payload_pub);
  64. }
  65. cmdInQueue = false; // payload is processed in "commands"
  66. }//if topic = mqtt_topic_in_setTemp
  67. if (strcmp(topic, mqtt_topic_in_setMode) == 0) { //if topic = mqtt_topic_in_setMode
  68. int len;
  69. if (length < 101) len = length; // if input is bigger than dest buffer, cut
  70. else len = 100;
  71. for (int i = 0; i < len; i++) {
  72. cmdPayload[i] = (char)payload[i];
  73. }
  74. //cmdPayload[len + 1] = '\0';
  75. cmdPayload[len] = '\0';
  76. // Serial.print("cmdPayload:");
  77. // Serial.println(cmdPayload);
  78. char tmpPayload[21];
  79. strlcpy(tmpPayload, cmdPayload, 20);
  80. strlwr(tmpPayload);
  81. byte tmpHeatMode;
  82. char tmpModename0[15];
  83. char tmpModename1[15];
  84. char tmpModename2[15];
  85. char tmpModename3[15];
  86. strlcpy(tmpModename0, modename0, 14);
  87. strlcpy(tmpModename1, modename1, 14);
  88. strlcpy(tmpModename2, modename2, 14);
  89. strlcpy(tmpModename3, modename3, 14);
  90. strlwr(tmpModename0);
  91. strlwr(tmpModename1);
  92. strlwr(tmpModename2);
  93. strlwr(tmpModename3);
  94. if (strcmp(tmpPayload, tmpModename0) == 0) tmpHeatMode = 0;
  95. else if (strcmp(tmpPayload, tmpModename1) == 0) tmpHeatMode = 1;
  96. else if (strcmp(tmpPayload, tmpModename2) == 0) tmpHeatMode = 2;
  97. else if (strcmp(tmpPayload, tmpModename3) == 0) tmpHeatMode = 3;
  98. else if (strcmp(tmpPayload, "off") == 0) tmpHeatMode = 0;
  99. else if (strcmp(tmpPayload, "aus") == 0) tmpHeatMode = 0;
  100. else if (strcmp(tmpPayload, "on") == 0) tmpHeatMode = 1;
  101. else if (strcmp(tmpPayload, "ein") == 0) tmpHeatMode = 1;
  102. else if (atoi(tmpPayload) == 0) tmpHeatMode = 0;
  103. else if (atoi(tmpPayload) == 1) tmpHeatMode = 1;
  104. else if (atoi(tmpPayload) == 2) tmpHeatMode = 2;
  105. else if (atoi(tmpPayload) == 3) tmpHeatMode = 3;
  106. if (serialdebug) {
  107. Serial.print("set heatmode to: ");
  108. Serial.println(tmpHeatMode);
  109. }
  110. setHeatingmodeTo(tmpHeatMode);
  111. if (serialdebug) {
  112. Serial.print("received MQTT ");
  113. Serial.print(mqtt_topic_in_setMode);
  114. Serial.print(" - \"");
  115. Serial.print(cmdPayload);
  116. Serial.println("\"");
  117. }
  118. if (mqttdebug) {
  119. sprintf(tmp_topic_pub, "%s/%s", mqtt_topic_out, "mqtt_received");
  120. sprintf(tmp_payload_pub, "%s: %s", mqtt_topic_in_setMode, cmdPayload);
  121. mqttclient.publish(tmp_topic_pub, tmp_payload_pub);
  122. }
  123. cmdInQueue = false; // payload is processed in "commands"
  124. }//if topic = mqtt_topic_in_setMode
  125. if (strcmp(topic, outTemp_topic_in) == 0) { //if topic = outTemp_topic_in
  126. int len;
  127. if (length < 6) len = length; // if input is bigger than dest buffer, cut
  128. else len = 5;
  129. for (int i = 0; i < len; i++) {
  130. outTemp_newValue[i] = (char)payload[i];
  131. }
  132. //outTemp_newValue[len + 1] = '\0';
  133. outTemp_newValue[len] = '\0';
  134. outTemp_parseNewValue = true;
  135. }//if topic = outTemp_topic_in
  136. if (strcmp(topic, outHum_topic_in) == 0) { //if topic = outHum_topic_in
  137. int len;
  138. if (length < 4) len = length; // if input is bigger than dest buffer, cut
  139. else len = 3;
  140. for (int i = 0; i < len; i++) {
  141. outHum_newValue[i] = (char)payload[i];
  142. }
  143. //outHum_newValue[len + 1] = '\0';
  144. outHum_newValue[len] = '\0';
  145. outHum_parseNewValue = true;
  146. }//if topic = outHum_topic_in
  147. if (strcmp(topic, domoticz_out_topic) == 0) { //if topic = domoticz_out_topic
  148. Serial.print("received MQTT ");
  149. Serial.println(domoticz_out_topic);
  150. if ( !domoticzOutParserBusy ) {
  151. int len;
  152. if (length < 450) len = length; // if input is bigger than dest buffer, cut
  153. else len = 449;
  154. for (int i = 0; i < len; i++) {
  155. domoticzOutPayload[i] = (char)payload[i];
  156. }
  157. //domoticzOutPayload[len + 1] = '\0';
  158. domoticzOutPayload[len] = '\0';
  159. domoticzOutParseData = true; // parse domoticz data in the next loop()
  160. }
  161. }//if topic = domoticz_out_topic
  162. }//mqttCallback
  163. void mqttPrepareConnection() {
  164. Serial.print("MQTT connection with ");
  165. if (strlen(mqtt_user) > 0 && strlen(mqtt_willTopic) == 0) {
  166. // user and password, no Last Will
  167. Serial.println("user and password, no Last Will");
  168. mqttMode = 2;
  169. }
  170. else if (strlen(mqtt_user) > 0 && strlen(mqtt_willTopic) > 0) {
  171. // user, password and Last Will
  172. Serial.println("user, password and Last Will");
  173. mqttMode = 3;
  174. }
  175. else if (strlen(mqtt_user) == 0 && strlen(mqtt_willTopic) > 0) {
  176. // Last Will but no user and password
  177. Serial.println("Last Will but no user and password");
  178. mqttMode = 4;
  179. }
  180. else {
  181. // no user, password and no Last Will
  182. Serial.println("no user, password and no Last Will");
  183. mqttMode = 1;
  184. }
  185. }
  186. void mqttPrepareSubscribeTopics() {
  187. char tmp_topic_out[50];
  188. sprintf(mqtt_topic_in_cmd, "%s/%s", mqtt_topic_in, "cmd");
  189. sprintf(mqtt_topic_in_setTemp, "%s/%s", mqtt_topic_in, "setTemp");
  190. sprintf(mqtt_topic_in_setMode, "%s/%s", mqtt_topic_in, "setMode");
  191. }
  192. bool mqttReconnect() {
  193. mqttclient.disconnect();
  194. delay(10);
  195. // Create MQTT client ID from device name
  196. String mqttClientId = "ESP8266Client-";
  197. //mqttClientId += String(random(0xffff), HEX); //or random
  198. mqttClientId += String(deviceName);
  199. if (serialdebug) Serial.print("connecting to MQTT broker with ");
  200. bool connRes;
  201. switch (mqttMode) {
  202. case 1:
  203. if (serialdebug) Serial.println("no user, password and no Last Will");
  204. connRes = mqttclient.connect(mqttClientId.c_str());
  205. break;
  206. case 2:
  207. if (serialdebug) Serial.println("user and password, no Last Will");
  208. connRes = mqttclient.connect(mqttClientId.c_str(), mqtt_user, mqtt_pass);
  209. break;
  210. case 3:
  211. if (serialdebug) Serial.println("user, password and Last Will");
  212. connRes = mqttclient.connect(mqttClientId.c_str(), mqtt_user, mqtt_pass, mqtt_willTopic, mqtt_willQos, mqtt_willRetain, mqtt_willMsg);
  213. break;
  214. case 4:
  215. if (serialdebug) Serial.println("Last Will, no user and password");
  216. connRes = mqttclient.connect(mqttClientId.c_str(), mqtt_willTopic, mqtt_willQos, mqtt_willRetain, mqtt_willMsg);
  217. break;
  218. }
  219. if (serialdebug) {
  220. Serial.print("... attempt: ");
  221. Serial.print(mqttReconnectAttempts);
  222. Serial.println();
  223. }
  224. if (connRes) {
  225. if (serialdebug) {
  226. Serial.print("MQTT connected. Reconnects: ");
  227. Serial.println(mqttReconnects);
  228. }
  229. mqttReconnects++;
  230. // Once connected, publish an announcement...
  231. // char outMsg[30];
  232. // sprintf(outMsg, "connected, %d reconnects", mqttReconnects);
  233. // mqttclient.publish(mqtt_topic_out, outMsg, mqtt_outRetain);
  234. mqttclient.publish(mqtt_willTopic, mqtt_connMsg, mqtt_willRetain);
  235. publishStatus();
  236. //mqttclient.publish(mqtt_topic_out, "connected");
  237. // ... and resubscribe
  238. if (serialdebug) Serial.println("Subscribed to:");
  239. if (strlen(mqtt_topic_in_cmd) > 0) {
  240. if (mqttclient.subscribe(mqtt_topic_in_cmd)) {
  241. if (serialdebug) Serial.println(mqtt_topic_in_cmd);
  242. mqttInTopicSubscribed = true;
  243. }
  244. }
  245. if (strlen(mqtt_topic_in_setTemp) > 0) {
  246. if (mqttclient.subscribe(mqtt_topic_in_setTemp)) {
  247. if (serialdebug) Serial.println(mqtt_topic_in_setTemp);
  248. }
  249. }
  250. if (strlen(mqtt_topic_in_setMode) > 0) {
  251. if (mqttclient.subscribe(mqtt_topic_in_setMode)) {
  252. if (serialdebug) Serial.println(mqtt_topic_in_setMode);
  253. }
  254. }
  255. if (strlen(outTemp_topic_in) > 0) {
  256. if (mqttclient.subscribe(outTemp_topic_in)) {
  257. if (serialdebug) Serial.println(outTemp_topic_in);
  258. }
  259. }
  260. if (strlen(outHum_topic_in) > 0) {
  261. if (mqttclient.subscribe(outHum_topic_in)) {
  262. if (serialdebug) Serial.println(outHum_topic_in);
  263. }
  264. }
  265. if (useDomoticz && strlen(domoticz_out_topic) > 0) {
  266. if (mqttclient.subscribe(domoticz_out_topic)) {
  267. if (serialdebug) Serial.println(domoticz_out_topic);
  268. }
  269. }
  270. return mqttclient.connected();
  271. }
  272. else {
  273. if (serialdebug) {
  274. Serial.print("MQTT connect FAILED, rc=");
  275. Serial.println(mqttclient.state());
  276. }
  277. }
  278. } //mqttReconnect
  279. void mqttClientInit() {
  280. mqttclient.setServer(mqtt_server, mqtt_port);
  281. mqttclient.setCallback(mqttCallback);
  282. mqttLastReconnectAttempt = 0;
  283. mqttReconnectAttempts = 0;
  284. }
  285. int lastWifiStatus;
  286. void mqttHandleConnection() {
  287. int currWifiStatus = WiFi.status();
  288. if ( currWifiStatus != lastWifiStatus ) {
  289. lastWifiStatus = currWifiStatus;
  290. Serial.print("WiFi status changed to: ");
  291. Serial.println(currWifiStatus);
  292. }
  293. if ( currWifiStatus == WL_CONNECTED ) {
  294. // MQTT reconnect if not connected (nonblocking)
  295. bool doReconnect = false;
  296. if (!mqttclient.connected()) doReconnect = true;
  297. if (mqttInTopicSubscribed) { // if mqtt_topic_in is subscribed
  298. if ( (millis() - mqttLastHeartbeat) > MQTT_HEARTBEAT_MAXAGE) { // also reconnect if no HEARTBEAT was received for some time
  299. doReconnect = true;
  300. mqttLastHeartbeat = millis();
  301. Serial.println("MQTT HEARTBEAT overdue. Force-Reconnecting MQTT...");
  302. }
  303. }
  304. if (doReconnect) {
  305. unsigned int mqttReconnectAttemptDelay;
  306. if (mqttReconnectAttempts < 3) mqttReconnectAttemptDelay = 15000; // if this is the 1-3rd attempt, try again in 15s
  307. else if (mqttReconnectAttempts < 10) mqttReconnectAttemptDelay = 60000; // if more than 3 attempts failed, try again every min
  308. else if (mqttReconnectAttempts < 20) mqttReconnectAttemptDelay = 300000; // if more than 10 attempts failed, try again every 5 min
  309. else if (mqttReconnectAttempts >= 6) {
  310. // if more than 6 attempts (= > 30 min) failed, restart the ESP
  311. delay(100);
  312. ESP.restart();
  313. }
  314. if ((millis() - mqttLastReconnectAttempt) > mqttReconnectAttemptDelay) {
  315. mqttLastReconnectAttempt = millis();
  316. mqttReconnectAttempts++;
  317. if (mqttReconnect()) { // Attempt to reconnect
  318. // attempt successful - reset mqttReconnectAttempts
  319. mqttReconnectAttempts = 0;
  320. }
  321. }
  322. mqttclient.loop();
  323. }
  324. else {
  325. mqttclient.loop();
  326. }
  327. }
  328. }
  329. void publishStatus() {
  330. char outMsg[60];
  331. long upTime = millis() / 1000;
  332. sprintf(outMsg, "connected, reconnects: %d, uptime: %d, free heap: %d", mqttReconnects - 1, upTime, ESP.getFreeHeap());
  333. mqttclient.publish(mqtt_topic_out, outMsg, mqtt_outRetain);
  334. mqttclient.publish(mqtt_willTopic, mqtt_connMsg, mqtt_willRetain);
  335. yield();
  336. }
  337. void sendStatus(char* payload) {
  338. char buf[101];
  339. strlcpy(buf, payload, 101);
  340. Serial.println(buf);
  341. mqttclient.publish(mqtt_topic_out, buf, mqtt_outRetain);
  342. yield();
  343. }
  344. void publishCurrentThermostatValues() {
  345. char tmp_topic_out[50];
  346. float curr_setTemp;
  347. if (heatingMode == 1) curr_setTemp = setTemp;
  348. else if (heatingMode == 2) curr_setTemp = setTempLow;
  349. else if (heatingMode == 3) curr_setTemp = setTempLow2;
  350. char setTemp_chararr[6];
  351. char currSetTemp_chararr[6];
  352. dtostrf(setTemp, 1, 1, setTemp_chararr );
  353. dtostrf(curr_setTemp, 1, 1, currSetTemp_chararr );
  354. Serial.print("heatingMode: '");
  355. Serial.print(heatingMode);
  356. Serial.println("'");
  357. Serial.print("set temp: '");
  358. Serial.print(setTemp_chararr);
  359. Serial.println("'");
  360. Serial.print("current set temp: '");
  361. Serial.print(currSetTemp_chararr);
  362. Serial.println("'");
  363. sprintf(tmp_topic_out, "%s/%s", mqtt_topic_out, "setTemp");
  364. mqttclient.publish(tmp_topic_out, setTemp_chararr);
  365. yield();
  366. sprintf(tmp_topic_out, "%s/%s", mqtt_topic_out, "currSetTemp");
  367. mqttclient.publish(tmp_topic_out, currSetTemp_chararr);
  368. yield();
  369. sprintf(tmp_topic_out, "%s/%s", mqtt_topic_out, "heatingMode");
  370. char heatingMode_chararr[3];
  371. sprintf(heatingMode_chararr, "%d", heatingMode);
  372. mqttclient.publish(tmp_topic_out, heatingMode_chararr);
  373. sprintf(tmp_topic_out, "%s/%s", mqtt_topic_out, "heatingModeName");
  374. mqttclient.publish(tmp_topic_out, currentModeName);
  375. yield();
  376. char turnHeatingOn_char[5];
  377. if (turnHeatingOn) strcpy(turnHeatingOn_char, "on");
  378. else strcpy(turnHeatingOn_char, "off");
  379. sprintf(tmp_topic_out, "%s/%s", mqtt_topic_out, "heating");
  380. mqttclient.publish(tmp_topic_out, turnHeatingOn_char);
  381. yield();
  382. char buf[101];
  383. sprintf(buf, "%d", heatingOnTime);
  384. sprintf(tmp_topic_out, "%s/%s", mqtt_topic_out, "heatingOnTime");
  385. mqttclient.publish(tmp_topic_out, buf);
  386. yield();
  387. sprintf(buf, "%d", heatingOffTime);
  388. sprintf(tmp_topic_out, "%s/%s", mqtt_topic_out, "heatingOffTime");
  389. mqttclient.publish(tmp_topic_out, buf);
  390. yield();
  391. }
  392. void publishCurrentSensorValues() {
  393. if ( lastTempUpdate != 0 && (millis() - lastTempUpdate) < 120000 ) {
  394. char tmp_topic_out[50];
  395. char temp_chararr[6];
  396. char hum_chararr[4];
  397. dtostrf(currTemp, 1, 1, temp_chararr );
  398. sprintf(hum_chararr, "%2i", currHum);
  399. Serial.print("temp: '");
  400. Serial.print(temp_chararr);
  401. Serial.println("'");
  402. sprintf(tmp_topic_out, "%s/%s", mqtt_topic_out, "temp");
  403. mqttclient.publish(tmp_topic_out, temp_chararr);
  404. yield();
  405. Serial.print("hum: '");
  406. Serial.print(currHum);
  407. Serial.println("'");
  408. sprintf(tmp_topic_out, "%s/%s", mqtt_topic_out, "hum");
  409. mqttclient.publish(tmp_topic_out, hum_chararr);
  410. yield();
  411. dtostrf(currTemp_raw, 1, 1, temp_chararr );
  412. sprintf(hum_chararr, "%2i", currHum_raw);
  413. Serial.print("temp_raw: '");
  414. Serial.print(temp_chararr);
  415. Serial.println("'");
  416. sprintf(tmp_topic_out, "%s/%s", mqtt_topic_out, "temp_raw");
  417. mqttclient.publish(tmp_topic_out, temp_chararr);
  418. yield();
  419. Serial.print("hum_raw: '");
  420. Serial.print(currHum_raw);
  421. Serial.println("'");
  422. sprintf(tmp_topic_out, "%s/%s", mqtt_topic_out, "hum_raw");
  423. mqttclient.publish(tmp_topic_out, hum_chararr);
  424. yield();
  425. }
  426. }
  427. void publishCurrentPIRValue() {
  428. char tmp_topic_out[50];
  429. char PIRStatus[4];
  430. sprintf(tmp_topic_out, "%s/%s", mqtt_topic_out, "PIR");
  431. if (PIRSensorOn) {
  432. strcpy(PIRStatus, "on");
  433. }
  434. else {
  435. strcpy(PIRStatus, "off");
  436. }
  437. mqttclient.publish(tmp_topic_out, PIRStatus);
  438. if (strlen(mqtt_topic_pir) > 0) {
  439. mqttclient.publish(mqtt_topic_pir, PIRStatus);
  440. }
  441. }
  442. void mqttPublishHeartbeat() {
  443. 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
  444. }