Commit aedbed70d121a026b53042ce963765fc77bace0b

Authored by Jeroen88
1 parent a7de2e9c

Changed MQTT client back to PubSubClient but TCPIP is handled by sketch, added E…

…SP8266 support, changed shortID() to pick the least significant bytes of chip ID, made StaticJsonDocument DynamicJsonDocument, small ISR related changes in OTPhysicalLayer
examples/Advanced_Thermostat/Advanced_Thermostat.ino
... ... @@ -112,21 +112,16 @@ static const char * TAG = __FILE__;
112 112  
113 113 #include <Arduino.h>
114 114  
  115 +#if defined(ESP8266)
  116 +#include <ESP8266WiFi.h>
  117 +#else
115 118 #include <WiFi.h>
  119 +#endif
116 120  
117 121 #include <time.h>
118 122  
119 123 #include <ArduinoJson.h>
120 124  
121   -// This example does not use the more popular PubSubClient, because that has too many issues, like losing a connection without possibilities to signal it and correct it
122   -// This MQTT client runs rock solid :)
123   -// https://github.com/monstrenyatko/ArduinoMqtt
124   -// Enable MqttClient logs
125   -#define MQTT_LOG_ENABLED 1
126   -// Include library
127   -#include <MqttClient.h>
128   -
129   -
130 125 #include <OneWire.h>
131 126 #include <DallasTemperature.h>
132 127  
... ... @@ -149,6 +144,7 @@ const char * password = &quot;YOUR WIFI PASSWORD&quot;;
149 144 const char * mqtt_server = "YOUR MQTT SERVER NAME OR IP ADDRESS";
150 145 const char * mqtt_user = "YOUR MQTT USER NAME";
151 146 const char * mqtt_password = "YOUR MQTT PASSWORD";
  147 +const char * MQTT_ID = "EasyOpenTherm"; // Should be unique for your broker, see e.g. https://stackoverflow.com/questions/40078252/mosquitto-prevent-duplicate-login
152 148  
153 149  
154 150 // Your time zone, used to display times correctly (and needed for WiFiClientSecure TLS certificate validation, if used)
... ... @@ -156,8 +152,8 @@ const char * mqtt_password = &quot;YOUR MQTT PASSWORD&quot;;
156 152 #define TIME_ZONE TZ_Europe_Amsterdam
157 153  
158 154  
159   -// Define OT_RX_PIN, the GPIO pin used to read data from the boiler or HVAC. Must support interrupts
160   -// Define OT_TX_PIN, the GPIO pin used to send data to the boiier or HVAC. Must not be a 'read only' GPIO
  155 +// Define OT_RX_PIN, the GPIO pin used to read data from the boiler or HVAC (TxD). Must support interrupts
  156 +// Define OT_TX_PIN, the GPIO pin used to send data to the boiier or HVAC (RxD). Must not be a 'read only' GPIO
161 157 // Define DALLAS, the GPIO pin used for the Dallas sensor, if used
162 158  
163 159 #if defined(ARDUINO_LOLIN_S2_MINI)
... ... @@ -168,12 +164,32 @@ const char * mqtt_password = &quot;YOUR MQTT PASSWORD&quot;;
168 164 #define OT_RX_PIN (10)
169 165 #define OT_TX_PIN (8)
170 166 #define DALLAS (4)
  167 +#elif defined(ARDUINO_ESP8266_WEMOS_D1MINIPRO)
  168 +// I can't get my "D1 MINI PRO Based ESP8266EX" passed a WiFi connection
  169 +// D1 is GPIO5
  170 +#define OT_RX_PIN (5)
  171 +// D2 is GPIO4
  172 +#define OT_TX_PIN (4)
  173 +// D7 is GPIO13
  174 +#define DALLAS (13)
  175 +#elif defined(ESP32)
  176 +#define OT_RX_PIN (33)
  177 +#define OT_TX_PIN (16)
  178 +#define DALLAS (17)
  179 +#elif defined(ESP8266)
  180 +// GPIO5 is D1
  181 +#define OT_RX_PIN (5)
  182 +// GPIO4 is D2
  183 +#define OT_TX_PIN (4)
  184 +// D7 is GPIO13
  185 +#define DALLAS (13)
171 186 #else
172 187 #define OT_RX_PIN (35)
173 188 #define OT_TX_PIN (33)
174 189 #define DALLAS (-1)
175 190 #endif
176 191  
  192 +
177 193 // The maximum room temperature
178 194 #define ROOM_TEMPERATURE_MAX_SETPOINT (30.0f)
179 195 // The minimum room temperature
... ... @@ -212,8 +228,7 @@ const size_t MSG_BUFFER_RECV_SIZE = 256; // Too small a receive buffer will fai
212 228 // Define a global WiFiClient instance for WiFi connection
213 229 WiFiClient wiFiClient;
214 230  
215   -#define MQTT_ID "EasyOpenTherm"
216   -static MqttClient *mqtt = NULL;
  231 +PubSubClient *mqtt = NULL;
