mqtt.ino 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  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. if (strcmp(topic, mqtt_topic_in) == 0) { //if topic = mqtt_topic_in
  11. Serial.print("received MQTT ");
  12. Serial.println(mqtt_topic_in);
  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. // Serial.print("cmdPayload:");
  21. // Serial.println(cmdPayload);
  22. cmdInQueue = true; // payload is processed in "commands"
  23. }//if topic = mqtt_topic_in
  24. if (strcmp(topic, outTemp_topic_in) == 0) { //if topic = outTemp_topic_in
  25. int len;
  26. if (length < 6) len = length; // if input is bigger than dest buffer, cut
  27. else len = 5;
  28. for (int i = 0; i < len; i++) {
  29. outTemp_newValue[i] = (char)payload[i];
  30. }
  31. outTemp_newValue[len + 1] = '\0';
  32. outTemp_parseNewValue = true;
  33. }//if topic = outTemp_topic_in
  34. if (strcmp(topic, outHum_topic_in) == 0) { //if topic = outHum_topic_in
  35. int len;
  36. if (length < 4) len = length; // if input is bigger than dest buffer, cut
  37. else len = 3;
  38. for (int i = 0; i < len; i++) {
  39. outHum_newValue[i] = (char)payload[i];
  40. }
  41. outHum_newValue[len + 1] = '\0';
  42. outHum_parseNewValue = true;
  43. }//if topic = outHum_topic_in
  44. if (strcmp(topic, domoticz_out_topic) == 0) { //if topic = domoticz_out_topic
  45. Serial.print("received MQTT ");
  46. Serial.println(domoticz_out_topic);
  47. if ( !domoticzOutParserBusy ) {
  48. int len;
  49. if (length < 450) len = length; // if input is bigger than dest buffer, cut
  50. else len = 449;
  51. for (int i = 0; i < len; i++) {
  52. domoticzOutPayload[i] = (char)payload[i];
  53. }
  54. domoticzOutPayload[len + 1] = '\0';
  55. domoticzOutParseData = true; // parse domoticz data in the next loop()
  56. }
  57. }//if topic = domoticz_out_topic
  58. }//mqttCallback
  59. void mqttPrepareConnection() {
  60. Serial.print("MQTT connection with ");
  61. if (strlen(mqtt_user) > 0 && strlen(mqtt_willTopic) == 0) {
  62. // user and password, no Last Will
  63. Serial.println("user and password, no Last Will");
  64. mqttMode = 2;
  65. }
  66. else if (strlen(mqtt_user) > 0 && strlen(mqtt_willTopic) > 0) {
  67. // user, password and Last Will
  68. Serial.println("user, password and Last Will");
  69. mqttMode = 3;
  70. }
  71. else if (strlen(mqtt_user) == 0 && strlen(mqtt_willTopic) > 0) {
  72. // Last Will but no user and password
  73. Serial.println("Last Will but no user and password");
  74. mqttMode = 4;
  75. }
  76. else {
  77. // no user, password and no Last Will
  78. Serial.println("no user, password and no Last Will");
  79. mqttMode = 1;
  80. }
  81. }
  82. bool mqttReconnect() {
  83. mqttclient.disconnect();
  84. delay(10);
  85. // Create a random MQTT client ID
  86. String mqttClientId = "ESP8266Client-";
  87. mqttClientId += String(random(0xffff), HEX);
  88. Serial.print("connecting to MQTT broker with ");
  89. bool connRes;
  90. switch (mqttMode) {
  91. case 1:
  92. Serial.print("no user, password and no Last Will");
  93. connRes = mqttclient.connect(mqttClientId.c_str());
  94. break;
  95. case 2:
  96. Serial.print("user and password, no Last Will");
  97. connRes = mqttclient.connect(mqttClientId.c_str(), mqtt_user, mqtt_pass);
  98. break;
  99. case 3:
  100. Serial.print("user, password and Last Will");
  101. connRes = mqttclient.connect(mqttClientId.c_str(), mqtt_user, mqtt_pass, mqtt_willTopic, mqtt_willQos, mqtt_willRetain, mqtt_willMsg);
  102. break;
  103. case 4:
  104. Serial.println("Last Will, no user and password");
  105. connRes = mqttclient.connect(mqttClientId.c_str(), mqtt_willTopic, mqtt_willQos, mqtt_willRetain, mqtt_willMsg);
  106. break;
  107. }
  108. Serial.print("... attempt: ");
  109. Serial.print(mqttReconnectAttempts);
  110. Serial.println();
  111. if (connRes) {
  112. Serial.print("MQTT connected. Reconnects: ");
  113. Serial.println(mqttReconnects);
  114. mqttReconnects++;
  115. // Once connected, publish an announcement...
  116. // char outMsg[30];
  117. // sprintf(outMsg, "connected, %d reconnects", mqttReconnects);
  118. // mqttclient.publish(mqtt_topic_out, outMsg, mqtt_outRetain);
  119. publishStatus();
  120. //mqttclient.publish(mqtt_topic_out, "connected");
  121. // ... and resubscribe
  122. Serial.println("Subscribed to:");
  123. if (strlen(mqtt_topic_in) > 0) {
  124. if (mqttclient.subscribe(mqtt_topic_in)) {
  125. Serial.println(mqtt_topic_in);
  126. mqttInTopicSubscribed = true;
  127. }
  128. }
  129. if (strlen(outTemp_topic_in) > 0) {
  130. if (mqttclient.subscribe(outTemp_topic_in)) {
  131. Serial.println(outTemp_topic_in);
  132. }
  133. }
  134. if (strlen(outHum_topic_in) > 0) {
  135. if (mqttclient.subscribe(outHum_topic_in)) {
  136. Serial.println(outHum_topic_in);
  137. }
  138. }
  139. if (useDomoticz && strlen(domoticz_out_topic) > 0) {
  140. if (mqttclient.subscribe(domoticz_out_topic)) {
  141. Serial.println(domoticz_out_topic);
  142. }
  143. }
  144. }
  145. else {
  146. Serial.print("MQTT connect FAILED, rc=");
  147. Serial.println(mqttclient.state());
  148. }
  149. return mqttclient.connected();
  150. } //mqttReconnect
  151. void mqttClientInit() {
  152. mqttclient.setServer(mqtt_server, mqtt_port);
  153. mqttclient.setCallback(mqttCallback);
  154. mqttLastReconnectAttempt = 0;
  155. mqttReconnectAttempts = 0;
  156. }
  157. int lastWifiStatus;
  158. void mqttHandleConnection() {
  159. int currWifiStatus = WiFi.status();
  160. if ( currWifiStatus != lastWifiStatus ) {
  161. lastWifiStatus = currWifiStatus;
  162. Serial.print("WiFi status changed to: ");
  163. Serial.println(currWifiStatus);
  164. }
  165. if ( currWifiStatus == WL_CONNECTED ) {
  166. // MQTT reconnect if not connected (nonblocking)
  167. bool doReconnect = false;
  168. if (!mqttclient.connected()) doReconnect = true;
  169. if (mqttInTopicSubscribed) { // if mqtt_topic_in is subscribed
  170. if ( (millis() - mqttLastHeartbeat) > MQTT_HEARTBEAT_MAXAGE) { // also reconnect if no HEARTBEAT was received for some time
  171. doReconnect = true;
  172. mqttLastHeartbeat = millis();
  173. Serial.println("MQTT HEARTBEAT overdue. Force-Reconnecting MQTT...");
  174. }
  175. }
  176. if (doReconnect) {
  177. unsigned int mqttReconnectAttemptDelay;
  178. if (mqttReconnectAttempts < 3) mqttReconnectAttemptDelay = 15000; // if this is the 1-3rd attempt, try again in 15s
  179. else mqttReconnectAttemptDelay = 60000; // if more than 3 attempts failed, try again in 1 min
  180. if ((millis() - mqttLastReconnectAttempt) > mqttReconnectAttemptDelay) {
  181. mqttLastReconnectAttempt = millis();
  182. mqttReconnectAttempts++;
  183. if (mqttReconnect()) { // Attempt to reconnect
  184. // attempt successful - reset mqttReconnectAttempts
  185. mqttReconnectAttempts = 0;
  186. }
  187. }
  188. mqttclient.loop();
  189. }
  190. else {
  191. mqttclient.loop();
  192. }
  193. }
  194. }
  195. void publishStatus() {
  196. char outMsg[60];
  197. long upTime = millis() / 1000;
  198. sprintf(outMsg, "connected, reconnects: %d, uptime: %d, free heap: %d", mqttReconnects - 1, upTime, ESP.getFreeHeap());
  199. mqttclient.publish(mqtt_topic_out, outMsg, mqtt_outRetain);
  200. yield();
  201. }
  202. void sendStatus(char* payload) {
  203. char buf[101];
  204. strlcpy(buf, payload, 101);
  205. Serial.println(buf);
  206. mqttclient.publish(mqtt_topic_out, buf, mqtt_outRetain);
  207. yield();
  208. }
  209. void publishCurrentThermostatValues() {
  210. char tmp_topic_out[50];
  211. float curr_setTemp;
  212. if (heatingMode == 1) curr_setTemp = setTemp;
  213. else if (heatingMode == 2) curr_setTemp = setTempLow;
  214. char setTemp_chararr[6];
  215. char currSetTemp_chararr[6];
  216. dtostrf(setTemp, 1, 1, setTemp_chararr );
  217. dtostrf(curr_setTemp, 1, 1, currSetTemp_chararr );
  218. Serial.print("heatingMode: '");
  219. Serial.print(heatingMode);
  220. Serial.println("'");
  221. Serial.print("set temp: '");
  222. Serial.print(setTemp_chararr);
  223. Serial.println("'");
  224. Serial.print("current set temp: '");
  225. Serial.print(currSetTemp_chararr);
  226. Serial.println("'");
  227. sprintf(tmp_topic_out, "%s/%s", mqtt_topic_out, "setTemp");
  228. mqttclient.publish(tmp_topic_out, setTemp_chararr);
  229. yield();
  230. sprintf(tmp_topic_out, "%s/%s", mqtt_topic_out, "currSetTemp");
  231. mqttclient.publish(tmp_topic_out, currSetTemp_chararr);
  232. yield();
  233. sprintf(tmp_topic_out, "%s/%s", mqtt_topic_out, "heatingMode");
  234. char heatingMode_chararr[3];
  235. sprintf(heatingMode_chararr, "%d", heatingMode);
  236. mqttclient.publish(tmp_topic_out, heatingMode_chararr);
  237. yield();
  238. char turnHeatingOn_char[5];
  239. if (turnHeatingOn) strcpy(turnHeatingOn_char, "on");
  240. else strcpy(turnHeatingOn_char, "off");
  241. sprintf(tmp_topic_out, "%s/%s", mqtt_topic_out, "heating");
  242. mqttclient.publish(tmp_topic_out, turnHeatingOn_char);
  243. yield();
  244. char buf[101];
  245. sprintf(buf, "%d", heatingOnTime);
  246. sprintf(tmp_topic_out, "%s/%s", mqtt_topic_out, "heatingOnTime");
  247. mqttclient.publish(tmp_topic_out, buf);
  248. yield();
  249. sprintf(buf, "%d", heatingOffTime);
  250. sprintf(tmp_topic_out, "%s/%s", mqtt_topic_out, "heatingOffTime");
  251. mqttclient.publish(tmp_topic_out, buf);
  252. yield();
  253. }
  254. void publishCurrentSensorValues() {
  255. if ( lastTempUpdate != 0 && (millis() - lastTempUpdate) < 120000 ) {
  256. char tmp_topic_out[50];
  257. char temp_chararr[6];
  258. char hum_chararr[4];
  259. dtostrf(currTemp, 1, 1, temp_chararr );
  260. sprintf(hum_chararr, "%2i", currHum);
  261. Serial.print("temp: '");
  262. Serial.print(temp_chararr);
  263. Serial.println("'");
  264. sprintf(tmp_topic_out, "%s/%s", mqtt_topic_out, "temp");
  265. mqttclient.publish(tmp_topic_out, temp_chararr);
  266. yield();
  267. Serial.print("hum: '");
  268. Serial.print(currHum);
  269. Serial.println("'");
  270. sprintf(tmp_topic_out, "%s/%s", mqtt_topic_out, "hum");
  271. mqttclient.publish(tmp_topic_out, hum_chararr);
  272. yield();
  273. dtostrf(currTemp_raw, 1, 1, temp_chararr );
  274. sprintf(hum_chararr, "%2i", currHum_raw);
  275. Serial.print("temp_raw: '");
  276. Serial.print(temp_chararr);
  277. Serial.println("'");
  278. sprintf(tmp_topic_out, "%s/%s", mqtt_topic_out, "temp_raw");
  279. mqttclient.publish(tmp_topic_out, temp_chararr);
  280. yield();
  281. Serial.print("hum_raw: '");
  282. Serial.print(currHum_raw);
  283. Serial.println("'");
  284. sprintf(tmp_topic_out, "%s/%s", mqtt_topic_out, "hum_raw");
  285. mqttclient.publish(tmp_topic_out, hum_chararr);
  286. yield();
  287. }
  288. }
  289. void publishCurrentPIRValue() {
  290. char tmp_topic_out[50];
  291. char PIRStatus[4];
  292. sprintf(tmp_topic_out, "%s/%s", mqtt_topic_out, "PIR");
  293. if (PIRSensorOn) {
  294. strcpy(PIRStatus, "on");
  295. }
  296. else {
  297. strcpy(PIRStatus, "off");
  298. }
  299. mqttclient.publish(tmp_topic_out, PIRStatus);
  300. }
  301. void mqttPublishHeartbeat() {
  302. mqttclient.publish(mqtt_topic_in, "HEARTBEAT"); // publishes to IN-topic. MQTT will force-reconnect if it does not get a HEARTBEAT for 2 min
  303. }