Commit aedbed70d121a026b53042ce963765fc77bace0b
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
Showing
5 changed files
with
257 additions
and
235 deletions
examples/Advanced_Thermostat/Advanced_Thermostat.ino
| @@ -112,21 +112,16 @@ static const char * TAG = __FILE__; | @@ -112,21 +112,16 @@ static const char * TAG = __FILE__; | ||
| 112 | 112 | ||
| 113 | #include <Arduino.h> | 113 | #include <Arduino.h> |
| 114 | 114 | ||
| 115 | +#if defined(ESP8266) | ||
| 116 | +#include <ESP8266WiFi.h> | ||
| 117 | +#else | ||
| 115 | #include <WiFi.h> | 118 | #include <WiFi.h> |
| 119 | +#endif | ||
| 116 | 120 | ||
| 117 | #include <time.h> | 121 | #include <time.h> |
| 118 | 122 | ||
| 119 | #include <ArduinoJson.h> | 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 | #include <OneWire.h> | 125 | #include <OneWire.h> |
| 131 | #include <DallasTemperature.h> | 126 | #include <DallasTemperature.h> |
| 132 | 127 | ||
| @@ -149,6 +144,7 @@ const char * password = "YOUR WIFI PASSWORD"; | @@ -149,6 +144,7 @@ const char * password = "YOUR WIFI PASSWORD"; | ||
| 149 | const char * mqtt_server = "YOUR MQTT SERVER NAME OR IP ADDRESS"; | 144 | const char * mqtt_server = "YOUR MQTT SERVER NAME OR IP ADDRESS"; |
| 150 | const char * mqtt_user = "YOUR MQTT USER NAME"; | 145 | const char * mqtt_user = "YOUR MQTT USER NAME"; |
| 151 | const char * mqtt_password = "YOUR MQTT PASSWORD"; | 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 | // Your time zone, used to display times correctly (and needed for WiFiClientSecure TLS certificate validation, if used) | 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 = "YOUR MQTT PASSWORD"; | @@ -156,8 +152,8 @@ const char * mqtt_password = "YOUR MQTT PASSWORD"; | ||
| 156 | #define TIME_ZONE TZ_Europe_Amsterdam | 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 | // Define DALLAS, the GPIO pin used for the Dallas sensor, if used | 157 | // Define DALLAS, the GPIO pin used for the Dallas sensor, if used |
| 162 | 158 | ||
| 163 | #if defined(ARDUINO_LOLIN_S2_MINI) | 159 | #if defined(ARDUINO_LOLIN_S2_MINI) |
| @@ -168,12 +164,32 @@ const char * mqtt_password = "YOUR MQTT PASSWORD"; | @@ -168,12 +164,32 @@ const char * mqtt_password = "YOUR MQTT PASSWORD"; | ||
| 168 | #define OT_RX_PIN (10) | 164 | #define OT_RX_PIN (10) |
| 169 | #define OT_TX_PIN (8) | 165 | #define OT_TX_PIN (8) |
| 170 | #define DALLAS (4) | 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 | #else | 186 | #else |
| 172 | #define OT_RX_PIN (35) | 187 | #define OT_RX_PIN (35) |
| 173 | #define OT_TX_PIN (33) | 188 | #define OT_TX_PIN (33) |
| 174 | #define DALLAS (-1) | 189 | #define DALLAS (-1) |
| 175 | #endif | 190 | #endif |
| 176 | 191 | ||
| 192 | + | ||
| 177 | // The maximum room temperature | 193 | // The maximum room temperature |
| 178 | #define ROOM_TEMPERATURE_MAX_SETPOINT (30.0f) | 194 | #define ROOM_TEMPERATURE_MAX_SETPOINT (30.0f) |
| 179 | // The minimum room temperature | 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,8 +228,7 @@ const size_t MSG_BUFFER_RECV_SIZE = 256; // Too small a receive buffer will fai | ||
| 212 | // Define a global WiFiClient instance for WiFi connection | 228 | // Define a global WiFiClient instance for WiFi connection |
| 213 | WiFiClient wiFiClient; | 229 | WiFiClient wiFiClient; |
| 214 | 230 | ||
| 215 | -#define MQTT_ID "EasyOpenTherm" | ||
| 216 | -static MqttClient *mqtt = NULL; | 231 | +PubSubClient *mqtt = NULL; |
| 217 | 232 | ||
| 218 | 233 | ||
| 219 | // GPIO where the DS18B20 is connected to, set to '-1' if not used | 234 | // GPIO where the DS18B20 is connected to, set to '-1' if not used |
| @@ -282,12 +297,32 @@ float roomTemperature; | @@ -282,12 +297,32 @@ float roomTemperature; | ||
| 282 | 297 | ||
| 283 | 298 | ||
| 284 | // ============== Subscription callbacks ======================================== | 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 | Serial.println("processRoomTemperatureMessage"); | 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 | StaticJsonDocument<32> roomTemperatureMsgDoc; | 327 | StaticJsonDocument<32> roomTemperatureMsgDoc; |
| 293 | DeserializationError error = deserializeJson(roomTemperatureMsgDoc, payload); | 328 | DeserializationError error = deserializeJson(roomTemperatureMsgDoc, payload); |
| @@ -314,12 +349,7 @@ Serial.printf("Received room temperature %.01f ºC\n", roomTemperature); | @@ -314,12 +349,7 @@ Serial.printf("Received room temperature %.01f ºC\n", 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 | float setpoint; | 353 | float setpoint; |
| 324 | if(sscanf(payload, "%f", &setpoint) != 1) { | 354 | if(sscanf(payload, "%f", &setpoint) != 1) { |
| 325 | ESP_LOGE(TAG, "Payload is not a float: '%s'", payload); | 355 | ESP_LOGE(TAG, "Payload is not a float: '%s'", payload); |
| @@ -333,11 +363,7 @@ Serial.printf("Received room temperature setpoint '%s'\n", payload); | @@ -333,11 +363,7 @@ Serial.printf("Received room temperature setpoint '%s'\n", 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 | ESP_LOGI(TAG, | 367 | ESP_LOGI(TAG, |
| 342 | "Message arrived: qos %d, retained %d, dup %d, packetid %d, payload:[%s]", | 368 | "Message arrived: qos %d, retained %d, dup %d, packetid %d, payload:[%s]", |
| 343 | msg.qos, msg.retained, msg.dup, msg.id, payload | 369 | msg.qos, msg.retained, msg.dup, msg.id, payload |
| @@ -362,27 +388,28 @@ void setup() { | @@ -362,27 +388,28 @@ void setup() { | ||
| 362 | delay(5000); // For debug only: give the Serial Monitor some time to connect to the native USB of the MCU for output | 388 | delay(5000); // For debug only: give the Serial Monitor some time to connect to the native USB of the MCU for output |
| 363 | Serial.println("\n\nStarted"); | 389 | Serial.println("\n\nStarted"); |
| 364 | Serial.printf("Chip ID is %s\n", chipID()); | 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 | Serial.printf("OpenTherm RX pin is %d, TX pin is %d\n", OT_RX_PIN, OT_TX_PIN); | 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 | // Connect WiFi | 397 | // Connect WiFi |
| 372 | WiFi.mode(WIFI_STA); | 398 | WiFi.mode(WIFI_STA); |
| 373 | WiFi.setAutoReconnect(true); | 399 | WiFi.setAutoReconnect(true); |
| 400 | + WiFi.setAutoReconnect(false); | ||
| 374 | WiFi.begin(ssid, password); | 401 | WiFi.begin(ssid, password); |
| 375 | 402 | ||
| 376 | uint32_t startMillis = millis(); | 403 | uint32_t startMillis = millis(); |
| 377 | while (WiFi.status() != WL_CONNECTED) { | 404 | while (WiFi.status() != WL_CONNECTED) { |
| 378 | delay(500); | 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 | if(millis() - startMillis > 15000) ESP.restart(); | 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 | // Set time and date, necessary for HTTPS certificate validation | 414 | // Set time and date, necessary for HTTPS certificate validation |
| 388 | configTzTime(TIME_ZONE, "pool.ntp.org", "time.nist.gov"); | 415 | configTzTime(TIME_ZONE, "pool.ntp.org", "time.nist.gov"); |
| @@ -400,7 +427,11 @@ void setup() { | @@ -400,7 +427,11 @@ void setup() { | ||
| 400 | 427 | ||
| 401 | if(millis() - startMillis > 15000) ESP.restart(); | 428 | if(millis() - startMillis > 15000) ESP.restart(); |
| 402 | } | 429 | } |
| 430 | +#if defined(ESP8266) | ||
| 431 | + digitalWrite(LED_BUILTIN, HIGH); | ||
| 432 | +#else | ||
| 403 | digitalWrite(LED_BUILTIN, LOW); | 433 | digitalWrite(LED_BUILTIN, LOW); |
| 434 | +#endif | ||
| 404 | Serial.println(); | 435 | Serial.println(); |
| 405 | 436 | ||
| 406 | const struct tm * timeinfo = localtime(&now); | 437 | const struct tm * timeinfo = localtime(&now); |
| @@ -417,32 +448,8 @@ void setup() { | @@ -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 | wiFiClient.connect(mqtt_server, 1883); | 453 | wiFiClient.connect(mqtt_server, 1883); |
| 447 | if(!wiFiClient.connected()) { | 454 | if(!wiFiClient.connected()) { |
| 448 | ESP_LOGE(TAG, "Can't establish the TCP connection"); | 455 | ESP_LOGE(TAG, "Can't establish the TCP connection"); |
| @@ -450,7 +457,10 @@ void setup() { | @@ -450,7 +457,10 @@ void setup() { | ||
| 450 | ESP.restart(); | 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 | bool MQTTConnected = connectMQTT(*mqtt, MQTT_ID, mqtt_user, mqtt_password); | 465 | bool MQTTConnected = connectMQTT(*mqtt, MQTT_ID, mqtt_user, mqtt_password); |
| 456 | if(MQTTConnected) { | 466 | if(MQTTConnected) { |
| @@ -487,14 +497,14 @@ Serial.println("MQTT NOT connected"); | @@ -487,14 +497,14 @@ Serial.println("MQTT NOT connected"); | ||
| 487 | if(!validJson(EASYOPENTHERM_MQTT_DISCOVERY_MSG_DHW_BINARY_SENSOR)) Serial.printf("Invalid JSON '%s'\n", EASYOPENTHERM_MQTT_DISCOVERY_MSG_DHW_BINARY_SENSOR); | 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 | // Add all 'always present' entities (the other entities are added only if supported by the boiler) | 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 | addEntity(*mqtt, "climate", "climate", EASYOPENTHERM_MQTT_DISCOVERY_MSG_CLIMATE); | 501 | addEntity(*mqtt, "climate", "climate", EASYOPENTHERM_MQTT_DISCOVERY_MSG_CLIMATE); |
| 491 | addEntity(*mqtt, "sensor", "boiler_setpoint", EASYOPENTHERM_MQTT_DISCOVERY_MSG_SETPOINT_SENSOR); | 502 | addEntity(*mqtt, "sensor", "boiler_setpoint", EASYOPENTHERM_MQTT_DISCOVERY_MSG_SETPOINT_SENSOR); |
| 492 | addEntity(*mqtt, "sensor", "thermostat_rssi", EASYOPENTHERM_MQTT_DISCOVERY_MSG_RSSI_SENSOR); | 503 | addEntity(*mqtt, "sensor", "thermostat_rssi", EASYOPENTHERM_MQTT_DISCOVERY_MSG_RSSI_SENSOR); |
| 493 | addEntity(*mqtt, "binary_sensor", "boiler_flame", EASYOPENTHERM_MQTT_DISCOVERY_MSG_FLAME_BINARY_SENSOR); | 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 | // Set all sensors, except those that are directly updated, to 'None', the binary sensor to 'Unknown' | 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 | publish(*mqtt, topicByReference("state_topic", EASYOPENTHERM_MQTT_DISCOVERY_MSG_SETPOINT_SENSOR), "{\"ch_setpoint\":\"None\"}"); | 508 | publish(*mqtt, topicByReference("state_topic", EASYOPENTHERM_MQTT_DISCOVERY_MSG_SETPOINT_SENSOR), "{\"ch_setpoint\":\"None\"}"); |
| 499 | publish(*mqtt, topicByReference("state_topic", EASYOPENTHERM_MQTT_DISCOVERY_MSG_FLOW_TEMPERATURE_SENSOR), "{\"flow_temperature\":\"None\"}"); | 509 | publish(*mqtt, topicByReference("state_topic", EASYOPENTHERM_MQTT_DISCOVERY_MSG_FLOW_TEMPERATURE_SENSOR), "{\"flow_temperature\":\"None\"}"); |
| 500 | publish(*mqtt, topicByReference("state_topic", EASYOPENTHERM_MQTT_DISCOVERY_MSG_RETURN_TEMPERATURE_SENSOR), "{\"return_temperature\":\"None\"}"); | 510 | publish(*mqtt, topicByReference("state_topic", EASYOPENTHERM_MQTT_DISCOVERY_MSG_RETURN_TEMPERATURE_SENSOR), "{\"return_temperature\":\"None\"}"); |
| @@ -511,7 +521,8 @@ Serial.println("MQTT NOT connected"); | @@ -511,7 +521,8 @@ Serial.println("MQTT NOT connected"); | ||
| 511 | // If the boikler can both heat and cool adds 'auto', 'off', 'cool' and 'heat' to the thermmostat modes | 521 | // If the boikler can both heat and cool adds 'auto', 'off', 'cool' and 'heat' to the thermmostat modes |
| 512 | // If the boikler can only heat adds 'off' and 'heat' to the thermmostat modes | 522 | // If the boikler can only heat adds 'off' and 'heat' to the thermmostat modes |
| 513 | void updateClimateEntity(bool canCool) { | 523 | void updateClimateEntity(bool canCool) { |
| 514 | - StaticJsonDocument<fullJsonDocSize> discoveryMsgDoc; | 524 | +// StaticJsonDocument<fullJsonDocSize> discoveryMsgDoc; |
| 525 | + DynamicJsonDocument discoveryMsgDoc(fullJsonDocSize); | ||
| 515 | 526 | ||
| 516 | if(discoveryMsgToJsonDoc(discoveryMsgDoc, EASYOPENTHERM_MQTT_DISCOVERY_MSG_CLIMATE)) { | 527 | if(discoveryMsgToJsonDoc(discoveryMsgDoc, EASYOPENTHERM_MQTT_DISCOVERY_MSG_CLIMATE)) { |
| 517 | JsonArray modesArray = discoveryMsgDoc["modes"]; | 528 | JsonArray modesArray = discoveryMsgDoc["modes"]; |
| @@ -552,7 +563,6 @@ void updateDHWEntity(bool enableDHW) { | @@ -552,7 +563,6 @@ void updateDHWEntity(bool enableDHW) { | ||
| 552 | void updateFlameSensor(uint8_t statusFlags) { | 563 | void updateFlameSensor(uint8_t statusFlags) { |
| 553 | static bool flameSensorInitialised = false; | 564 | static bool flameSensorInitialised = false; |
| 554 | static uint8_t previousStatusFlags = 0; | 565 | static uint8_t previousStatusFlags = 0; |
| 555 | -Serial.printf("Secondary status flags is 0x%02x\n", statusFlags); | ||
| 556 | 566 | ||
| 557 | if(!flameSensorInitialised || (statusFlags & uint8_t(OpenTherm::STATUS_FLAGS::SECONDARY_FLAME_STATUS)) != (previousStatusFlags & uint8_t(OpenTherm::STATUS_FLAGS::SECONDARY_FLAME_STATUS))) { | 567 | if(!flameSensorInitialised || (statusFlags & uint8_t(OpenTherm::STATUS_FLAGS::SECONDARY_FLAME_STATUS)) != (previousStatusFlags & uint8_t(OpenTherm::STATUS_FLAGS::SECONDARY_FLAME_STATUS))) { |
| 558 | const char * topic = topicByReference("state_topic", EASYOPENTHERM_MQTT_DISCOVERY_MSG_FLAME_BINARY_SENSOR); | 568 | const char * topic = topicByReference("state_topic", EASYOPENTHERM_MQTT_DISCOVERY_MSG_FLAME_BINARY_SENSOR); |
| @@ -591,10 +601,11 @@ void updateDHWSensor(uint8_t statusFlags) { | @@ -591,10 +601,11 @@ void updateDHWSensor(uint8_t statusFlags) { | ||
| 591 | // updateSensors | 601 | // updateSensors |
| 592 | // 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 | 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 | // an entity yet in Home Assistant are created by sending the discovery JSON to the right '/config' topic. | 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 | float CHSetpoint, | 606 | float CHSetpoint, |
| 596 | uint32_t & previousOTCommunicationMs) { | 607 | uint32_t & previousOTCommunicationMs) { |
| 597 | - if(client.isConnected()) { | 608 | + if(client.connected()) { |
| 598 | char payload[64]; | 609 | char payload[64]; |
| 599 | const char * topic; | 610 | const char * topic; |
| 600 | 611 | ||
| @@ -611,74 +622,80 @@ void updateSensors(MqttClient & client, | @@ -611,74 +622,80 @@ void updateSensors(MqttClient & client, | ||
| 611 | publish(client, topic, payload); | 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,17 +718,15 @@ void updateRoomTemperatureStale(bool stale) { | ||
| 701 | // subscribeAll() | 718 | // subscribeAll() |
| 702 | // Subsbribe to all needed topics: one for the room temperature setpoint, one for the mode (OFF / HEAT / COOL / AUTO) and one for | 719 | // Subsbribe to all needed topics: one for the room temperature setpoint, one for the mode (OFF / HEAT / COOL / AUTO) and one for |
| 703 | // the actual room temperature | 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 | // subscribe(client, processClimateMessage, EASYOPENTHERM_MQTT_DISCOVERY_MSG_CLIMATE, "preset_mode_command_topic"); // Not implemented yet | 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,35 +758,49 @@ void loop() { | ||
| 743 | 758 | ||
| 744 | 759 | ||
| 745 | // Check if we are still connected to the MQTT broker. If not, reconnect and resubscribe to the topics we are interested in | 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 | // Subscribe to all relevant topics after a new connection | 782 | // Subscribe to all relevant topics after a new connection |
| 756 | if(!subscribed) { | 783 | if(!subscribed) { |
| 784 | + Serial.println("Subscribe to all relevant MQTT topics..."); | ||
| 757 | if(subscribeAll(*mqtt)) { | 785 | if(subscribeAll(*mqtt)) { |
| 758 | subscribed = true; | 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 | uint32_t thermostatStateTimestampMs = millis(); | 791 | uint32_t thermostatStateTimestampMs = millis(); |
| 764 | - | ||
| 765 | if(millis() - previousOTCommunicationMs >= 1000) { // OpenTherm specifies that primary to secondary communication should take place at least every second | 792 | if(millis() - previousOTCommunicationMs >= 1000) { // OpenTherm specifies that primary to secondary communication should take place at least every second |
| 766 | // connected() becomes 'true' after communication has taken place between thermostat and boiler and the boiler's configuration flags are read | 793 | // connected() becomes 'true' after communication has taken place between thermostat and boiler and the boiler's configuration flags are read |
| 794 | + | ||
| 767 | if(!thermoStateMachine.connected()) { | 795 | if(!thermoStateMachine.connected()) { |
| 768 | // Try to contact the boiler and construct the thermostat's primary flags from the boiler's capabilities | 796 | // Try to contact the boiler and construct the thermostat's primary flags from the boiler's capabilities |
| 769 | OpenTherm::CONFIGURATION_FLAGS configurationFlags; | 797 | OpenTherm::CONFIGURATION_FLAGS configurationFlags; |
| 770 | if(readSecondaryConfiguration(thermostat, configurationFlags, previousOTCommunicationMs)) { | 798 | if(readSecondaryConfiguration(thermostat, configurationFlags, previousOTCommunicationMs)) { |
| 799 | + Serial.println("OpenTherm secondary connected"); | ||
| 771 | thermoStateMachine.initPrimaryFlags(configurationFlags); | 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("MQTT disconnected"); | @@ -829,7 +858,7 @@ Serial.println("MQTT disconnected"); | ||
| 829 | // Read status in every loop, to meet the 'communication each second' requirement | 858 | // Read status in every loop, to meet the 'communication each second' requirement |
| 830 | if(readStatus(thermostat, primaryFlags, statusFlags, previousOTCommunicationMs)) { | 859 | if(readStatus(thermostat, primaryFlags, statusFlags, previousOTCommunicationMs)) { |
| 831 | // Inform Home Assitant directly about the status; is automatically ignored if the flame status or CH / DHW status did not change | 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 | updateDHWSensor(statusFlags); | 862 | updateDHWSensor(statusFlags); |
| 834 | } | 863 | } |
| 835 | } | 864 | } |
| @@ -837,9 +866,10 @@ Serial.println("MQTT disconnected"); | @@ -837,9 +866,10 @@ Serial.println("MQTT disconnected"); | ||
| 837 | 866 | ||
| 838 | // Publish the 'interval' sensors' at exact 'PUBLISH_STATE_UPDATE_INTERVAL' intervals | 867 | // Publish the 'interval' sensors' at exact 'PUBLISH_STATE_UPDATE_INTERVAL' intervals |
| 839 | if(thermostatStateTimestampAligned - publishedThermostatStateTimestamp >= PUBLISH_STATE_UPDATE_INTERVAL) { | 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 | publishedThermostatStateTimestamp = thermostatStateTimestampAligned; | 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,7 +41,7 @@ const char * chipID() { | ||
| 41 | return serialNumber; | 41 | return serialNumber; |
| 42 | } | 42 | } |
| 43 | 43 | ||
| 44 | -#include <machine/types.h> | 44 | +//#include <machine/types.h> |
| 45 | /* | 45 | /* |
| 46 | * shortID() | 46 | * shortID() |
| 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 | 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,7 +59,18 @@ const char * shortID() { | ||
| 59 | #endif | 59 | #endif |
| 60 | 60 | ||
| 61 | uint8_t * MAC = (uint8_t *) &mac; | 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 | sprintf(shortNumber, "%02X%02X", MAC[4], MAC[5]); | 70 | sprintf(shortNumber, "%02X%02X", MAC[4], MAC[5]); |
| 71 | +#else | ||
| 72 | + sprintf(shortNumber, "%02X%02X", MAC[1], MAC[0]); | ||
| 73 | +#endif | ||
| 63 | ESP_LOGI(TAG, "Short ID is %s", shortNumber); | 74 | ESP_LOGI(TAG, "Short ID is %s", shortNumber); |
| 64 | } | 75 | } |
| 65 | 76 | ||
| @@ -123,6 +134,7 @@ const char * topicByReference(const char * key, | @@ -123,6 +134,7 @@ const char * topicByReference(const char * key, | ||
| 123 | DeserializationError error = deserializeJson(discoveryJsonPartDoc, discoveryMsgJson, DeserializationOption::Filter(filter)); | 134 | DeserializationError error = deserializeJson(discoveryJsonPartDoc, discoveryMsgJson, DeserializationOption::Filter(filter)); |
| 124 | if(error) { | 135 | if(error) { |
| 125 | ESP_LOGE(TAG, "Deserialize error %s for JSON '%s'", error.f_str(), discoveryMsgJson); | 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 | return nullptr; | 139 | return nullptr; |
| 128 | } | 140 | } |
| @@ -131,12 +143,14 @@ const char * topicByReference(const char * key, | @@ -131,12 +143,14 @@ const char * topicByReference(const char * key, | ||
| 131 | const char * topic = discoveryJsonPartDoc[key]; | 143 | const char * topic = discoveryJsonPartDoc[key]; |
| 132 | if(topic == nullptr) { | 144 | if(topic == nullptr) { |
| 133 | ESP_LOGE(TAG, "Key '%s' not found in JSON '%s'", key, discoveryMsgJson); | 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 | return nullptr; | 148 | return nullptr; |
| 136 | } | 149 | } |
| 137 | 150 | ||
| 138 | if(*topic == '~' && baseTopic == nullptr) { | 151 | if(*topic == '~' && baseTopic == nullptr) { |
| 139 | ESP_LOGE(TAG, "Base topic '~' not found in JSON '%s'", discoveryMsgJson); | 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 | return nullptr; | 155 | return nullptr; |
| 142 | } | 156 | } |
| @@ -149,6 +163,7 @@ const char * topicByReference(const char * key, | @@ -149,6 +163,7 @@ const char * topicByReference(const char * key, | ||
| 149 | if(topicBuffer == nullptr) { | 163 | if(topicBuffer == nullptr) { |
| 150 | topicBufferSize = 0; | 164 | topicBufferSize = 0; |
| 151 | ESP_LOGE(TAG, "topicByReference out of memory"); | 165 | ESP_LOGE(TAG, "topicByReference out of memory"); |
| 166 | +Serial.printf("topicByReference out of memory\n"); | ||
| 152 | 167 | ||
| 153 | return nullptr; | 168 | return nullptr; |
| 154 | } | 169 | } |
| @@ -179,24 +194,18 @@ bool validJson(const char * discoveryMsgJson) { | @@ -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 | const char * clientID, | 198 | const char * clientID, |
| 184 | const char * user, | 199 | const char * user, |
| 185 | const char * password) { | 200 | const char * password) { |
| 186 | // Start new MQTT connection | 201 | // Start new MQTT connection |
| 187 | - ESP_LOGI(TAG, "Connecting"); | ||
| 188 | - MqttClient::ConnectResult connectResult; | 202 | + ESP_LOGI(TAG, "Connecting..."); |
| 203 | + | ||
| 189 | // Connect | 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 | return false; | 210 | return false; |
| 202 | } | 211 | } |
| @@ -205,25 +214,29 @@ bool connectMQTT(MqttClient & client, | @@ -205,25 +214,29 @@ bool connectMQTT(MqttClient & client, | ||
| 205 | } | 214 | } |
| 206 | 215 | ||
| 207 | 216 | ||
| 208 | -bool publish(MqttClient & client, | 217 | +bool publish(PubSubClient & client, |
| 209 | const char * topic, | 218 | const char * topic, |
| 210 | - const char * payload, | 219 | + const char * payload, |
| 220 | + size_t payloadLength, | ||
| 211 | bool retained) { | 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 | bool discoveryMsgToJsonDoc(JsonDocument & discoveryMsgDoc, | 240 | bool discoveryMsgToJsonDoc(JsonDocument & discoveryMsgDoc, |
| 228 | const char * discoveryMsgJson) { | 241 | const char * discoveryMsgJson) { |
| 229 | DeserializationError error = deserializeJson(discoveryMsgDoc, discoveryMsgJson); | 242 | DeserializationError error = deserializeJson(discoveryMsgDoc, discoveryMsgJson); |
| @@ -243,35 +256,30 @@ bool discoveryMsgToJsonDoc(JsonDocument & discoveryMsgDoc, | @@ -243,35 +256,30 @@ bool discoveryMsgToJsonDoc(JsonDocument & discoveryMsgDoc, | ||
| 243 | * 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 | 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 | * device. | 257 | * device. |
| 245 | */ | 258 | */ |
| 246 | -bool addEntity(MqttClient & client, | 259 | +bool addEntity(PubSubClient & client, |
| 247 | const char * component, | 260 | const char * component, |
| 248 | const char * object, | 261 | const char * object, |
| 249 | JsonDocument & discoveryMsgDoc) { | 262 | JsonDocument & discoveryMsgDoc) { |
| 250 | - if(!client.isConnected()) return false; | 263 | + if(!client.connected()) return false; |
| 251 | 264 | ||
| 252 | size_t jsonSize = measureJson(discoveryMsgDoc); | 265 | size_t jsonSize = measureJson(discoveryMsgDoc); |
| 253 | char discoveryMsgJson[jsonSize + 1]; | 266 | char discoveryMsgJson[jsonSize + 1]; |
| 254 | serializeJson(discoveryMsgDoc, discoveryMsgJson, sizeof discoveryMsgJson); | 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 | // addEntity() | 280 | // addEntity() |
| 273 | // Same as above but providing the discovery message as a const char * JSON | 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 | const char * component, | 283 | const char * component, |
| 276 | const char * object, | 284 | const char * object, |
| 277 | const char * discoveryMsgJson) { | 285 | const char * discoveryMsgJson) { |
| @@ -287,23 +295,14 @@ bool addEntity(MqttClient & client, | @@ -287,23 +295,14 @@ bool addEntity(MqttClient & client, | ||
| 287 | * Subscribe to the topic at at the given key in the discovery message. Before subscription the topic in the discovery | 295 | * Subscribe to the topic at at the given key in the discovery message. Before subscription the topic in the discovery |
| 288 | * message is expanded to the full topic by prefixing the "~" path. | 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 | const char * discoveryMessage, | 299 | const char * discoveryMessage, |
| 293 | const char * key) { | 300 | const char * key) { |
| 294 | const char * topic = topicByReference(key, discoveryMessage); | 301 | const char * topic = topicByReference(key, discoveryMessage); |
| 295 | if(topic == nullptr) return false; | 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 | \ No newline at end of file | 307 | \ No newline at end of file |
| 308 | + return client.subscribe(topic); | ||
| 309 | +} |
examples/Advanced_Thermostat/MQTTHelpers.h
| @@ -2,7 +2,7 @@ | @@ -2,7 +2,7 @@ | ||
| 2 | 2 | ||
| 3 | 3 | ||
| 4 | #include <Arduino.h> | 4 | #include <Arduino.h> |
| 5 | -#include <MqttClient.h> | 5 | +#include <PubSubClient.h> |
| 6 | #include <ArduinoJson.h> | 6 | #include <ArduinoJson.h> |
| 7 | 7 | ||
| 8 | 8 | ||
| @@ -12,20 +12,6 @@ const char * chipID(); | @@ -12,20 +12,6 @@ const char * chipID(); | ||
| 12 | 12 | ||
| 13 | const char * shortID(); | 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 | void discoveryMessageSetIDs(char * discoveryMsgJson); | 15 | void discoveryMessageSetIDs(char * discoveryMsgJson); |
| 30 | 16 | ||
| 31 | const char * topicByReference(const char * key, | 17 | const char * topicByReference(const char * key, |
| @@ -33,12 +19,18 @@ const char * topicByReference(const char * key, | @@ -33,12 +19,18 @@ const char * topicByReference(const char * key, | ||
| 33 | 19 | ||
| 34 | bool validJson(const char * discoveryMsgJson); | 20 | bool validJson(const char * discoveryMsgJson); |
| 35 | 21 | ||
| 36 | -bool connectMQTT(MqttClient & client, | 22 | +bool connectMQTT(PubSubClient & client, |
| 37 | const char * clientID, | 23 | const char * clientID, |
| 38 | const char * user, | 24 | const char * user, |
| 39 | const char * password); | 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 | const char * topic, | 34 | const char * topic, |
| 43 | const char * payload, | 35 | const char * payload, |
| 44 | bool retained = false); | 36 | bool retained = false); |
| @@ -46,17 +38,16 @@ bool publish(MqttClient & client, | @@ -46,17 +38,16 @@ bool publish(MqttClient & client, | ||
| 46 | bool discoveryMsgToJsonDoc(JsonDocument & discoveryMsgDoc, | 38 | bool discoveryMsgToJsonDoc(JsonDocument & discoveryMsgDoc, |
| 47 | const char * discoveryMsgJson); | 39 | const char * discoveryMsgJson); |
| 48 | 40 | ||
| 49 | -bool addEntity(MqttClient & client, | 41 | +bool addEntity(PubSubClient & client, |
| 50 | const char * component, | 42 | const char * component, |
| 51 | const char * object, | 43 | const char * object, |
| 52 | JsonDocument & discoveryMsgDoc); | 44 | JsonDocument & discoveryMsgDoc); |
| 53 | 45 | ||
| 54 | -bool addEntity(MqttClient & client, | 46 | +bool addEntity(PubSubClient & client, |
| 55 | const char * component, | 47 | const char * component, |
| 56 | const char * object, | 48 | const char * object, |
| 57 | const char * discoveryMsgJson); | 49 | const char * discoveryMsgJson); |
| 58 | 50 | ||
| 59 | -bool subscribe(MqttClient & client, | ||
| 60 | - MqttClient::MessageHandlerCbk cbk, | 51 | +bool subscribe(PubSubClient & client, |
| 61 | const char * discoveryMessage, | 52 | const char * discoveryMessage, |
| 62 | const char * key); | 53 | const char * key); |
| 63 | \ No newline at end of file | 54 | \ No newline at end of file |
examples/Advanced_Thermostat/OpenThermHelpers.cpp
| @@ -134,7 +134,7 @@ bool readSecondaryConfiguration(OpenTherm & thermostat, | @@ -134,7 +134,7 @@ bool readSecondaryConfiguration(OpenTherm & thermostat, | ||
| 134 | return true; | 134 | return true; |
| 135 | } | 135 | } |
| 136 | 136 | ||
| 137 | - configurationFlags = OpenTherm::CONFIGURATION_FLAGS(flags); | 137 | + configurationFlags = (OpenTherm::CONFIGURATION_FLAGS) flags; |
| 138 | 138 | ||
| 139 | return true; | 139 | return true; |
| 140 | } else { | 140 | } else { |
examples/Advanced_Thermostat/ThermoStateMachine.cpp
| @@ -25,19 +25,20 @@ bool ThermoStateMachine::connected() { | @@ -25,19 +25,20 @@ bool ThermoStateMachine::connected() { | ||
| 25 | 25 | ||
| 26 | 26 | ||
| 27 | void ThermoStateMachine::initPrimaryFlags(OpenTherm::CONFIGURATION_FLAGS configurationFlags) { | 27 | void ThermoStateMachine::initPrimaryFlags(OpenTherm::CONFIGURATION_FLAGS configurationFlags) { |
| 28 | - _configurationFlags = uint8_t(configurationFlags); | 28 | + _configurationFlags = (uint8_t) configurationFlags; |
| 29 | _primaryFlags = 0; | 29 | _primaryFlags = 0; |
| 30 | // Enable DHW if boiler is capable of DHW | 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 | // If boiler is capable of cooling, signal this by setting 'canCool' | 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 | // Do not enable OTC | 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 | _state = ThermostatState::OFF; | 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,8 +196,11 @@ bool ThermoStateMachine::update(float ro | ||
| 195 | _previousRoomTemperatureSetpoint = roomTemperatureSetpoint; | 196 | _previousRoomTemperatureSetpoint = roomTemperatureSetpoint; |
| 196 | 197 | ||
| 197 | return false; | 198 | return false; |
| 199 | + } else if(_state == ThermostatState::OFF) { | ||
| 200 | + | ||
| 201 | + return false; | ||
| 198 | } else { | 202 | } else { |
| 199 | - Serial.println("Unknown state"); | 203 | + Serial.printf("Unknown state %d\n", _state); |
| 200 | 204 | ||
| 201 | return false; | 205 | return false; |
| 202 | } | 206 | } |
| @@ -263,5 +267,3 @@ bool ThermoStateMachine::getRoomTemperatureStale() { | @@ -263,5 +267,3 @@ bool ThermoStateMachine::getRoomTemperatureStale() { | ||
| 263 | const char * ThermoStateMachine::c_str() { | 267 | const char * ThermoStateMachine::c_str() { |
| 264 | return _state_c_str; | 268 | return _state_c_str; |
| 265 | } | 269 | } |
| 266 | - | ||
| 267 | - |