217 232  
218 233  
219 234 // GPIO where the DS18B20 is connected to, set to '-1' if not used
... ... @@ -282,12 +297,32 @@ float roomTemperature;
282 297  
283 298  
284 299 // ============== Subscription callbacks ========================================
285   -void processRoomTemperatureMessage(MqttClient::MessageData& md) {
  300 +void PubSubClientCallback(char* topic, byte* payload, unsigned int length) {
  301 + // handle message arrived
  302 + char payloadReceived[length + 1];
  303 + memcpy(payloadReceived, payload, length);
  304 + payloadReceived[length] = '\0';
  305 +
  306 + Serial.printf("Received topic '%s' with payload '%s'\n", topic, payloadReceived);
  307 +
  308 + const char * subscriptionTopic = topicByReference("temperature_command_topic", EASYOPENTHERM_MQTT_DISCOVERY_MSG_CLIMATE);
  309 + if(subscriptionTopic == nullptr) return;
  310 + if(strcmp(topic, subscriptionTopic) == 0) return processSetpointTemperatureMessage(payloadReceived);
  311 +
  312 + subscriptionTopic = topicByReference("mode_command_topic", EASYOPENTHERM_MQTT_DISCOVERY_MSG_CLIMATE);
  313 + if(subscriptionTopic == nullptr) return;
  314 + if(strcmp(topic, subscriptionTopic) == 0) return processClimateMessage(payloadReceived);
  315 +
  316 + subscriptionTopic = topicByReference("current_temperature_topic", EASYOPENTHERM_MQTT_DISCOVERY_MSG_CLIMATE);
  317 + if(subscriptionTopic == nullptr) return;
  318 + if(strcmp(topic, subscriptionTopic) == 0) return processRoomTemperatureMessage(payloadReceived);
  319 +
  320 + Serial.printf("Received unhandled topic '%s' with payload '%s'\n", topic, payloadReceived);
  321 +}
  322 +
  323 +
  324 +void processRoomTemperatureMessage(const char * payload) {
286 325 Serial.println("processRoomTemperatureMessage");
287   - const MqttClient::Message& msg = md.message;
288   - char payload[msg.payloadLen + 1];
289   - memcpy(payload, msg.payload, msg.payloadLen);
290   - payload[msg.payloadLen] = '\0';
291 326  
292 327 StaticJsonDocument<32> roomTemperatureMsgDoc;
293 328 DeserializationError error = deserializeJson(roomTemperatureMsgDoc, payload);
... ... @@ -314,12 +349,7 @@ Serial.printf(&quot;Received room temperature %.01f ºC\n&quot;, roomTemperature);
314 349 }
315 350  
316 351  
317   -void processSetpointTemperatureMessage(MqttClient::MessageData& md) {
318   - const MqttClient::Message& msg = md.message;
319   - char payload[msg.payloadLen + 1];
320   - memcpy(payload, msg.payload, msg.payloadLen);
321   - payload[msg.payloadLen] = '\0';
322   -
  352 +void processSetpointTemperatureMessage(const char * payload) {
323 353 float setpoint;
324 354 if(sscanf(payload, "%f", &setpoint) != 1) {
325 355 ESP_LOGE(TAG, "Payload is not a float: '%s'", payload);
... ... @@ -333,11 +363,7 @@ Serial.printf(&quot;Received room temperature setpoint &#39;%s&#39;\n&quot;, payload);
333 363 }
334 364  
335 365  
336   -void processClimateMessage(MqttClient::MessageData& md) {
337   - const MqttClient::Message& msg = md.message;
338   - char payload[msg.payloadLen + 1];
339   - memcpy(payload, msg.payload, msg.payloadLen);
340   - payload[msg.payloadLen] = '\0';
  366 +void processClimateMessage(const char * payload) {
341 367 ESP_LOGI(TAG,
342 368 "Message arrived: qos %d, retained %d, dup %d, packetid %d, payload:[%s]",
343 369 msg.qos, msg.retained, msg.dup, msg.id, payload
... ... @@ -362,27 +388,28 @@ void setup() {
362 388 delay(5000); // For debug only: give the Serial Monitor some time to connect to the native USB of the MCU for output
363 389 Serial.println("\n\nStarted");
364 390 Serial.printf("Chip ID is %s\n", chipID());
365   - ESP_LOGI(TAG, "Chip ID is %s", chipID());
  391 + Serial.printf("Short ID is %s\n", shortID());
366 392  
367 393 Serial.printf("OpenTherm RX pin is %d, TX pin is %d\n", OT_RX_PIN, OT_TX_PIN);
368 394  
369   - pinMode(LED_BUILTIN, OUTPUT);
  395 +// pinMode(LED_BUILTIN, OUTPUT);
370 396  
371 397 // Connect WiFi
372 398 WiFi.mode(WIFI_STA);
373 399 WiFi.setAutoReconnect(true);
  400 + WiFi.setAutoReconnect(false);
374 401 WiFi.begin(ssid, password);
375 402  
376 403 uint32_t startMillis = millis();
377 404 while (WiFi.status() != WL_CONNECTED) {
378 405 delay(500);
379   - digitalWrite(LED_BUILTIN, digitalRead(LED_BUILTIN) == LOW ? HIGH : LOW);
  406 +// digitalWrite(LED_BUILTIN, digitalRead(LED_BUILTIN) == LOW ? HIGH : LOW);
380 407  
381 408 if(millis() - startMillis > 15000) ESP.restart();
382 409 }
383 410  
384   - ESP_LOGI(TAG, "WiFi connected to %s", ssid);
385   - ESP_LOGI(TAG, "IP address: %s", WiFi.localIP().toString().c_str());
  411 + Serial.printf("WiFi connected to %s\n", ssid);
  412 + Serial.printf("IP address: %s\n", WiFi.localIP().toString().c_str());
386 413  
387 414 // Set time and date, necessary for HTTPS certificate validation
388 415 configTzTime(TIME_ZONE, "pool.ntp.org", "time.nist.gov");
... ... @@ -400,7 +427,11 @@ void setup() {
400 427  
401 428 if(millis() - startMillis > 15000) ESP.restart();
402 429 }
  430 +#if defined(ESP8266)
  431 + digitalWrite(LED_BUILTIN, HIGH);
  432 +#else
403 433 digitalWrite(LED_BUILTIN, LOW);
  434 +#endif
404 435 Serial.println();
405 436  
406 437 const struct tm * timeinfo = localtime(&now);
... ... @@ -417,32 +448,8 @@ void setup() {
417 448  
418 449 }
419 450  
420   - // Setup MQTT client
421   - MqttClient::System *mqttSystem = new System;
422   -#if defined(ARDUINO_LOLIN_S2_MINI)
423   - MqttClient::Logger *mqttLogger = new MqttClient::LoggerImpl<USBCDC>(Serial);
424   -#elif defined(ARDUINO_LOLIN_C3_MINI)
425   - MqttClient::Logger *mqttLogger = new MqttClient::LoggerImpl<HWCDC>(Serial);
426   -#else
427   - MqttClient::Logger *mqttLogger = new MqttClient::LoggerImpl<HardwareSerial>(Serial);
428   -#endif
429   - MqttClient::Network * mqttNetwork = new MqttClient::NetworkClientImpl<WiFiClient>(wiFiClient, *mqttSystem);
430   - //// Make MSG_BUFFER_SIZE bytes send buffer
431   - MqttClient::Buffer *mqttSendBuffer = new MqttClient::ArrayBuffer<MSG_BUFFER_SEND_SIZE>();
432   - //// Make MSG_BUFFER_SIZE bytes receive buffer
433   - MqttClient::Buffer *mqttRecvBuffer = new MqttClient::ArrayBuffer<MSG_BUFFER_RECV_SIZE>();
434   - //// Allow up to 4 subscriptions simultaneously
435   - MqttClient::MessageHandlers *mqttMessageHandlers = new MqttClient::MessageHandlersDynamicImpl<4>();
436   - // Note: the MessageHandlersDynamicImpl does not copy the topic string. The second parameter to MessageHandlersStaticImpl is the maximum topic size
437   - // NOT TRUE: https://github.com/monstrenyatko/ArduinoMqtt/blob/15091f0b8c05f843f93b73db9a98f7b59ffb4dfa/src/MqttClient.h#L390
438   -// MqttClient::MessageHandlers *mqttMessageHandlers = new MqttClient::MessageHandlersStaticImpl<4, 128>();
439   - //// Configure client options
440   - MqttClient::Options mqttOptions;
441   - ////// Set command timeout to 10 seconds
442   - mqttOptions.commandTimeoutMs = 10000;
443   - //// Make client object
444   - mqtt = new MqttClient(mqttOptions, *mqttLogger, *mqttSystem, *mqttNetwork, *mqttSendBuffer, *mqttRecvBuffer, *mqttMessageHandlers);
445   -
  451 + // Do not let PubSubClient handle the TCP/IP socket connection, because of connection issues
  452 + Serial.println("Connect to MQTT broker...");
446 453 wiFiClient.connect(mqtt_server, 1883);
447 454 if(!wiFiClient.connected()) {
448 455 ESP_LOGE(TAG, "Can't establish the TCP connection");
... ... @@ -450,7 +457,10 @@ void setup() {
450 457 ESP.restart();
451 458 }
452 459  
453   - Serial.println("Connect MQTT client...");
  460 + // Setup MQTT client
  461 + mqtt = new PubSubClient(wiFiClient);
  462 + mqtt->setBufferSize(1024);
  463 + mqtt->setCallback(PubSubClientCallback);
454 464  
455 465 bool MQTTConnected = connectMQTT(*mqtt, MQTT_ID, mqtt_user, mqtt_password);
456 466 if(MQTTConnected) {
... ... @@ -487,14 +497,14 @@ Serial.println(&quot;MQTT NOT connected&quot;);
487 497 if(!validJson(EASYOPENTHERM_MQTT_DISCOVERY_MSG_DHW_BINARY_SENSOR)) Serial.printf("Invalid JSON '%s'\n", EASYOPENTHERM_MQTT_DISCOVERY_MSG_DHW_BINARY_SENSOR);
488 498  
489 499 // Add all 'always present' entities (the other entities are added only if supported by the boiler)
  500 + Serial.println("Add default entities to Home Assistant by publishing discovery messages to MQTT broker...");
490 501 addEntity(*mqtt, "climate", "climate", EASYOPENTHERM_MQTT_DISCOVERY_MSG_CLIMATE);
491 502 addEntity(*mqtt, "sensor", "boiler_setpoint", EASYOPENTHERM_MQTT_DISCOVERY_MSG_SETPOINT_SENSOR);
492 503 addEntity(*mqtt, "sensor", "thermostat_rssi", EASYOPENTHERM_MQTT_DISCOVERY_MSG_RSSI_SENSOR);
493 504 addEntity(*mqtt, "binary_sensor", "boiler_flame", EASYOPENTHERM_MQTT_DISCOVERY_MSG_FLAME_BINARY_SENSOR);
494 505  
495   - char payload[16];
496   - snprintf(payload, sizeof payload, "%.01f", ROOM_TEMPERATURE_MIN_SETPOINT);
497 506 // Set all sensors, except those that are directly updated, to 'None', the binary sensor to 'Unknown'
  507 + Serial.println("Set sensor values to 'none' by publishing to MQTT sensor state topics...");
498 508 publish(*mqtt, topicByReference("state_topic", EASYOPENTHERM_MQTT_DISCOVERY_MSG_SETPOINT_SENSOR), "{\"ch_setpoint\":\"None\"}");
499 509 publish(*mqtt, topicByReference("state_topic", EASYOPENTHERM_MQTT_DISCOVERY_MSG_FLOW_TEMPERATURE_SENSOR), "{\"flow_temperature\":\"None\"}");
500 510 publish(*mqtt, topicByReference("state_topic", EASYOPENTHERM_MQTT_DISCOVERY_MSG_RETURN_TEMPERATURE_SENSOR), "{\"return_temperature\":\"None\"}");
... ... @@ -511,7 +521,8 @@ Serial.println(&quot;MQTT NOT connected&quot;);
511 521 // If the boikler can both heat and cool adds 'auto', 'off', 'cool' and 'heat' to the thermmostat modes
512 522 // If the boikler can only heat adds 'off' and 'heat' to the thermmostat modes
513 523 void updateClimateEntity(bool canCool) {
514   - StaticJsonDocument<fullJsonDocSize> discoveryMsgDoc;
  524 +// StaticJsonDocument<fullJsonDocSize> discoveryMsgDoc;
  525 + DynamicJsonDocument discoveryMsgDoc(fullJsonDocSize);
515 526  
516 527 if(discoveryMsgToJsonDoc(discoveryMsgDoc, EASYOPENTHERM_MQTT_DISCOVERY_MSG_CLIMATE)) {
517 528 JsonArray modesArray = discoveryMsgDoc["modes"];
... ... @@ -552,7 +563,6 @@ void updateDHWEntity(bool enableDHW) {
552 563 void updateFlameSensor(uint8_t statusFlags) {
553 564 static bool flameSensorInitialised = false;
554 565 static uint8_t previousStatusFlags = 0;
555   -Serial.printf("Secondary status flags is 0x%02x\n", statusFlags);
556 566  
557 567 if(!flameSensorInitialised || (statusFlags & uint8_t(OpenTherm::STATUS_FLAGS::SECONDARY_FLAME_STATUS)) != (previousStatusFlags & uint8_t(OpenTherm::STATUS_FLAGS::SECONDARY_FLAME_STATUS))) {
558 568 const char * topic = topicByReference("state_topic", EASYOPENTHERM_MQTT_DISCOVERY_MSG_FLAME_BINARY_SENSOR);
... ... @@ -591,10 +601,11 @@ void updateDHWSensor(uint8_t statusFlags) {
591 601 // updateSensors
592 602 // Update the values of all 'interval' sensors in Home Assistant by sending the value in the right format to the topic looked up in the discovery JSON. OpenTherm sensor can be read and do not have
593 603 // an entity yet in Home Assistant are created by sending the discovery JSON to the right '/config' topic.
594   -void updateSensors(MqttClient & client,
  604 +void updateSensors(PubSubClient & client,
  605 + bool isConnectedOT,
595 606 float CHSetpoint,
596 607 uint32_t & previousOTCommunicationMs) {
597   - if(client.isConnected()) {
  608 + if(client.connected()) {
598 609 char payload[64];
599 610 const char * topic;
600 611  
... ... @@ -611,74 +622,80 @@ void updateSensors(MqttClient &amp; client,
611 622 publish(client, topic, payload);
612 623 }
613 624  
614   - // Publish the Central Heating setpoint temperature
615   - snprintf(payload, sizeof payload, "{\"ch_setpoint\":%.01f}", CHSetpoint);
616   - topic = topicByReference("state_topic", EASYOPENTHERM_MQTT_DISCOVERY_MSG_SETPOINT_SENSOR);
617   - publish(client, topic, payload);
  625 + if(isConnectedOT) {
  626 + // Publish the Central Heating setpoint temperature
  627 + snprintf(payload, sizeof payload, "{\"ch_setpoint\":%.01f}", CHSetpoint);
  628 + topic = topicByReference("state_topic", EASYOPENTHERM_MQTT_DISCOVERY_MSG_SETPOINT_SENSOR);
  629 + publish(client, topic, payload);
618 630  
619   - float value;
620   - // Test if Relative Modulation Level can be read from the boiler
621   - if(readSensor(thermostat, OpenTherm::READ_DATA_ID::RELATIVE_MODULATION_LEVEL, value, previousOTCommunicationMs)) {
622   - Serial.printf("Relative Modulation level is %.01f %\n", value);
623   - // Use a static variable to keep track of the entity already being created
624   - static bool relativeModulationLevelDiscoveryPublished = false;
625   - if(!relativeModulationLevelDiscoveryPublished) {
626   - // Create the entity
627   - addEntity(client, "sensor", "relative_modulation", EASYOPENTHERM_MQTT_DISCOVERY_MSG_RELATIVE_MODULATION_SENSOR);
628   - relativeModulationLevelDiscoveryPublished = true;
  631 + float value;
  632 + // Test if Relative Modulation Level can be read from the boiler
  633 + if(readSensor(thermostat, OpenTherm::READ_DATA_ID::RELATIVE_MODULATION_LEVEL, value, previousOTCommunicationMs)) {
  634 + Serial.printf("Relative Modulation level is %.01f %\n", value);
  635 + // Use a static variable to keep track of the entity already being created
  636 + static bool relativeModulationLevelDiscoveryPublished = false;
  637 + if(!relativeModulationLevelDiscoveryPublished) {
  638 + // Create the entity
  639 + addEntity(client, "sensor", "relative_modulation", EASYOPENTHERM_MQTT_DISCOVERY_MSG_RELATIVE_MODULATION_SENSOR);
  640 + relativeModulationLevelDiscoveryPublished = true;
  641 + }
  642 + // Publish the Relative Modulation Level
  643 + snprintf(payload, sizeof payload, "{\"relative_modulation\":%.01f}", value);
  644 + topic = topicByReference("state_topic", EASYOPENTHERM_MQTT_DISCOVERY_MSG_RELATIVE_MODULATION_SENSOR);
  645 + publish(client, topic, payload);
629 646 }
630   - // Publish the Relative Modulation Level
631   - snprintf(payload, sizeof payload, "{\"relative_modulation\":%.01f}", value);
632   - topic = topicByReference("state_topic", EASYOPENTHERM_MQTT_DISCOVERY_MSG_RELATIVE_MODULATION_SENSOR);
633   - publish(client, topic, payload);
634   - }
635   - // Test if Relative Central Heating Water Pressure can be read from the boiler
636   - if(readSensor(thermostat, OpenTherm::READ_DATA_ID::CH_WATER_PRESSURE, value, previousOTCommunicationMs)) {
637   - Serial.printf("Central Heating water pressure is %.01f bar\n", value);
638   - // Use a static variable to keep track of the entity already being created
639   - static bool waterPressureEntityAdded = false;
640   - // Create the entity
641   - if(!waterPressureEntityAdded) {
642   - addEntity(client, "sensor", "water_pressure", EASYOPENTHERM_MQTT_DISCOVERY_MSG_WATER_PRESSURE_SENSOR);
643   - waterPressureEntityAdded = true;
  647 +
  648 + // Test if Relative Central Heating Water Pressure can be read from the boiler
  649 + if(readSensor(thermostat, OpenTherm::READ_DATA_ID::CH_WATER_PRESSURE, value, previousOTCommunicationMs)) {
  650 + Serial.printf("Central Heating water pressure is %.01f bar\n", value);
  651 + // Use a static variable to keep track of the entity already being created
  652 + static bool waterPressureEntityAdded = false;
  653 + // Create the entity
  654 + if(!waterPressureEntityAdded) {
  655 + addEntity(client, "sensor", "water_pressure", EASYOPENTHERM_MQTT_DISCOVERY_MSG_WATER_PRESSURE_SENSOR);
  656 + waterPressureEntityAdded = true;
  657 + }
  658 + // Publish the Central Heating Water Pressure
  659 + snprintf(payload, sizeof payload, "{\"water_pressure\":%.01f}", value);
  660 + topic = topicByReference("state_topic", EASYOPENTHERM_MQTT_DISCOVERY_MSG_WATER_PRESSURE_SENSOR);
  661 + publish(client, topic, payload);
644 662 }
645   - // Publish the Central Heating Water Pressure
646   - snprintf(payload, sizeof payload, "{\"water_pressure\":%.01f}", value);
647   - topic = topicByReference("state_topic", EASYOPENTHERM_MQTT_DISCOVERY_MSG_WATER_PRESSURE_SENSOR);
648   - publish(client, topic, payload);
649   - }
650   - // Test if Flow Temperature can be read from the boiler
651   - if(readSensor(thermostat, OpenTherm::READ_DATA_ID::BOILER_WATER_TEMP, value, previousOTCommunicationMs)) {
652   - Serial.printf("Flow water temperature from boiler is %.01f %\n", value);
653   - // Use a static variable to keep track of the entity already being created
654   - static bool flowTemperatureEntityAdded = false;
655   - // Create the entity
656   - if(!flowTemperatureEntityAdded) {
657   - addEntity(client, "sensor", "flow_temperature", EASYOPENTHERM_MQTT_DISCOVERY_MSG_FLOW_TEMPERATURE_SENSOR);
658   - flowTemperatureEntityAdded = true;
  663 +
  664 + // Test if Flow Temperature can be read from the boiler
  665 + if(readSensor(thermostat, OpenTherm::READ_DATA_ID::BOILER_WATER_TEMP, value, previousOTCommunicationMs)) {
  666 + Serial.printf("Flow water temperature from boiler is %.01f %\n", value);
  667 + // Use a static variable to keep track of the entity already being created
  668 + static bool flowTemperatureEntityAdded = false;
  669 + // Create the entity
  670 + if(!flowTemperatureEntityAdded) {
  671 + addEntity(client, "sensor", "flow_temperature", EASYOPENTHERM_MQTT_DISCOVERY_MSG_FLOW_TEMPERATURE_SENSOR);
  672 + flowTemperatureEntityAdded = true;
  673 + }
  674 + // Publish the Flow Temperature
  675 + snprintf(payload, sizeof payload, "{\"flow_temperature\":%.01f}", value);
  676 + topic = topicByReference("state_topic", EASYOPENTHERM_MQTT_DISCOVERY_MSG_FLOW_TEMPERATURE_SENSOR);
  677 + publish(client, topic, payload);
659 678 }
660   - // Publish the Flow Temperature
661   - snprintf(payload, sizeof payload, "{\"flow_temperature\":%.01f}", value);
662   - topic = topicByReference("state_topic", EASYOPENTHERM_MQTT_DISCOVERY_MSG_FLOW_TEMPERATURE_SENSOR);
663   - publish(client, topic, payload);
664   - }
665   - // Test if Return Temperature can be read from the boiler
666   - if(readSensor(thermostat, OpenTherm::READ_DATA_ID::RETURN_WATER_TEMPERATURE, value, previousOTCommunicationMs)) {
667   - Serial.printf("Return water temperature to boiler is %.01f %\n", value);
668   - // Use a static variable to keep track of the entity already being created
669   - static bool returnTemperatureEntityAdded = false;
670   - // Create the entity
671   - if(!returnTemperatureEntityAdded) {
672   - addEntity(client, "sensor", "return_temperature", EASYOPENTHERM_MQTT_DISCOVERY_MSG_RETURN_TEMPERATURE_SENSOR);
673   - returnTemperatureEntityAdded = true;
  679 +
  680 + // Test if Return Temperature can be read from the boiler
  681 + if(readSensor(thermostat, OpenTherm::READ_DATA_ID::RETURN_WATER_TEMPERATURE, value, previousOTCommunicationMs)) {
  682 + Serial.printf("Return water temperature to boiler is %.01f %\n", value);
  683 + // Use a static variable to keep track of the entity already being created
  684 + static bool returnTemperatureEntityAdded = false;
  685 + // Create the entity
  686 + if(!returnTemperatureEntityAdded) {
  687 + addEntity(client, "sensor", "return_temperature", EASYOPENTHERM_MQTT_DISCOVERY_MSG_RETURN_TEMPERATURE_SENSOR);
  688 + returnTemperatureEntityAdded = true;
  689 + }
  690 + // Publish the Return Temperature
  691 + snprintf(payload, sizeof payload, "{\"return_temperature\":%.01f}", value);
  692 + topic = topicByReference("state_topic", EASYOPENTHERM_MQTT_DISCOVERY_MSG_RETURN_TEMPERATURE_SENSOR);
  693 + publish(client, topic, payload);
674 694 }
675   - // Publish the Return Temperature
676   - snprintf(payload, sizeof payload, "{\"return_temperature\":%.01f}", value);
677   - topic = topicByReference("state_topic", EASYOPENTHERM_MQTT_DISCOVERY_MSG_RETURN_TEMPERATURE_SENSOR);
678   - publish(client, topic, payload);
  695 +
  696 + // Any other OpenTherm sensor that returns a float (f8.8) can be added in the same way as above by using the correct OpenTherm::READ_DATA_ID::, adding a dicovery JSON in JSONs.h, calling
  697 + // addEntity with the according parameters and publishing the value to the right topic in the right format
679 698 }
680   - // Any other OpenTherm sensor that returns a float (f8.8) can be added in the same way as above by using the correct OpenTherm::READ_DATA_ID::, adding a dicovery JSON in JSONs.h, calling
681   - // addEntity with the according parameters and publishing the value to the right topic in the right format
682 699 }
683 700 }
684 701  
... ... @@ -701,17 +718,15 @@ void updateRoomTemperatureStale(bool stale) {
701 718 // subscribeAll()
702 719 // Subsbribe to all needed topics: one for the room temperature setpoint, one for the mode (OFF / HEAT / COOL / AUTO) and one for
703 720 // the actual room temperature
704   -bool subscribeAll(MqttClient & client) {
705   - if(client.isConnected()) {
706   - subscribe(client, processSetpointTemperatureMessage, EASYOPENTHERM_MQTT_DISCOVERY_MSG_CLIMATE, "temperature_command_topic");
707   - subscribe(client, processClimateMessage, EASYOPENTHERM_MQTT_DISCOVERY_MSG_CLIMATE, "mode_command_topic");
708   - subscribe(client, processRoomTemperatureMessage, EASYOPENTHERM_MQTT_DISCOVERY_MSG_CLIMATE, "current_temperature_topic");
  721 +bool subscribeAll(PubSubClient & client) {
  722 + if(client.connected()) {
  723 + subscribe(client, EASYOPENTHERM_MQTT_DISCOVERY_MSG_CLIMATE, "temperature_command_topic");
  724 + subscribe(client, EASYOPENTHERM_MQTT_DISCOVERY_MSG_CLIMATE, "mode_command_topic");
  725 + subscribe(client, EASYOPENTHERM_MQTT_DISCOVERY_MSG_CLIMATE, "current_temperature_topic");
709 726 // subscribe(client, processClimateMessage, EASYOPENTHERM_MQTT_DISCOVERY_MSG_CLIMATE, "preset_mode_command_topic"); // Not implemented yet
710   -
711   - return true;
712 727 }
713 728  
714   - return false;
  729 + return client.connected();
715 730 }
716 731  
717 732  
... ... @@ -743,35 +758,49 @@ void loop() {
743 758  
744 759  
745 760 // Check if we are still connected to the MQTT broker. If not, reconnect and resubscribe to the topics we are interested in
746   - if(!mqtt->isConnected()) {
747   - ESP_LOGI(TAG, "MQTT disconnected");
748   -Serial.println("MQTT disconnected");
749   - wiFiClient.stop();
750   - wiFiClient.connect(mqtt_server, 1883);
751   - connectMQTT(*mqtt, MQTT_ID, mqtt_user, mqtt_password);
752   - subscribed = false;
  761 + if(!mqtt->connected()) {
  762 + Serial.println("MQTT disconnected");
  763 + // handle the TCP/IP socket connection outside of PubSubClient because of connection issues
  764 + if(!wiFiClient.connected()) {
  765 + Serial.printf("WiFi client disconnected, WiFi status = %d\n", WiFi.status());
  766 +// wiFiClient.stop();
  767 + wiFiClient.connect(mqtt_server, 1883);
  768 + if(wiFiClient.connected()) {
  769 + Serial.println("WiFi client reconnected");
  770 + }
  771 + }
  772 + if(wiFiClient.connected()) {
  773 + Serial.printf("WiFi client is connected, WiFi status = %d\n", WiFi.status());
  774 + bool MQTTConnected = connectMQTT(*mqtt, MQTT_ID, mqtt_user, mqtt_password);
  775 + Serial.printf("MQTT reconnected is %s\n", MQTTConnected ? "true" : "false");
  776 + subscribed = false;
  777 + } else {
  778 + Serial.println("WiFi client did not reconnected");
  779 + }
753 780 }
754 781  
755 782 // Subscribe to all relevant topics after a new connection
756 783 if(!subscribed) {
  784 + Serial.println("Subscribe to all relevant MQTT topics...");
757 785 if(subscribeAll(*mqtt)) {
758 786 subscribed = true;
759 787 }
760 788 }
761 789  
762   - uint32_t thermostatStateTimestampAligned = ldiv(time(nullptr), PUBLISH_STATE_UPDATE_INTERVAL).quot * PUBLISH_STATE_UPDATE_INTERVAL; // Align to exact intervals
  790 + uint32_t thermostatStateTimestampAligned = (time(nullptr) / PUBLISH_STATE_UPDATE_INTERVAL) * PUBLISH_STATE_UPDATE_INTERVAL; // Align to exact intervals
763 791 uint32_t thermostatStateTimestampMs = millis();
764   -
765 792 if(millis() - previousOTCommunicationMs >= 1000) { // OpenTherm specifies that primary to secondary communication should take place at least every second
766 793 // connected() becomes 'true' after communication has taken place between thermostat and boiler and the boiler's configuration flags are read
  794 +
767 795 if(!thermoStateMachine.connected()) {
768 796 // Try to contact the boiler and construct the thermostat's primary flags from the boiler's capabilities
769 797 OpenTherm::CONFIGURATION_FLAGS configurationFlags;
770 798 if(readSecondaryConfiguration(thermostat, configurationFlags, previousOTCommunicationMs)) {
  799 + Serial.println("OpenTherm secondary connected");
771 800 thermoStateMachine.initPrimaryFlags(configurationFlags);
772 801  
773   - updateClimateEntity((uint8_t(configurationFlags) & uint8_t(OpenTherm::CONFIGURATION_FLAGS::SECONDARY_COOLING)) != 0);
774   - updateDHWEntity((uint8_t(configurationFlags) & uint8_t(OpenTherm::CONFIGURATION_FLAGS::SECONDARY_DHW_PRESENT)) != 0);
  802 + updateClimateEntity(((uint8_t) configurationFlags & (uint8_t) OpenTherm::CONFIGURATION_FLAGS::SECONDARY_COOLING) != 0);
  803 + updateDHWEntity(((uint8_t) configurationFlags & (uint8_t) OpenTherm::CONFIGURATION_FLAGS::SECONDARY_DHW_PRESENT) != 0);
775 804 }
776 805 }
777 806  
... ... @@ -829,7 +858,7 @@ Serial.println(&quot;MQTT disconnected&quot;);
829 858 // Read status in every loop, to meet the 'communication each second' requirement
830 859 if(readStatus(thermostat, primaryFlags, statusFlags, previousOTCommunicationMs)) {
831 860 // Inform Home Assitant directly about the status; is automatically ignored if the flame status or CH / DHW status did not change
832   - updateFlameSensor(statusFlags);
  861 + updateFlameSensor(statusFlags);
833 862 updateDHWSensor(statusFlags);
834 863 }
835 864 }
... ... @@ -837,9 +866,10 @@ Serial.println(&quot;MQTT disconnected&quot;);
837 866  
838 867 // Publish the 'interval' sensors' at exact 'PUBLISH_STATE_UPDATE_INTERVAL' intervals
839 868 if(thermostatStateTimestampAligned - publishedThermostatStateTimestamp >= PUBLISH_STATE_UPDATE_INTERVAL) {
840   - updateSensors(*mqtt, CHSetpoint, previousOTCommunicationMs);
  869 + Serial.println("Update sensors by publishing sensor values to MQTT broker...");
  870 + updateSensors(*mqtt, thermoStateMachine.connected(), CHSetpoint, previousOTCommunicationMs);
841 871 publishedThermostatStateTimestamp = thermostatStateTimestampAligned;
842 872 }
843 873  
844   - mqtt->yield(100);
  874 + mqtt->loop();
845 875 }
... ...
examples/Advanced_Thermostat/MQTTHelpers.cpp
... ... @@ -41,7 +41,7 @@ const char * chipID() {
41 41 return serialNumber;
42 42 }
43 43  
44   -#include <machine/types.h>
  44 +//#include <machine/types.h>
45 45 /*
46 46 * shortID()
47 47 * Store the least significant two bytes of the ESP32 unique ID once. Return a pointer to the stored short ID. The ID is the same as the last two MAC bytes, in the same order
... ... @@ -59,7 +59,18 @@ const char * shortID() {
59 59 #endif
60 60  
61 61 uint8_t * MAC = (uint8_t *) &mac;
  62 +
  63 +// ESP32 Chip ID is cca4f003f784 => 0x84, 0xf7, 0x03, 0xf0, 0xa4, 0xcc, 0x00, 0x00
  64 +// ESP8266 Chip ID is 00c2005a3cc2 => 0xc2, 0x3c, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00
  65 +// So for the ESP32 MAC[4] and MAC[5] are the least significant bytes, and for the ESP8266 MAC[1] and MAC[0]
  66 +// Serial.print("Serial number bytes: "); for(size_t index = 0; index < 8; index++) Serial.printf("0x%02x, ", MAC[index]); Serial.println();
  67 +
  68 +// sprintf(shortNumber, "%02X%02X", MAC[4], MAC[5]);
  69 +#if defined(ESP32)
62 70 sprintf(shortNumber, "%02X%02X", MAC[4], MAC[5]);
  71 +#else
  72 + sprintf(shortNumber, "%02X%02X", MAC[1], MAC[0]);
  73 +#endif
63 74 ESP_LOGI(TAG, "Short ID is %s", shortNumber);
64 75 }
65 76  
... ... @@ -123,6 +134,7 @@ const char * topicByReference(const char * key,
123 134 DeserializationError error = deserializeJson(discoveryJsonPartDoc, discoveryMsgJson, DeserializationOption::Filter(filter));
124 135 if(error) {
125 136 ESP_LOGE(TAG, "Deserialize error %s for JSON '%s'", error.f_str(), discoveryMsgJson);
  137 +Serial.printf("Deserialize error %s for JSON '%s'\n", error.f_str(), discoveryMsgJson);
126 138  
127 139 return nullptr;
128 140 }
... ... @@ -131,12 +143,14 @@ const char * topicByReference(const char * key,
131 143 const char * topic = discoveryJsonPartDoc[key];
132 144 if(topic == nullptr) {
133 145 ESP_LOGE(TAG, "Key '%s' not found in JSON '%s'", key, discoveryMsgJson);
  146 +Serial.printf("Key '%s' not found in JSON '%s'\n", key, discoveryMsgJson);
134 147  
135 148 return nullptr;
136 149 }
137 150  
138 151 if(*topic == '~' && baseTopic == nullptr) {
139 152 ESP_LOGE(TAG, "Base topic '~' not found in JSON '%s'", discoveryMsgJson);
  153 +Serial.printf("Base topic '~' not found in JSON '%s'\n", discoveryMsgJson);
140 154  
141 155 return nullptr;
142 156 }
... ... @@ -149,6 +163,7 @@ const char * topicByReference(const char * key,
149 163 if(topicBuffer == nullptr) {
150 164 topicBufferSize = 0;
151 165 ESP_LOGE(TAG, "topicByReference out of memory");
  166 +Serial.printf("topicByReference out of memory\n");
152 167  
153 168 return nullptr;
154 169 }
... ... @@ -179,24 +194,18 @@ bool validJson(const char * discoveryMsgJson) {
179 194 }
180 195  
181 196  
182   -bool connectMQTT(MqttClient & client,
  197 +bool connectMQTT(PubSubClient & client,
183 198 const char * clientID,
184 199 const char * user,
185 200 const char * password) {
186 201 // Start new MQTT connection
187   - ESP_LOGI(TAG, "Connecting");
188   - MqttClient::ConnectResult connectResult;
  202 + ESP_LOGI(TAG, "Connecting...");
  203 +
189 204 // Connect
190   - MQTTPacket_connectData options = MQTTPacket_connectData_initializer;
191   - options.MQTTVersion = 4;
192   - options.clientID.cstring = (char *)clientID;
193   - options.username.cstring = (char *)user;
194   - options.password.cstring = (char *)password;
195   - options.cleansession = true;
196   - options.keepAliveInterval = 15; // 15 seconds
197   - MqttClient::Error::type rc = client.connect(options, connectResult);
198   - if (rc != MqttClient::Error::SUCCESS) {
199   - ESP_LOGE(TAG, "Connection error: %i", rc);
  205 + bool connectionResult = client.connect(clientID, user, password);
  206 +
  207 + if(!connectionResult) {
  208 + ESP_LOGE(TAG, "Connection error: %d", client.state());
200 209  
201 210 return false;
202 211 }
... ... @@ -205,25 +214,29 @@ bool connectMQTT(MqttClient &amp; client,
205 214 }
206 215  
207 216  
208   -bool publish(MqttClient & client,
  217 +bool publish(PubSubClient & client,
209 218 const char * topic,
210   - const char * payload,
  219 + const char * payload,
  220 + size_t payloadLength,
211 221 bool retained) {
212   - if(!client.isConnected()) return false;
  222 + if(payloadLength == 0) return true;
213 223  
214   - MqttClient::Message message;
215   - message.qos = MqttClient::QOS0;
216   - message.retained = retained;
217   - message.dup = true;
218   - message.payload = (void *)payload;
219   - message.payloadLen = strlen(payload);
220   - client.publish(topic, message);
221   -Serial.printf("PUBLISH topic is '%s' message is '%s'\n", topic, message.payload);
  224 + if(!client.beginPublish(topic, payloadLength, retained)) return false;
  225 + size_t bytesWritten = client.write((const unsigned char *) payload, payloadLength);
222 226  
223   - return true;
  227 + return client.endPublish() && bytesWritten == payloadLength;
224 228 }
225 229  
226 230  
  231 +bool publish(PubSubClient & client,
  232 + const char * topic,
  233 + const char * payload,
  234 + bool retained) {
  235 + size_t payloadLength = strlen(payload);
  236 +
  237 + return publish(client, topic, payload, payloadLength, retained);
  238 +}
  239 +
227 240 bool discoveryMsgToJsonDoc(JsonDocument & discoveryMsgDoc,
228 241 const char * discoveryMsgJson) {
229 242 DeserializationError error = deserializeJson(discoveryMsgDoc, discoveryMsgJson);
... ... @@ -243,35 +256,30 @@ bool discoveryMsgToJsonDoc(JsonDocument &amp; discoveryMsgDoc,
243 256 * Home Assistant MQTT components like 'climate', 'sensor' or 'binary_sensor' and object a unique ID to differentiate between e.g. two sensors in the same
244 257 * device.
245 258 */
246   -bool addEntity(MqttClient & client,
  259 +bool addEntity(PubSubClient & client,
247 260 const char * component,
248 261 const char * object,
249 262 JsonDocument & discoveryMsgDoc) {
250   - if(!client.isConnected()) return false;
  263 + if(!client.connected()) return false;
251 264  
252 265 size_t jsonSize = measureJson(discoveryMsgDoc);
253 266 char discoveryMsgJson[jsonSize + 1];
254 267 serializeJson(discoveryMsgDoc, discoveryMsgJson, sizeof discoveryMsgJson);
255 268  
256   - ESP_LOGI(TAG, "Discovery topic is '%s'\n", (String("homeassistant/") + String(component) + String("/") + String(chipID()) + String("/") + String(object) + String("/config")).c_str());
257   - ESP_LOGI(TAG, "Discovery message is '%s'", discoveryMsgJson);
  269 + size_t topicSize = sizeof("homeassistant/") - 1 + strlen(component) + sizeof("/") - 1 + strlen(chipID()) + sizeof("/") - 1 + strlen(object) + sizeof("/config") - 1 + 1;
  270 + char topic[topicSize];
  271 + sprintf(topic, "homeassistant/%s/%s/%s/config", component, chipID(), object);
258 272  
259   - MqttClient::Message message;
260   - message.qos = MqttClient::QOS0;
261   - message.retained = false;
262   - message.dup = false;
263   - message.payload = (void*) discoveryMsgJson;
264   - message.payloadLen = jsonSize;
265   - client.publish((String("homeassistant/") + String(component) + String("/") + String(chipID()) + String("/") + String(object) + String("/config")).c_str(), message);
266   -Serial.printf("PUBLISH topic is '%s' message is '%s'\n", (String("homeassistant/") + String(component) + String("/") + String(chipID()) + String("/") + String(object) + String("/config")).c_str(), message.payload);
  273 + ESP_LOGI(TAG, "Discovery topic is '%s'\n", topic);
  274 + ESP_LOGI(TAG, "Discovery message is '%s'", discoveryMsgJson);
267 275  
268   - return true;
  276 + return publish(client, topic, discoveryMsgJson);
269 277 }
270 278  
271 279  
272 280 // addEntity()
273 281 // Same as above but providing the discovery message as a const char * JSON
274   -bool addEntity(MqttClient & client,
  282 +bool addEntity(PubSubClient & client,
275 283 const char * component,
276 284 const char * object,
277 285 const char * discoveryMsgJson) {
... ... @@ -287,23 +295,14 @@ bool addEntity(MqttClient &amp; client,
287 295 * Subscribe to the topic at at the given key in the discovery message. Before subscription the topic in the discovery
288 296 * message is expanded to the full topic by prefixing the "~" path.
289 297 */
290   -bool subscribe(MqttClient & client,
291   - MqttClient::MessageHandlerCbk cbk,
  298 +bool subscribe(PubSubClient & client,
292 299 const char * discoveryMessage,
293 300 const char * key) {
294 301 const char * topic = topicByReference(key, discoveryMessage);
295 302 if(topic == nullptr) return false;
296 303  
297   - MqttClient::Error::type rc = client.subscribe(topic, MqttClient::QOS0, cbk);
298   - if (rc != MqttClient::Error::SUCCESS) {
299   - ESP_LOGE(TAG, "Subscribe error: %i for topic '%s'", rc, topic);
300   - ESP_LOGE(TAG, "Drop connection");
301   - client.disconnect();
  304 + ESP_LOGI(TAG, "Subscribe to '%s'", topic);
  305 +Serial.printf("Subscribe to '%s'\n", topic);
302 306  
303   - return false;
304   - }
305   - ESP_LOGI(TAG, "Subscribed to '%s'", topic);
306   -Serial.printf("Subscribed to '%s'\n", topic);
307   -
308   - return true;
309   -}
310 307 \ No newline at end of file
  308 + return client.subscribe(topic);
  309 +}
... ...
examples/Advanced_Thermostat/MQTTHelpers.h
... ... @@ -2,7 +2,7 @@
2 2  
3 3  
4 4 #include <Arduino.h>
5   -#include <MqttClient.h>
  5 +#include <PubSubClient.h>
6 6 #include <ArduinoJson.h>
7 7  
8 8  
... ... @@ -12,20 +12,6 @@ const char * chipID();
12 12  
13 13 const char * shortID();
14 14  
15   -
16   -// ============== Object to supply system functions ============================
17   -class System: public MqttClient::System {
18   -public:
19   -
20   - unsigned long millis() const {
21   - return ::millis();
22   - }
23   -
24   - void yield(void) {
25   - ::yield();
26   - }
27   -};
28   -
29 15 void discoveryMessageSetIDs(char * discoveryMsgJson);
30 16  
31 17 const char * topicByReference(const char * key,
... ... @@ -33,12 +19,18 @@ const char * topicByReference(const char * key,
33 19  
34 20 bool validJson(const char * discoveryMsgJson);
35 21  
36   -bool connectMQTT(MqttClient & client,
  22 +bool connectMQTT(PubSubClient & client,
37 23 const char * clientID,
38 24 const char * user,
39 25 const char * password);
40 26  
41   -bool publish(MqttClient & client,
  27 +bool publish(PubSubClient & client,
  28 + const char * topic,
  29 + const char * payload,
  30 + size_t payloadLength,
  31 + bool retained = false);
  32 +
  33 +bool publish(PubSubClient & client,
42 34 const char * topic,
43 35 const char * payload,
44 36 bool retained = false);
... ... @@ -46,17 +38,16 @@ bool publish(MqttClient &amp; client,
46 38 bool discoveryMsgToJsonDoc(JsonDocument & discoveryMsgDoc,
47 39 const char * discoveryMsgJson);
48 40  
49   -bool addEntity(MqttClient & client,
  41 +bool addEntity(PubSubClient & client,
50 42 const char * component,
51 43 const char * object,
52 44 JsonDocument & discoveryMsgDoc);
53 45  
54   -bool addEntity(MqttClient & client,
  46 +bool addEntity(PubSubClient & client,
55 47 const char * component,
56 48 const char * object,
57 49 const char * discoveryMsgJson);
58 50  
59   -bool subscribe(MqttClient & client,
60   - MqttClient::MessageHandlerCbk cbk,
  51 +bool subscribe(PubSubClient & client,
61 52 const char * discoveryMessage,
62 53 const char * key);
63 54 \ No newline at end of file
... ...
examples/Advanced_Thermostat/OpenThermHelpers.cpp
... ... @@ -134,7 +134,7 @@ bool readSecondaryConfiguration(OpenTherm &amp; thermostat,
134 134 return true;
135 135 }
136 136  
137   - configurationFlags = OpenTherm::CONFIGURATION_FLAGS(flags);
  137 + configurationFlags = (OpenTherm::CONFIGURATION_FLAGS) flags;
138 138  
139 139 return true;
140 140 } else {
... ...
examples/Advanced_Thermostat/ThermoStateMachine.cpp
... ... @@ -25,19 +25,20 @@ bool ThermoStateMachine::connected() {
25 25  
26 26  
27 27 void ThermoStateMachine::initPrimaryFlags(OpenTherm::CONFIGURATION_FLAGS configurationFlags) {
28   - _configurationFlags = uint8_t(configurationFlags);
  28 + _configurationFlags = (uint8_t) configurationFlags;
29 29 _primaryFlags = 0;
30 30 // Enable DHW if boiler is capable of DHW
31   - if(_configurationFlags & uint8_t(OpenTherm::CONFIGURATION_FLAGS::SECONDARY_DHW_PRESENT)) {
32   - _primaryFlags |= uint8_t(OpenTherm::STATUS_FLAGS::PRIMARY_DHW_ENABLE);
  31 + if(_configurationFlags & ((uint8_t) OpenTherm::CONFIGURATION_FLAGS::SECONDARY_DHW_PRESENT)) {
  32 + _primaryFlags |= (uint8_t) OpenTherm::STATUS_FLAGS::PRIMARY_DHW_ENABLE;
33 33 }
34 34 // If boiler is capable of cooling, signal this by setting 'canCool'
35   - _canCool = (_configurationFlags & uint8_t(OpenTherm::CONFIGURATION_FLAGS::SECONDARY_COOLING)) != 0;
  35 + _canCool = (_configurationFlags & (uint8_t) OpenTherm::CONFIGURATION_FLAGS::SECONDARY_COOLING) != 0;
36 36  
37 37 // Do not enable OTC
38   - // _primaryFlags |= uint8_t(OpenTherm::STATUS_FLAGS::PRIMARY_OTC_ENABLE);
  38 + // _primaryFlags |= (uint8_t) OpenTherm::STATUS_FLAGS::PRIMARY_OTC_ENABLE;
39 39  
40 40 _state = ThermostatState::OFF;
  41 + _state_c_str = "Off";
41 42 }
42 43  
43 44  
... ... @@ -195,8 +196,11 @@ bool ThermoStateMachine::update(float ro
195 196 _previousRoomTemperatureSetpoint = roomTemperatureSetpoint;
196 197  
197 198 return false;
  199 + } else if(_state == ThermostatState::OFF) {
  200 +
  201 + return false;
198 202 } else {
199   - Serial.println("Unknown state");
  203 + Serial.printf("Unknown state %d\n", _state);
200 204  
201 205 return false;
202 206 }
... ... @@ -263,5 +267,3 @@ bool ThermoStateMachine::getRoomTemperatureStale() {
263 267 const char * ThermoStateMachine::c_str() {
264 268 return _state_c_str;
265 269 }
266   -
267   -
... ...