From 498c990cbf93f764882aaf2470ed3f761fc8cc73 Mon Sep 17 00:00:00 2001 From: visualapproach Date: Sat, 12 Mar 2022 13:58:15 +0100 Subject: [PATCH 01/10] 6w: HA autodiscover --- Code/6-wire-version/.vscode/extensions.json | 17 +- Code/6-wire-version/src/config.h | 12 +- Code/6-wire-version/src/main.cpp | 696 +++++++++++++++++++- Code/6-wire-version/src/main.h | 1 + 4 files changed, 713 insertions(+), 13 deletions(-) diff --git a/Code/6-wire-version/.vscode/extensions.json b/Code/6-wire-version/.vscode/extensions.json index 0f0d7401..080e70d0 100644 --- a/Code/6-wire-version/.vscode/extensions.json +++ b/Code/6-wire-version/.vscode/extensions.json @@ -1,7 +1,10 @@ -{ - // See http://go.microsoft.com/fwlink/?LinkId=827846 - // for the documentation about the extensions.json format - "recommendations": [ - "platformio.platformio-ide" - ] -} +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": [ + "platformio.platformio-ide" + ], + "unwantedRecommendations": [ + "ms-vscode.cpptools-extension-pack" + ] +} diff --git a/Code/6-wire-version/src/config.h b/Code/6-wire-version/src/config.h index a9d92483..62294fa2 100644 --- a/Code/6-wire-version/src/config.h +++ b/Code/6-wire-version/src/config.h @@ -1,7 +1,9 @@ #include #include -#define LEGACY_NAME "layzspa" +#define DEVICE_NAME "layzspa" +#define FW_VERSION "2022-03-12" +#define HA_PREFIX "homeassistant" /* * Miscellaneous @@ -9,7 +11,7 @@ /** get the state of password visibility */ const bool hidePasswords = true; /** get the network hostname of the device (max. length 26) */ -const char *netHostname = LEGACY_NAME; +const char *netHostname = DEVICE_NAME; /* * Web Server Authentication @@ -25,7 +27,7 @@ String authPassword = "password"; * OTA Service Credentials */ /** get the name for the OTA service */ -const char *OTAName = LEGACY_NAME; +const char *OTAName = DEVICE_NAME; /** get the password for the OTA service */ const char *OTAPassword = "esp8266"; @@ -106,8 +108,8 @@ String mqttUsername = "username"; /** get or set the MQTT server password */ String mqttPassword = "password"; /** get or set the unique MQTT client ID */ -String mqttClientId = LEGACY_NAME; +String mqttClientId = DEVICE_NAME; /** get or set the MQTT topic name */ -String mqttBaseTopic = LEGACY_NAME; +String mqttBaseTopic = DEVICE_NAME; /** get or set the MQTT telemetry interval */ int mqttTelemetryInterval = 600; diff --git a/Code/6-wire-version/src/main.cpp b/Code/6-wire-version/src/main.cpp index d234dab1..10a68ceb 100644 --- a/Code/6-wire-version/src/main.cpp +++ b/Code/6-wire-version/src/main.cpp @@ -239,6 +239,27 @@ void sendMQTT() { //Serial.println(F("MQTT > times not published")); } + + //send other info + DynamicJsonDocument doc(512); + json = ""; + // Set the values in the document + doc["RSSI"] = WiFi.RSSI(); + doc["IP"] = WiFi.localIP().toString(); + doc["SSID"] = WiFi.SSID(); + + // Serialize JSON to string + if (serializeJson(doc, json) == 0) { + json = "{\"error\": \"Failed to serialize message\"}"; + } + if (mqttClient.publish((String(mqttBaseTopic) + "/other").c_str(), String(json).c_str(), true)) + { + //Serial.println(F("MQTT > other published")); + } + else + { + //Serial.println(F("MQTT > other not published")); + } } @@ -1139,7 +1160,7 @@ void startMqtt() // setup MQTT broker information as defined earlier mqttClient.setServer(mqttIpAddress, mqttPort); // set buffer for larger messages, new to library 2.8.0 - if (mqttClient.setBufferSize(1024)) + if (mqttClient.setBufferSize(1536)) { Serial.println(F("MQTT > buffer size successfully increased")); } @@ -1222,6 +1243,12 @@ void mqttConnect() // Watch the 'command' topic for incoming MQTT messages mqttClient.subscribe((String(mqttBaseTopic) + "/command").c_str()); mqttClient.loop(); + + mqttClient.publish((String(mqttBaseTopic) + "/reboot_time").c_str(), DateTime.format(DateFormatter::ISO8601).c_str(), true); + mqttClient.publish((String(mqttBaseTopic) + "/reboot_reason").c_str(), ESP.getResetReason().c_str(), true); + mqttClient.loop(); + sendMQTT(); + setupHA(); } else { @@ -1229,3 +1256,670 @@ void mqttConnect() Serial.println(mqttClient.state()); // states explained in WebSocket.js } } + +void setupHA() +{ + String topic; + String payload; + DynamicJsonDocument devicedoc(512); + DynamicJsonDocument doc(1536); + devicedoc["device"]["configuration_url"] = "http://" + WiFi.localIP().toString(); + devicedoc["device"]["connections"].add(serialized("[\"mac\",\"" + WiFi.macAddress()+"\"]" )); + devicedoc["device"]["identifiers"] = ESP.getChipId(); + devicedoc["device"]["manufacturer"] = "Visualapproach"; + devicedoc["device"]["model"] = "NodeMCU 12E"; + devicedoc["device"]["name"] = "Layzspa WiFi controller"; + devicedoc["device"]["sw_version"] = FW_VERSION; + + // pressed button sensor + doc["device"] = devicedoc["device"]; + payload = ""; + topic = String(HA_PREFIX) + "/sensor/layzspa_pressed_button/config"; + Serial.println(topic); + doc["name"] = "Layzspa pressed button"; + doc["unique_id"] = "sensor.layzspa_pressed_button"; + doc["state_topic"] = mqttBaseTopic+"/button"; + doc["availability_topic"] = mqttBaseTopic+"/Status"; + doc["payload_available"] = "Alive"; + doc["payload_not_available"] = "Dead"; + if (serializeJson(doc, payload) == 0) + { + Serial.println(F("Failed to serialize HA message!")); + return; + } + mqttClient.publish(topic.c_str(), payload.c_str(), true); + mqttClient.loop(); + Serial.println(payload); + doc.clear(); + doc.garbageCollect(); + + // reboot time sensor + doc["device"] = devicedoc["device"]; + payload = ""; + topic = String(HA_PREFIX) + "/sensor/layzspa_reboot_time/config"; + Serial.println(topic); + doc["name"] = "Layzspa reboot time"; + doc["unique_id"] = "sensor.layzspa_reboot_time"; + doc["state_topic"] = mqttBaseTopic+"/reboot_time"; + doc["availability_topic"] = mqttBaseTopic+"/Status"; + doc["payload_available"] = "Alive"; + doc["payload_not_available"] = "Dead"; + if (serializeJson(doc, payload) == 0) + { + Serial.println(F("Failed to serialize HA message!")); + return; + } + mqttClient.publish(topic.c_str(), payload.c_str(), true); + mqttClient.loop(); + Serial.println(payload); + doc.clear(); + doc.garbageCollect(); + + // reboot reason sensor + doc["device"] = devicedoc["device"]; + payload = ""; + topic = String(HA_PREFIX) + "/sensor/layzspa_reboot_reason/config"; + Serial.println(topic); + doc["name"] = "Layzspa reboot reason"; + doc["unique_id"] = "sensor.layzspa_reboot_reason"; + doc["state_topic"] = mqttBaseTopic+"/reboot_reason"; + doc["availability_topic"] = mqttBaseTopic+"/Status"; + doc["payload_available"] = "Alive"; + doc["payload_not_available"] = "Dead"; + if (serializeJson(doc, payload) == 0) + { + Serial.println(F("Failed to serialize HA message!")); + return; + } + mqttClient.publish(topic.c_str(), payload.c_str(), true); + mqttClient.loop(); + Serial.println(payload); + doc.clear(); + doc.garbageCollect(); + + // WiFi SSID sensor + doc["device"] = devicedoc["device"]; + payload = ""; + topic = String(HA_PREFIX) + "/sensor/layzspa_ssid/config"; + Serial.println(topic); + doc["name"] = "Layzspa ssid"; + doc["unique_id"] = "sensor.layzspa_ssid"; + doc["state_topic"] = mqttBaseTopic+"/other"; + doc["value_template"] = "{{ value_json.SSID }}"; + doc["expire_after"] = 700; + doc["availability_topic"] = mqttBaseTopic+"/Status"; + doc["payload_available"] = "Alive"; + doc["payload_not_available"] = "Dead"; + if (serializeJson(doc, payload) == 0) + { + Serial.println(F("Failed to serialize HA message!")); + return; + } + mqttClient.publish(topic.c_str(), payload.c_str(), true); + mqttClient.loop(); + Serial.println(payload); + doc.clear(); + doc.garbageCollect(); + + // WiFi RSSI sensor + doc["device"] = devicedoc["device"]; + payload = ""; + topic = String(HA_PREFIX) + "/sensor/layzspa_rssi/config"; + Serial.println(topic); + doc["name"] = "Layzspa rssi"; + doc["unique_id"] = "sensor.layzspa_rssi"; + doc["state_topic"] = mqttBaseTopic+"/other"; + doc["value_template"] = "{{ value_json.RSSI }}"; + doc["expire_after"] = 700; + doc["availability_topic"] = mqttBaseTopic+"/Status"; + doc["payload_available"] = "Alive"; + doc["payload_not_available"] = "Dead"; + if (serializeJson(doc, payload) == 0) + { + Serial.println(F("Failed to serialize HA message!")); + return; + } + mqttClient.publish(topic.c_str(), payload.c_str(), true); + mqttClient.loop(); + Serial.println(payload); + doc.clear(); + doc.garbageCollect(); + + // WiFi local ip sensor + doc["device"] = devicedoc["device"]; + payload = ""; + topic = String(HA_PREFIX) + "/sensor/layzspa_ip/config"; + Serial.println(topic); + doc["name"] = "Layzspa ip"; + doc["unique_id"] = "sensor.layzspa_ip"; + doc["state_topic"] = mqttBaseTopic+"/other"; + doc["value_template"] = "{{ value_json.IP }}"; + doc["expire_after"] = 700; + doc["availability_topic"] = mqttBaseTopic+"/Status"; + doc["payload_available"] = "Alive"; + doc["payload_not_available"] = "Dead"; + if (serializeJson(doc, payload) == 0) + { + Serial.println(F("Failed to serialize HA message!")); + return; + } + mqttClient.publish(topic.c_str(), payload.c_str(), true); + mqttClient.loop(); + Serial.println(payload); + doc.clear(); + doc.garbageCollect(); + + + // connect count sensor + doc["device"] = devicedoc["device"]; + payload = ""; + topic = String(HA_PREFIX) + "/sensor/layzspa_connect_count/config"; + Serial.println(topic); + doc["name"] = "Layzspa connect count"; + doc["unique_id"] = "sensor.layzspa_connect_count"; + doc["state_topic"] = mqttBaseTopic+"/MQTT_Connect_Count"; + doc["availability_topic"] = mqttBaseTopic+"/Status"; + doc["payload_available"] = "Alive"; + doc["payload_not_available"] = "Dead"; + if (serializeJson(doc, payload) == 0) + { + Serial.println(F("Failed to serialize HA message!")); + return; + } + mqttClient.publish(topic.c_str(), payload.c_str(), true); + mqttClient.loop(); + Serial.println(payload); + doc.clear(); + doc.garbageCollect(); + + + // spa temperature sensor + doc["device"] = devicedoc["device"]; + payload = ""; + topic = String(HA_PREFIX) + "/sensor/layzspa_temperature/config"; + Serial.println(topic); + doc["name"] = "Layzspa temperature"; + doc["unique_id"] = "sensor.layzspa_temperature"; + doc["state_topic"] = mqttBaseTopic+"/message"; + doc["unit_of_measurement"] = "°C"; + doc["value_template"] = "{{ value_json.TMP }}"; + doc["expire_after"] = 700; + doc["availability_topic"] = mqttBaseTopic+"/Status"; + doc["payload_available"] = "Alive"; + doc["payload_not_available"] = "Dead"; + if (serializeJson(doc, payload) == 0) + { + Serial.println(F("Failed to serialize HA message!")); + return; + } + mqttClient.publish(topic.c_str(), payload.c_str(), true); + mqttClient.loop(); + Serial.println(payload); + doc.clear(); + doc.garbageCollect(); + + // spa target temperature sensor + doc["device"] = devicedoc["device"]; + payload = ""; + topic = String(HA_PREFIX) + "/sensor/layzspa_target_temperature/config"; + Serial.println(topic); + doc["name"] = "Layzspa target temperature"; + doc["unique_id"] = "sensor.layzspa_target_temperature"; + doc["state_topic"] = mqttBaseTopic+"/message"; + doc["unit_of_measurement"] = "°C"; + doc["value_template"] = "{{ value_json.TGT }}"; + doc["expire_after"] = 700; + doc["availability_topic"] = mqttBaseTopic+"/Status"; + doc["payload_available"] = "Alive"; + doc["payload_not_available"] = "Dead"; + if (serializeJson(doc, payload) == 0) + { + Serial.println(F("Failed to serialize HA message!")); + return; + } + mqttClient.publish(topic.c_str(), payload.c_str(), true); + mqttClient.loop(); + Serial.println(payload); + doc.clear(); + doc.garbageCollect(); + + // spa time to target temperature sensor + doc["device"] = devicedoc["device"]; + payload = ""; + topic = String(HA_PREFIX) + "/sensor/layzspa_time_to_target/config"; + Serial.println(topic); + doc["name"] = "Layzspa time to target"; + doc["unique_id"] = "sensor.layzspa_time_to_target"; + doc["state_topic"] = mqttBaseTopic+"/times"; + doc["unit_of_measurement"] = "hours"; + doc["value_template"] = "{{ (value_json.TTTT / 3600 | float) | round(2) }}"; + doc["expire_after"] = 700; + doc["icon"] = "mdi:clock"; + doc["availability_topic"] = mqttBaseTopic+"/Status"; + doc["payload_available"] = "Alive"; + doc["payload_not_available"] = "Dead"; + if (serializeJson(doc, payload) == 0) + { + Serial.println(F("Failed to serialize HA message!")); + return; + } + mqttClient.publish(topic.c_str(), payload.c_str(), true); + mqttClient.loop(); + Serial.println(payload); + doc.clear(); + doc.garbageCollect(); + + // spa energy sensor + doc["device"] = devicedoc["device"]; + payload = ""; + topic = String(HA_PREFIX) + "/sensor/layzspa_energy/config"; + Serial.println(topic); + doc["name"] = "Layzspa energy"; + doc["unique_id"] = "sensor.layzspa_energy"; + doc["state_topic"] = mqttBaseTopic+"/times"; + doc["unit_of_measurement"] = "kWh"; + doc["value_template"] = "{{ value_json.KWH }}"; + doc["device_class"] = "energy"; + doc["state_class"] = "total_increasing"; + doc["expire_after"] = 700; + doc["icon"] = "mdi:flash"; + doc["availability_topic"] = mqttBaseTopic+"/Status"; + doc["payload_available"] = "Alive"; + doc["payload_not_available"] = "Dead"; + if (serializeJson(doc, payload) == 0) + { + Serial.println(F("Failed to serialize HA message!")); + return; + } + mqttClient.publish(topic.c_str(), payload.c_str(), true); + mqttClient.loop(); + Serial.println(payload); + doc.clear(); + doc.garbageCollect(); + + // spa chlorine age sensor + doc["device"] = devicedoc["device"]; + payload = ""; + topic = String(HA_PREFIX) + "/sensor/layzspa_chlorine_age/config"; + Serial.println(topic); + doc["name"] = "Layzspa chlorine age"; + doc["unique_id"] = "sensor.layzspa_chlorine_age"; + doc["state_topic"] = mqttBaseTopic+"/times"; + doc["unit_of_measurement"] = "days"; + doc["value_template"] = "{{ ( ( (now().timestamp()|int) - value_json.CLTIME|int)/3600/24) | round(2) }}"; + doc["expire_after"] = 700; + doc["icon"] = "hass:hand-coin-outline"; + doc["availability_topic"] = mqttBaseTopic+"/Status"; + doc["payload_available"] = "Alive"; + doc["payload_not_available"] = "Dead"; + if (serializeJson(doc, payload) == 0) + { + Serial.println(F("Failed to serialize HA message!")); + return; + } + mqttClient.publish(topic.c_str(), payload.c_str(), true); + mqttClient.loop(); + Serial.println(payload); + doc.clear(); + doc.garbageCollect(); + + // spa filter age sensor + doc["device"] = devicedoc["device"]; + payload = ""; + topic = String(HA_PREFIX) + "/sensor/layzspa_filter_age/config"; + Serial.println(topic); + doc["name"] = "Layzspa filter age"; + doc["unique_id"] = "sensor.layzspa_filter_age"; + doc["state_topic"] = mqttBaseTopic+"/times"; + doc["unit_of_measurement"] = "days"; + doc["value_template"] = "{{ ( ( (now().timestamp()|int) - value_json.FTIME|int)/3600/24) | round(2) }}"; + doc["expire_after"] = 700; + doc["icon"] = "hass:air-filter"; + doc["availability_topic"] = mqttBaseTopic+"/Status"; + doc["payload_available"] = "Alive"; + doc["payload_not_available"] = "Dead"; + if (serializeJson(doc, payload) == 0) + { + Serial.println(F("Failed to serialize HA message!")); + return; + } + mqttClient.publish(topic.c_str(), payload.c_str(), true); + mqttClient.loop(); + Serial.println(payload); + doc.clear(); + doc.garbageCollect(); + + // spa lock binary_sensor + doc["device"] = devicedoc["device"]; + payload = ""; + topic = String(HA_PREFIX) + "/binary_sensor/layzspa_lock/config"; + Serial.println(topic); + doc["name"] = "Layzspa lock"; + doc["unique_id"] = "binary_sensor.layzspa_lock"; + doc["state_topic"] = mqttBaseTopic+"/message"; + doc["value_template"] = "{% if value_json.LCK == 1 %}ON{% else %}OFF{% endif %}"; + doc["device_class"] = "lock"; + doc["expire_after"] = 700; + doc["availability_topic"] = mqttBaseTopic+"/Status"; + doc["payload_available"] = "Alive"; + doc["payload_not_available"] = "Dead"; + if (serializeJson(doc, payload) == 0) + { + Serial.println(F("Failed to serialize HA message!")); + return; + } + mqttClient.publish(topic.c_str(), payload.c_str(), true); + mqttClient.loop(); + Serial.println(payload); + doc.clear(); + doc.garbageCollect(); + + // spa heater binary_sensor + doc["device"] = devicedoc["device"]; + payload = ""; + topic = String(HA_PREFIX) + "/binary_sensor/layzspa_heater/config"; + Serial.println(topic); + doc["name"] = "Layzspa heater"; + doc["unique_id"] = "binary_sensor.layzspa_heater"; + doc["state_topic"] = mqttBaseTopic+"/message"; + doc["value_template"] = "{% if value_json.RED == 1 %}ON{% else %}OFF{% endif %}"; + doc["device_class"] = "heat"; + doc["expire_after"] = 700; + doc["availability_topic"] = mqttBaseTopic+"/Status"; + doc["payload_available"] = "Alive"; + doc["payload_not_available"] = "Dead"; + if (serializeJson(doc, payload) == 0) + { + Serial.println(F("Failed to serialize HA message!")); + return; + } + mqttClient.publish(topic.c_str(), payload.c_str(), true); + mqttClient.loop(); + Serial.println(payload); + doc.clear(); + doc.garbageCollect(); + + // spa ready binary_sensor + doc["device"] = devicedoc["device"]; + payload = ""; + topic = String(HA_PREFIX) + "/binary_sensor/layzspa_ready/config"; + Serial.println(topic); + doc["name"] = "Layzspa ready"; + doc["unique_id"] = "binary_sensor.layzspa_ready"; + doc["state_topic"] = mqttBaseTopic+"/message"; + doc["value_template"] = "{% if value_json.TMP > 30 %}{% if value_json.TMP >= value_json.TGT-1 %}ON{% else %}OFF{% endif %}{% else %}OFF{% endif %}"; + doc["expire_after"] = 700; + doc["icon"] = "mdi:hot-tub"; + doc["availability_topic"] = mqttBaseTopic+"/Status"; + doc["payload_available"] = "Alive"; + doc["payload_not_available"] = "Dead"; + if (serializeJson(doc, payload) == 0) + { + Serial.println(F("Failed to serialize HA message!")); + return; + } + mqttClient.publish(topic.c_str(), payload.c_str(), true); + mqttClient.loop(); + Serial.println(payload); + doc.clear(); + doc.garbageCollect(); + + // spa connection status binary_sensor + doc["device"] = devicedoc["device"]; + payload = ""; + topic = String(HA_PREFIX) + "/binary_sensor/layzspa_connection/config"; + Serial.println(topic); + doc["name"] = "Layzspa connection"; + doc["unique_id"] = "binary_sensor.layzspa_connection"; + doc["state_topic"] = mqttBaseTopic+"/Status"; + doc["device-class"] = "connectivity"; + doc["availability_topic"] = mqttBaseTopic+"/Status"; + doc["payload_available"] = "Alive"; + doc["payload_not_available"] = "Dead"; + doc["payload_on"] = "Alive"; + doc["payload_off"] = "Dead"; + if (serializeJson(doc, payload) == 0) + { + Serial.println(F("Failed to serialize HA message!")); + return; + } + mqttClient.publish(topic.c_str(), payload.c_str(), true); + mqttClient.loop(); + Serial.println(payload); + doc.clear(); + doc.garbageCollect(); + + // spa heat regulation switch + doc["device"] = devicedoc["device"]; + payload = ""; + topic = String(HA_PREFIX) + "/switch/layzspa_heat_regulation/config"; + Serial.println(topic); + doc["name"] = "Layzspa heat regulation"; + doc["unique_id"] = "switch.layzspa_heat_regulation"; + doc["state_topic"] = mqttBaseTopic+"/message"; + doc["command_topic"] = mqttBaseTopic+"/command"; + doc["value_template"] = "{% if value_json.RED == 1 %}1{% elif value_json.GRN == 1 %}1{% else %}0{% endif %}"; + doc["expire_after"] = 700; + doc["icon"] = "mdi:radiator"; + doc["availability_topic"] = mqttBaseTopic+"/Status"; + doc["payload_available"] = "Alive"; + doc["payload_not_available"] = "Dead"; + doc["payload_on"] = "{CMD:3,VALUE:true,XTIME:0,INTERVAL:0}"; + doc["payload_off"] = "{CMD:3,VALUE:false,XTIME:0,INTERVAL:0}"; + doc["state_on"] = 1; + doc["state_off"] = 0; + if (serializeJson(doc, payload) == 0) + { + Serial.println(F("Failed to serialize HA message!")); + return; + } + mqttClient.publish(topic.c_str(), payload.c_str(), true); + mqttClient.loop(); + Serial.println(payload); + doc.clear(); + doc.garbageCollect(); + + // spa airbubbles switch + doc["device"] = devicedoc["device"]; + payload = ""; + topic = String(HA_PREFIX) + "/switch/layzspa_airbubbles/config"; + Serial.println(topic); + doc["name"] = "Layzspa airbubbles"; + doc["unique_id"] = "switch.layzspa_airbubbles"; + doc["state_topic"] = mqttBaseTopic+"/message"; + doc["command_topic"] = mqttBaseTopic+"/command"; + doc["value_template"] = "{{ value_json.AIR }}"; + doc["expire_after"] = 700; + doc["icon"] = "mdi:chart-bubble"; + doc["availability_topic"] = mqttBaseTopic+"/Status"; + doc["payload_available"] = "Alive"; + doc["payload_not_available"] = "Dead"; + doc["payload_on"] = "{CMD:2,VALUE:true,XTIME:0,INTERVAL:0}"; + doc["payload_off"] = "{CMD:2,VALUE:false,XTIME:0,INTERVAL:0}"; + doc["state_on"] = 1; + doc["state_off"] = 0; + if (serializeJson(doc, payload) == 0) + { + Serial.println(F("Failed to serialize HA message!")); + return; + } + mqttClient.publish(topic.c_str(), payload.c_str(), true); + mqttClient.loop(); + Serial.println(payload); + doc.clear(); + doc.garbageCollect(); + + // spa pump switch + doc["device"] = devicedoc["device"]; + payload = ""; + topic = String(HA_PREFIX) + "/switch/layzspa_pump/config"; + Serial.println(topic); + doc["name"] = "Layzspa pump"; + doc["unique_id"] = "switch.layzspa_pump"; + doc["state_topic"] = mqttBaseTopic+"/message"; + doc["command_topic"] = mqttBaseTopic+"/command"; + doc["value_template"] = "{{ value_json.FLT }}"; + doc["expire_after"] = 700; + doc["icon"] = "mdi:pump"; + doc["availability_topic"] = mqttBaseTopic+"/Status"; + doc["payload_available"] = "Alive"; + doc["payload_not_available"] = "Dead"; + doc["payload_on"] = "{CMD:4,VALUE:true,XTIME:0,INTERVAL:0}"; + doc["payload_off"] = "{CMD:4,VALUE:false,XTIME:0,INTERVAL:0}"; + doc["state_on"] = 1; + doc["state_off"] = 0; + if (serializeJson(doc, payload) == 0) + { + Serial.println(F("Failed to serialize HA message!")); + return; + } + mqttClient.publish(topic.c_str(), payload.c_str(), true); + mqttClient.loop(); + Serial.println(payload); + doc.clear(); + doc.garbageCollect(); + + // spa temperature unit switch + doc["device"] = devicedoc["device"]; + payload = ""; + topic = String(HA_PREFIX) + "/switch/layzspa_temperature_unit/config"; + Serial.println(topic); + doc["name"] = "Layzspa temperature unit"; + doc["unique_id"] = "switch.layzspa_unit"; + doc["state_topic"] = mqttBaseTopic+"/message"; + doc["command_topic"] = mqttBaseTopic+"/command"; + doc["value_template"] = "{{ value_json.UNT }}"; + doc["expire_after"] = 700; + doc["icon"] = "mdi:temperature-celsius"; + doc["availability_topic"] = mqttBaseTopic+"/Status"; + doc["payload_available"] = "Alive"; + doc["payload_not_available"] = "Dead"; + doc["payload_on"] = "{CMD:1,VALUE:true,XTIME:0,INTERVAL:0}"; + doc["payload_off"] = "{CMD:1,VALUE:false,XTIME:0,INTERVAL:0}"; + doc["state_on"] = 1; + doc["state_off"] = 0; + if (serializeJson(doc, payload) == 0) + { + Serial.println(F("Failed to serialize HA message!")); + return; + } + mqttClient.publish(topic.c_str(), payload.c_str(), true); + mqttClient.loop(); + Serial.println(payload); + doc.clear(); + doc.garbageCollect(); + + // spa reset chlorine timer button + doc["device"] = devicedoc["device"]; + payload = ""; + topic = String(HA_PREFIX) + "/button/layzspa_reset_chlorine/config"; + Serial.println(topic); + doc["name"] = "Layzspa reset chlorine timer"; + doc["unique_id"] = "button.layzspa_reset_chlorine"; + doc["command_topic"] = mqttBaseTopic+"/command"; + doc["payload_press"] = "{CMD:9,VALUE:true,XTIME:0,INTERVAL:0}"; + doc["icon"] = "mdi:restart"; + doc["availability_topic"] = mqttBaseTopic+"/Status"; + doc["payload_available"] = "Alive"; + doc["payload_not_available"] = "Dead"; + if (serializeJson(doc, payload) == 0) + { + Serial.println(F("Failed to serialize HA message!")); + return; + } + mqttClient.publish(topic.c_str(), payload.c_str(), true); + mqttClient.loop(); + Serial.println(payload); + doc.clear(); + doc.garbageCollect(); + + // spa reset filter timer button + doc["device"] = devicedoc["device"]; + payload = ""; + topic = String(HA_PREFIX) + "/button/layzspa_reset_filter/config"; + Serial.println(topic); + doc["name"] = "Layzspa reset filter timer"; + doc["unique_id"] = "button.layzspa_reset_filter"; + doc["command_topic"] = mqttBaseTopic+"/command"; + doc["payload_press"] = "{CMD:10,VALUE:true,XTIME:0,INTERVAL:0}"; + doc["icon"] = "mdi:restart"; + doc["availability_topic"] = mqttBaseTopic+"/Status"; + doc["payload_available"] = "Alive"; + doc["payload_not_available"] = "Dead"; + if (serializeJson(doc, payload) == 0) + { + Serial.println(F("Failed to serialize HA message!")); + return; + } + mqttClient.publish(topic.c_str(), payload.c_str(), true); + mqttClient.loop(); + Serial.println(payload); + doc.clear(); + doc.garbageCollect(); + + // spa restart esp button + doc["device"] = devicedoc["device"]; + payload = ""; + topic = String(HA_PREFIX) + "/button/layzspa_restart_esp/config"; + Serial.println(topic); + doc["name"] = "Layzspa restart esp"; + doc["unique_id"] = "button.layzspa_restart_esp"; + doc["command_topic"] = mqttBaseTopic+"/command"; + doc["payload_press"] = "{CMD:6,VALUE:true,XTIME:0,INTERVAL:0}"; + doc["icon"] = "mdi:restart"; + doc["device_class"] = "restart"; + doc["availability_topic"] = mqttBaseTopic+"/Status"; + doc["payload_available"] = "Alive"; + doc["payload_not_available"] = "Dead"; + if (serializeJson(doc, payload) == 0) + { + Serial.println(F("Failed to serialize HA message!")); + return; + } + mqttClient.publish(topic.c_str(), payload.c_str(), true); + mqttClient.loop(); + Serial.println(payload); + doc.clear(); + doc.garbageCollect(); + + // spa climate control + doc["device"] = devicedoc["device"]; + payload = ""; + topic = String(HA_PREFIX) + "/climate/layzspa_climate/config"; + Serial.println(topic); + doc["name"] = "Layzspa temperature control"; + doc["unique_id"] = "button.layzspa_climate"; + doc["max_temp"] = 40; + doc["min_temp"] = 20; + doc["precision"] = 1.0; + doc["temperature_unit"] = "C"; + doc["modes"].add(serialized("\"off\", \"heat\"")); + doc["mode_state_topic"] = mqttBaseTopic+"/message"; + doc["mode_state_template"] = "{% if value_json.RED == 1 %}heat{% elif value_json.GRN == 1 %}heat{% else %}off{% endif %}"; + doc["action_topic"] = mqttBaseTopic+"/message"; + doc["action_template"] = "{% if value_json.RED == 1 %}heating{% elif value_json.GRN == 1 %}idle{% else %}off{% endif %}"; + doc["temperature_state_topic"] = mqttBaseTopic+"/message"; + doc["temperature_state_template"] = "{{ value_json.TGT }}"; + doc["current_temperature_topic"] = mqttBaseTopic+"/message"; + doc["current_temperature_template"] = "{{ value_json.TMP }}"; + doc["temperature_command_topic"] = mqttBaseTopic+"/command"; + doc["temperature_command_template"] = "{CMD:0,VALUE:{{ value|int }},XTIME:0,INTERVAL:0}"; + doc["power_command_topic"] = mqttBaseTopic+"/command"; + doc["payload_on"] = "{CMD:3,VALUE:1,XTIME:0,INTERVAL:0}"; + doc["payload_off"] = "{CMD:3,VALUE:0,XTIME:0,INTERVAL:0}"; + doc["availability_topic"] = mqttBaseTopic+"/Status"; + doc["payload_available"] = "Alive"; + doc["payload_not_available"] = "Dead"; + if (serializeJson(doc, payload) == 0) + { + Serial.println(F("Failed to serialize HA message!")); + return; + } + mqttClient.publish(topic.c_str(), payload.c_str(), true); + mqttClient.loop(); + Serial.println(payload); + doc.clear(); + doc.garbageCollect(); + + +} diff --git a/Code/6-wire-version/src/main.h b/Code/6-wire-version/src/main.h index aafc2b40..887ff3c9 100644 --- a/Code/6-wire-version/src/main.h +++ b/Code/6-wire-version/src/main.h @@ -111,3 +111,4 @@ void handleRestart(); void startMqtt(); void mqttCallback(char* topic, byte* payload, unsigned int length); void mqttConnect(); +void setupHA(); \ No newline at end of file From e48b7642aa66953c59cdb26877fabc6362c5d55f Mon Sep 17 00:00:00 2001 From: visualapproach Date: Sat, 12 Mar 2022 16:51:44 +0100 Subject: [PATCH 02/10] HA init fix --- Code/6-wire-version/src/main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Code/6-wire-version/src/main.cpp b/Code/6-wire-version/src/main.cpp index 10a68ceb..700716a6 100644 --- a/Code/6-wire-version/src/main.cpp +++ b/Code/6-wire-version/src/main.cpp @@ -1246,6 +1246,7 @@ void mqttConnect() mqttClient.publish((String(mqttBaseTopic) + "/reboot_time").c_str(), DateTime.format(DateFormatter::ISO8601).c_str(), true); mqttClient.publish((String(mqttBaseTopic) + "/reboot_reason").c_str(), ESP.getResetReason().c_str(), true); + mqttClient.publish((String(mqttBaseTopic) + "/button").c_str(), bwc.getButtonName().c_str(), true); mqttClient.loop(); sendMQTT(); setupHA(); From cc79ca196e9cbf851489145ba92e08b7713f3fc7 Mon Sep 17 00:00:00 2001 From: visualapproach Date: Sun, 13 Mar 2022 08:54:24 +0100 Subject: [PATCH 03/10] Fix: reversed LOCK in HA --- Code/6-wire-version/src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/6-wire-version/src/main.cpp b/Code/6-wire-version/src/main.cpp index 700716a6..9e625c7f 100644 --- a/Code/6-wire-version/src/main.cpp +++ b/Code/6-wire-version/src/main.cpp @@ -1598,7 +1598,7 @@ void setupHA() doc["name"] = "Layzspa lock"; doc["unique_id"] = "binary_sensor.layzspa_lock"; doc["state_topic"] = mqttBaseTopic+"/message"; - doc["value_template"] = "{% if value_json.LCK == 1 %}ON{% else %}OFF{% endif %}"; + doc["value_template"] = "{% if value_json.LCK == 1 %}OFF{% else %}ON{% endif %}"; doc["device_class"] = "lock"; doc["expire_after"] = 700; doc["availability_topic"] = mqttBaseTopic+"/Status"; From 467d33b82bb29cf0a9d8fcb9bcbd344fd2967f2c Mon Sep 17 00:00:00 2001 From: visualapproach Date: Sun, 13 Mar 2022 08:55:34 +0100 Subject: [PATCH 04/10] edit fw_version --- Code/6-wire-version/src/config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/6-wire-version/src/config.h b/Code/6-wire-version/src/config.h index 62294fa2..369cd07e 100644 --- a/Code/6-wire-version/src/config.h +++ b/Code/6-wire-version/src/config.h @@ -2,7 +2,7 @@ #include #define DEVICE_NAME "layzspa" -#define FW_VERSION "2022-03-12" +#define FW_VERSION "2022-03-13" #define HA_PREFIX "homeassistant" /* From b1b3b4caead0066e4516f1c3ab08c45958981e3f Mon Sep 17 00:00:00 2001 From: visualapproach Date: Fri, 18 Mar 2022 18:42:38 +0100 Subject: [PATCH 05/10] improved HA integration --- Code/6-wire-version/src/config.h | 2 +- Code/6-wire-version/src/main.cpp | 601 +++++++++++++++++-------------- Code/6-wire-version/src/main.h | 5 +- 3 files changed, 327 insertions(+), 281 deletions(-) diff --git a/Code/6-wire-version/src/config.h b/Code/6-wire-version/src/config.h index 369cd07e..e9b0abde 100644 --- a/Code/6-wire-version/src/config.h +++ b/Code/6-wire-version/src/config.h @@ -2,7 +2,7 @@ #include #define DEVICE_NAME "layzspa" -#define FW_VERSION "2022-03-13" +#define FW_VERSION "2022-03-18" #define HA_PREFIX "homeassistant" /* diff --git a/Code/6-wire-version/src/main.cpp b/Code/6-wire-version/src/main.cpp index 9e625c7f..e70122af 100644 --- a/Code/6-wire-version/src/main.cpp +++ b/Code/6-wire-version/src/main.cpp @@ -73,6 +73,12 @@ void loop() if (newData) { + //the climate control in HA must know what unit to expect + if(bwc.getState(UNITSTATE) != prevunit) + { + prevunit = bwc.getState(UNITSTATE); + setupClimate(); + } sendMQTT(); } else if (sendMQTTFlag) @@ -1262,27 +1268,28 @@ void setupHA() { String topic; String payload; + String mychipid = String((unsigned int)ESP.getChipId()); DynamicJsonDocument devicedoc(512); - DynamicJsonDocument doc(1536); + DynamicJsonDocument doc(2048); devicedoc["device"]["configuration_url"] = "http://" + WiFi.localIP().toString(); devicedoc["device"]["connections"].add(serialized("[\"mac\",\"" + WiFi.macAddress()+"\"]" )); - devicedoc["device"]["identifiers"] = ESP.getChipId(); - devicedoc["device"]["manufacturer"] = "Visualapproach"; - devicedoc["device"]["model"] = "NodeMCU 12E"; - devicedoc["device"]["name"] = "Layzspa WiFi controller"; + devicedoc["device"]["identifiers"] = mychipid; + devicedoc["device"]["manufacturer"] = F("Visualapproach"); + devicedoc["device"]["model"] = F("NodeMCU 12E"); + devicedoc["device"]["name"] = F("Layzspa WiFi controller"); devicedoc["device"]["sw_version"] = FW_VERSION; // pressed button sensor doc["device"] = devicedoc["device"]; payload = ""; - topic = String(HA_PREFIX) + "/sensor/layzspa_pressed_button/config"; + topic = String(HA_PREFIX) + F("/sensor/layzspa_pressed_button/config"); Serial.println(topic); - doc["name"] = "Layzspa pressed button"; - doc["unique_id"] = "sensor.layzspa_pressed_button"; - doc["state_topic"] = mqttBaseTopic+"/button"; - doc["availability_topic"] = mqttBaseTopic+"/Status"; - doc["payload_available"] = "Alive"; - doc["payload_not_available"] = "Dead"; + doc["name"] = F("Layzspa pressed button"); + doc["unique_id"] = "sensor.layzspa_pressed_button"+mychipid; + doc["state_topic"] = mqttBaseTopic+F("/button"); + doc["availability_topic"] = mqttBaseTopic+F("/Status"); + doc["payload_available"] = F("Alive"); + doc["payload_not_available"] = F("Dead"); if (serializeJson(doc, payload) == 0) { Serial.println(F("Failed to serialize HA message!")); @@ -1297,14 +1304,14 @@ void setupHA() // reboot time sensor doc["device"] = devicedoc["device"]; payload = ""; - topic = String(HA_PREFIX) + "/sensor/layzspa_reboot_time/config"; + topic = String(HA_PREFIX) + F("/sensor/layzspa_reboot_time/config"); Serial.println(topic); - doc["name"] = "Layzspa reboot time"; - doc["unique_id"] = "sensor.layzspa_reboot_time"; - doc["state_topic"] = mqttBaseTopic+"/reboot_time"; - doc["availability_topic"] = mqttBaseTopic+"/Status"; - doc["payload_available"] = "Alive"; - doc["payload_not_available"] = "Dead"; + doc["name"] = F("Layzspa reboot time"); + doc["unique_id"] = "sensor.layzspa_reboot_time"+mychipid; + doc["state_topic"] = mqttBaseTopic+F("/reboot_time"); + doc["availability_topic"] = mqttBaseTopic+F("/Status"); + doc["payload_available"] = F("Alive"); + doc["payload_not_available"] = F("Dead"); if (serializeJson(doc, payload) == 0) { Serial.println(F("Failed to serialize HA message!")); @@ -1319,12 +1326,12 @@ void setupHA() // reboot reason sensor doc["device"] = devicedoc["device"]; payload = ""; - topic = String(HA_PREFIX) + "/sensor/layzspa_reboot_reason/config"; + topic = String(HA_PREFIX) + F("/sensor/layzspa_reboot_reason/config"); Serial.println(topic); - doc["name"] = "Layzspa reboot reason"; - doc["unique_id"] = "sensor.layzspa_reboot_reason"; - doc["state_topic"] = mqttBaseTopic+"/reboot_reason"; - doc["availability_topic"] = mqttBaseTopic+"/Status"; + doc["name"] = F("Layzspa reboot reason"); + doc["unique_id"] = "sensor.layzspa_reboot_reason"+mychipid; + doc["state_topic"] = mqttBaseTopic+F("/reboot_reason"); + doc["availability_topic"] = mqttBaseTopic+F("/Status"); doc["payload_available"] = "Alive"; doc["payload_not_available"] = "Dead"; if (serializeJson(doc, payload) == 0) @@ -1341,16 +1348,16 @@ void setupHA() // WiFi SSID sensor doc["device"] = devicedoc["device"]; payload = ""; - topic = String(HA_PREFIX) + "/sensor/layzspa_ssid/config"; + topic = String(HA_PREFIX) + F("/sensor/layzspa_ssid/config"); Serial.println(topic); - doc["name"] = "Layzspa ssid"; - doc["unique_id"] = "sensor.layzspa_ssid"; - doc["state_topic"] = mqttBaseTopic+"/other"; - doc["value_template"] = "{{ value_json.SSID }}"; + doc["name"] = F("Layzspa ssid"); + doc["unique_id"] = "sensor.layzspa_ssid"+mychipid; + doc["state_topic"] = mqttBaseTopic+F("/other"); + doc["value_template"] = F("{{ value_json.SSID }}"); doc["expire_after"] = 700; - doc["availability_topic"] = mqttBaseTopic+"/Status"; - doc["payload_available"] = "Alive"; - doc["payload_not_available"] = "Dead"; + doc["availability_topic"] = mqttBaseTopic+F("/Status"); + doc["payload_available"] = F("Alive"); + doc["payload_not_available"] = F("Dead"); if (serializeJson(doc, payload) == 0) { Serial.println(F("Failed to serialize HA message!")); @@ -1365,16 +1372,16 @@ void setupHA() // WiFi RSSI sensor doc["device"] = devicedoc["device"]; payload = ""; - topic = String(HA_PREFIX) + "/sensor/layzspa_rssi/config"; + topic = String(HA_PREFIX) + F("/sensor/layzspa_rssi/config"); Serial.println(topic); - doc["name"] = "Layzspa rssi"; - doc["unique_id"] = "sensor.layzspa_rssi"; - doc["state_topic"] = mqttBaseTopic+"/other"; - doc["value_template"] = "{{ value_json.RSSI }}"; + doc["name"] = F("Layzspa rssi"); + doc["unique_id"] = "sensor.layzspa_rssi"+mychipid; + doc["state_topic"] = mqttBaseTopic+F("/other"); + doc["value_template"] = F("{{ value_json.RSSI }}"); doc["expire_after"] = 700; - doc["availability_topic"] = mqttBaseTopic+"/Status"; - doc["payload_available"] = "Alive"; - doc["payload_not_available"] = "Dead"; + doc["availability_topic"] = mqttBaseTopic+F("/Status"); + doc["payload_available"] = F("Alive"); + doc["payload_not_available"] = F("Dead"); if (serializeJson(doc, payload) == 0) { Serial.println(F("Failed to serialize HA message!")); @@ -1389,16 +1396,16 @@ void setupHA() // WiFi local ip sensor doc["device"] = devicedoc["device"]; payload = ""; - topic = String(HA_PREFIX) + "/sensor/layzspa_ip/config"; + topic = String(HA_PREFIX) + F("/sensor/layzspa_ip/config"); Serial.println(topic); - doc["name"] = "Layzspa ip"; - doc["unique_id"] = "sensor.layzspa_ip"; - doc["state_topic"] = mqttBaseTopic+"/other"; - doc["value_template"] = "{{ value_json.IP }}"; + doc["name"] = F("Layzspa ip"); + doc["unique_id"] = "sensor.layzspa_ip"+mychipid; + doc["state_topic"] = mqttBaseTopic+F("/other"); + doc["value_template"] = F("{{ value_json.IP }}"); doc["expire_after"] = 700; - doc["availability_topic"] = mqttBaseTopic+"/Status"; - doc["payload_available"] = "Alive"; - doc["payload_not_available"] = "Dead"; + doc["availability_topic"] = mqttBaseTopic+F("/Status"); + doc["payload_available"] = F("Alive"); + doc["payload_not_available"] = F("Dead"); if (serializeJson(doc, payload) == 0) { Serial.println(F("Failed to serialize HA message!")); @@ -1414,14 +1421,14 @@ void setupHA() // connect count sensor doc["device"] = devicedoc["device"]; payload = ""; - topic = String(HA_PREFIX) + "/sensor/layzspa_connect_count/config"; + topic = String(HA_PREFIX) + F("/sensor/layzspa_connect_count/config"); Serial.println(topic); - doc["name"] = "Layzspa connect count"; - doc["unique_id"] = "sensor.layzspa_connect_count"; - doc["state_topic"] = mqttBaseTopic+"/MQTT_Connect_Count"; - doc["availability_topic"] = mqttBaseTopic+"/Status"; - doc["payload_available"] = "Alive"; - doc["payload_not_available"] = "Dead"; + doc["name"] = F("Layzspa connect count"); + doc["unique_id"] = "sensor.layzspa_connect_count"+mychipid; + doc["state_topic"] = mqttBaseTopic+F("/MQTT_Connect_Count"); + doc["availability_topic"] = mqttBaseTopic+F("/Status"); + doc["payload_available"] = F("Alive"); + doc["payload_not_available"] = F("Dead"); if (serializeJson(doc, payload) == 0) { Serial.println(F("Failed to serialize HA message!")); @@ -1434,20 +1441,22 @@ void setupHA() doc.garbageCollect(); - // spa temperature sensor + + // spa time to target temperature sensor doc["device"] = devicedoc["device"]; payload = ""; - topic = String(HA_PREFIX) + "/sensor/layzspa_temperature/config"; + topic = String(HA_PREFIX) + F("/sensor/layzspa_time_to_target/config"); Serial.println(topic); - doc["name"] = "Layzspa temperature"; - doc["unique_id"] = "sensor.layzspa_temperature"; - doc["state_topic"] = mqttBaseTopic+"/message"; - doc["unit_of_measurement"] = "°C"; - doc["value_template"] = "{{ value_json.TMP }}"; + doc["name"] = F("Layzspa time to target"); + doc["unique_id"] = "sensor.layzspa_time_to_target"+mychipid; + doc["state_topic"] = mqttBaseTopic+F("/times"); + doc["unit_of_measurement"] = F("hours"); + doc["value_template"] = F("{{ (value_json.TTTT / 3600 | float) | round(2) }}"); doc["expire_after"] = 700; - doc["availability_topic"] = mqttBaseTopic+"/Status"; - doc["payload_available"] = "Alive"; - doc["payload_not_available"] = "Dead"; + doc["icon"] = F("mdi:clock"); + doc["availability_topic"] = mqttBaseTopic+F("/Status"); + doc["payload_available"] = F("Alive"); + doc["payload_not_available"] = F("Dead"); if (serializeJson(doc, payload) == 0) { Serial.println(F("Failed to serialize HA message!")); @@ -1459,20 +1468,23 @@ void setupHA() doc.clear(); doc.garbageCollect(); - // spa target temperature sensor + // spa energy sensor doc["device"] = devicedoc["device"]; payload = ""; - topic = String(HA_PREFIX) + "/sensor/layzspa_target_temperature/config"; + topic = String(HA_PREFIX) + F("/sensor/layzspa_energy/config"); Serial.println(topic); - doc["name"] = "Layzspa target temperature"; - doc["unique_id"] = "sensor.layzspa_target_temperature"; - doc["state_topic"] = mqttBaseTopic+"/message"; - doc["unit_of_measurement"] = "°C"; - doc["value_template"] = "{{ value_json.TGT }}"; + doc["name"] = F("Layzspa energy"); + doc["unique_id"] = "sensor.layzspa_energy"+mychipid; + doc["state_topic"] = mqttBaseTopic+F("/times"); + doc["unit_of_measurement"] = F("kWh"); + doc["value_template"] = F("{{ value_json.KWH }}"); + doc["device_class"] = F("energy"); + doc["state_class"] = F("total_increasing"); doc["expire_after"] = 700; - doc["availability_topic"] = mqttBaseTopic+"/Status"; - doc["payload_available"] = "Alive"; - doc["payload_not_available"] = "Dead"; + doc["icon"] = F("mdi:flash"); + doc["availability_topic"] = mqttBaseTopic+F("/Status"); + doc["payload_available"] = F("Alive"); + doc["payload_not_available"] = F("Dead"); if (serializeJson(doc, payload) == 0) { Serial.println(F("Failed to serialize HA message!")); @@ -1484,21 +1496,21 @@ void setupHA() doc.clear(); doc.garbageCollect(); - // spa time to target temperature sensor + // spa chlorine age sensor doc["device"] = devicedoc["device"]; payload = ""; - topic = String(HA_PREFIX) + "/sensor/layzspa_time_to_target/config"; + topic = String(HA_PREFIX) + F("/sensor/layzspa_chlorine_age/config"); Serial.println(topic); - doc["name"] = "Layzspa time to target"; - doc["unique_id"] = "sensor.layzspa_time_to_target"; - doc["state_topic"] = mqttBaseTopic+"/times"; - doc["unit_of_measurement"] = "hours"; - doc["value_template"] = "{{ (value_json.TTTT / 3600 | float) | round(2) }}"; + doc["name"] = F("Layzspa chlorine age"); + doc["unique_id"] = "sensor.layzspa_chlorine_age"+mychipid; + doc["state_topic"] = mqttBaseTopic+F("/times"); + doc["unit_of_measurement"] = F("days"); + doc["value_template"] = F("{{ ( ( (now().timestamp()|int) - value_json.CLTIME|int)/3600/24) | round(2) }}"); doc["expire_after"] = 700; - doc["icon"] = "mdi:clock"; - doc["availability_topic"] = mqttBaseTopic+"/Status"; - doc["payload_available"] = "Alive"; - doc["payload_not_available"] = "Dead"; + doc["icon"] = F("hass:hand-coin-outline"); + doc["availability_topic"] = mqttBaseTopic+F("/Status"); + doc["payload_available"] = F("Alive"); + doc["payload_not_available"] = F("Dead"); if (serializeJson(doc, payload) == 0) { Serial.println(F("Failed to serialize HA message!")); @@ -1510,23 +1522,21 @@ void setupHA() doc.clear(); doc.garbageCollect(); - // spa energy sensor + // spa filter age sensor doc["device"] = devicedoc["device"]; payload = ""; - topic = String(HA_PREFIX) + "/sensor/layzspa_energy/config"; + topic = String(HA_PREFIX) + F("/sensor/layzspa_filter_age/config"); Serial.println(topic); - doc["name"] = "Layzspa energy"; - doc["unique_id"] = "sensor.layzspa_energy"; - doc["state_topic"] = mqttBaseTopic+"/times"; - doc["unit_of_measurement"] = "kWh"; - doc["value_template"] = "{{ value_json.KWH }}"; - doc["device_class"] = "energy"; - doc["state_class"] = "total_increasing"; + doc["name"] = F("Layzspa filter age"); + doc["unique_id"] = "sensor.layzspa_filter_age"+mychipid; + doc["state_topic"] = mqttBaseTopic+F("/times"); + doc["unit_of_measurement"] = F("days"); + doc["value_template"] = F("{{ ( ( (now().timestamp()|int) - value_json.FTIME|int)/3600/24) | round(2) }}"); doc["expire_after"] = 700; - doc["icon"] = "mdi:flash"; - doc["availability_topic"] = mqttBaseTopic+"/Status"; - doc["payload_available"] = "Alive"; - doc["payload_not_available"] = "Dead"; + doc["icon"] = F("hass:air-filter"); + doc["availability_topic"] = mqttBaseTopic+F("/Status"); + doc["payload_available"] = F("Alive"); + doc["payload_not_available"] = F("Dead"); if (serializeJson(doc, payload) == 0) { Serial.println(F("Failed to serialize HA message!")); @@ -1538,21 +1548,20 @@ void setupHA() doc.clear(); doc.garbageCollect(); - // spa chlorine age sensor + // spa lock binary_sensor doc["device"] = devicedoc["device"]; payload = ""; - topic = String(HA_PREFIX) + "/sensor/layzspa_chlorine_age/config"; + topic = String(HA_PREFIX) + F("/binary_sensor/layzspa_lock/config"); Serial.println(topic); - doc["name"] = "Layzspa chlorine age"; - doc["unique_id"] = "sensor.layzspa_chlorine_age"; - doc["state_topic"] = mqttBaseTopic+"/times"; - doc["unit_of_measurement"] = "days"; - doc["value_template"] = "{{ ( ( (now().timestamp()|int) - value_json.CLTIME|int)/3600/24) | round(2) }}"; + doc["name"] = F("Layzspa lock"); + doc["unique_id"] = "binary_sensor.layzspa_lock"+mychipid; + doc["state_topic"] = mqttBaseTopic+F("/message"); + doc["value_template"] = F("{% if value_json.LCK == 1 %}OFF{% else %}ON{% endif %}"); + doc["device_class"] = F("lock"); doc["expire_after"] = 700; - doc["icon"] = "hass:hand-coin-outline"; - doc["availability_topic"] = mqttBaseTopic+"/Status"; - doc["payload_available"] = "Alive"; - doc["payload_not_available"] = "Dead"; + doc["availability_topic"] = mqttBaseTopic+F("/Status"); + doc["payload_available"] = F("Alive"); + doc["payload_not_available"] = F("Dead"); if (serializeJson(doc, payload) == 0) { Serial.println(F("Failed to serialize HA message!")); @@ -1564,21 +1573,20 @@ void setupHA() doc.clear(); doc.garbageCollect(); - // spa filter age sensor + // spa heater binary_sensor doc["device"] = devicedoc["device"]; payload = ""; - topic = String(HA_PREFIX) + "/sensor/layzspa_filter_age/config"; + topic = String(HA_PREFIX) + F("/binary_sensor/layzspa_heater/config"); Serial.println(topic); - doc["name"] = "Layzspa filter age"; - doc["unique_id"] = "sensor.layzspa_filter_age"; - doc["state_topic"] = mqttBaseTopic+"/times"; - doc["unit_of_measurement"] = "days"; - doc["value_template"] = "{{ ( ( (now().timestamp()|int) - value_json.FTIME|int)/3600/24) | round(2) }}"; + doc["name"] = F("Layzspa heater"); + doc["unique_id"] = "binary_sensor.layzspa_heater"+mychipid; + doc["state_topic"] = mqttBaseTopic+F("/message"); + doc["value_template"] = F("{% if value_json.RED == 1 %}ON{% else %}OFF{% endif %}"); + doc["device_class"] = F("heat"); doc["expire_after"] = 700; - doc["icon"] = "hass:air-filter"; - doc["availability_topic"] = mqttBaseTopic+"/Status"; - doc["payload_available"] = "Alive"; - doc["payload_not_available"] = "Dead"; + doc["availability_topic"] = mqttBaseTopic+F("/Status"); + doc["payload_available"] = F("Alive"); + doc["payload_not_available"] = F("Dead"); if (serializeJson(doc, payload) == 0) { Serial.println(F("Failed to serialize HA message!")); @@ -1590,20 +1598,20 @@ void setupHA() doc.clear(); doc.garbageCollect(); - // spa lock binary_sensor + // spa ready binary_sensor doc["device"] = devicedoc["device"]; payload = ""; - topic = String(HA_PREFIX) + "/binary_sensor/layzspa_lock/config"; + topic = String(HA_PREFIX) + F("/binary_sensor/layzspa_ready/config"); Serial.println(topic); - doc["name"] = "Layzspa lock"; - doc["unique_id"] = "binary_sensor.layzspa_lock"; - doc["state_topic"] = mqttBaseTopic+"/message"; - doc["value_template"] = "{% if value_json.LCK == 1 %}OFF{% else %}ON{% endif %}"; - doc["device_class"] = "lock"; + doc["name"] = F("Layzspa ready"); + doc["unique_id"] = "binary_sensor.layzspa_ready"+mychipid; + doc["state_topic"] = mqttBaseTopic+F("/message"); + doc["value_template"] = F("{% if value_json.TMP > 30 %}{% if value_json.TMP >= value_json.TGT-1 %}ON{% else %}OFF{% endif %}{% else %}OFF{% endif %}"); doc["expire_after"] = 700; - doc["availability_topic"] = mqttBaseTopic+"/Status"; - doc["payload_available"] = "Alive"; - doc["payload_not_available"] = "Dead"; + doc["icon"] = F("mdi:hot-tub"); + doc["availability_topic"] = mqttBaseTopic+F("/Status"); + doc["payload_available"] = F("Alive"); + doc["payload_not_available"] = F("Dead"); if (serializeJson(doc, payload) == 0) { Serial.println(F("Failed to serialize HA message!")); @@ -1615,20 +1623,20 @@ void setupHA() doc.clear(); doc.garbageCollect(); - // spa heater binary_sensor + // spa connection status binary_sensor doc["device"] = devicedoc["device"]; payload = ""; - topic = String(HA_PREFIX) + "/binary_sensor/layzspa_heater/config"; + topic = String(HA_PREFIX) + F("/binary_sensor/layzspa_connection/config"); Serial.println(topic); - doc["name"] = "Layzspa heater"; - doc["unique_id"] = "binary_sensor.layzspa_heater"; - doc["state_topic"] = mqttBaseTopic+"/message"; - doc["value_template"] = "{% if value_json.RED == 1 %}ON{% else %}OFF{% endif %}"; - doc["device_class"] = "heat"; - doc["expire_after"] = 700; - doc["availability_topic"] = mqttBaseTopic+"/Status"; - doc["payload_available"] = "Alive"; - doc["payload_not_available"] = "Dead"; + doc["name"] = F("Layzspa connection"); + doc["unique_id"] = "binary_sensor.layzspa_connection"+mychipid; + doc["state_topic"] = mqttBaseTopic+F("/Status"); + doc["device-class"] = F("connectivity"); + doc["availability_topic"] = mqttBaseTopic+F("/Status"); + doc["payload_available"] = F("Alive"); + doc["payload_not_available"] = F("Dead"); + doc["payload_on"] = "Alive"; + doc["payload_off"] = "Dead"; if (serializeJson(doc, payload) == 0) { Serial.println(F("Failed to serialize HA message!")); @@ -1640,20 +1648,25 @@ void setupHA() doc.clear(); doc.garbageCollect(); - // spa ready binary_sensor + // spa heat regulation switch doc["device"] = devicedoc["device"]; payload = ""; - topic = String(HA_PREFIX) + "/binary_sensor/layzspa_ready/config"; + topic = String(HA_PREFIX) + F("/switch/layzspa_heat_regulation/config"); Serial.println(topic); - doc["name"] = "Layzspa ready"; - doc["unique_id"] = "binary_sensor.layzspa_ready"; - doc["state_topic"] = mqttBaseTopic+"/message"; - doc["value_template"] = "{% if value_json.TMP > 30 %}{% if value_json.TMP >= value_json.TGT-1 %}ON{% else %}OFF{% endif %}{% else %}OFF{% endif %}"; + doc["name"] = F("Layzspa heat regulation"); + doc["unique_id"] = "switch.layzspa_heat_regulation"+mychipid; + doc["state_topic"] = mqttBaseTopic+F("/message"); + doc["command_topic"] = mqttBaseTopic+F("/command"); + doc["value_template"] = F("{% if value_json.RED == 1 %}1{% elif value_json.GRN == 1 %}1{% else %}0{% endif %}"); doc["expire_after"] = 700; - doc["icon"] = "mdi:hot-tub"; - doc["availability_topic"] = mqttBaseTopic+"/Status"; - doc["payload_available"] = "Alive"; - doc["payload_not_available"] = "Dead"; + doc["icon"] = F("mdi:radiator"); + doc["availability_topic"] = mqttBaseTopic+F("/Status"); + doc["payload_available"] = F("Alive"); + doc["payload_not_available"] = F("Dead"); + doc["payload_on"] = F("{CMD:3,VALUE:true,XTIME:0,INTERVAL:0}"); + doc["payload_off"] = F("{CMD:3,VALUE:false,XTIME:0,INTERVAL:0}"); + doc["state_on"] = 1; + doc["state_off"] = 0; if (serializeJson(doc, payload) == 0) { Serial.println(F("Failed to serialize HA message!")); @@ -1665,20 +1678,25 @@ void setupHA() doc.clear(); doc.garbageCollect(); - // spa connection status binary_sensor + // spa airbubbles switch doc["device"] = devicedoc["device"]; payload = ""; - topic = String(HA_PREFIX) + "/binary_sensor/layzspa_connection/config"; + topic = String(HA_PREFIX) + F("/switch/layzspa_airbubbles/config"); Serial.println(topic); - doc["name"] = "Layzspa connection"; - doc["unique_id"] = "binary_sensor.layzspa_connection"; - doc["state_topic"] = mqttBaseTopic+"/Status"; - doc["device-class"] = "connectivity"; - doc["availability_topic"] = mqttBaseTopic+"/Status"; - doc["payload_available"] = "Alive"; - doc["payload_not_available"] = "Dead"; - doc["payload_on"] = "Alive"; - doc["payload_off"] = "Dead"; + doc["name"] = F("Layzspa airbubbles"); + doc["unique_id"] = "switch.layzspa_airbubbles"+mychipid; + doc["state_topic"] = mqttBaseTopic+F("/message"); + doc["command_topic"] = mqttBaseTopic+F("/command"); + doc["value_template"] = F("{{ value_json.AIR }}"); + doc["expire_after"] = 700; + doc["icon"] = F("mdi:chart-bubble"); + doc["availability_topic"] = mqttBaseTopic+F("/Status"); + doc["payload_available"] = F("Alive"); + doc["payload_not_available"] = F("Dead"); + doc["payload_on"] = F("{CMD:2,VALUE:true,XTIME:0,INTERVAL:0}"); + doc["payload_off"] = F("{CMD:2,VALUE:false,XTIME:0,INTERVAL:0}"); + doc["state_on"] = 1; + doc["state_off"] = 0; if (serializeJson(doc, payload) == 0) { Serial.println(F("Failed to serialize HA message!")); @@ -1690,23 +1708,23 @@ void setupHA() doc.clear(); doc.garbageCollect(); - // spa heat regulation switch + // spa pump switch doc["device"] = devicedoc["device"]; payload = ""; - topic = String(HA_PREFIX) + "/switch/layzspa_heat_regulation/config"; + topic = String(HA_PREFIX) + F("/switch/layzspa_pump/config"); Serial.println(topic); - doc["name"] = "Layzspa heat regulation"; - doc["unique_id"] = "switch.layzspa_heat_regulation"; - doc["state_topic"] = mqttBaseTopic+"/message"; - doc["command_topic"] = mqttBaseTopic+"/command"; - doc["value_template"] = "{% if value_json.RED == 1 %}1{% elif value_json.GRN == 1 %}1{% else %}0{% endif %}"; + doc["name"] = F("Layzspa pump"); + doc["unique_id"] = "switch.layzspa_pump"+mychipid; + doc["state_topic"] = mqttBaseTopic+F("/message"); + doc["command_topic"] = mqttBaseTopic+F("/command"); + doc["value_template"] = F("{{ value_json.FLT }}"); doc["expire_after"] = 700; - doc["icon"] = "mdi:radiator"; - doc["availability_topic"] = mqttBaseTopic+"/Status"; - doc["payload_available"] = "Alive"; - doc["payload_not_available"] = "Dead"; - doc["payload_on"] = "{CMD:3,VALUE:true,XTIME:0,INTERVAL:0}"; - doc["payload_off"] = "{CMD:3,VALUE:false,XTIME:0,INTERVAL:0}"; + doc["icon"] = F("mdi:pump"); + doc["availability_topic"] = mqttBaseTopic+F("/Status"); + doc["payload_available"] = F("Alive"); + doc["payload_not_available"] = F("Dead"); + doc["payload_on"] = F("{CMD:4,VALUE:true,XTIME:0,INTERVAL:0}"); + doc["payload_off"] = F("{CMD:4,VALUE:false,XTIME:0,INTERVAL:0}"); doc["state_on"] = 1; doc["state_off"] = 0; if (serializeJson(doc, payload) == 0) @@ -1720,23 +1738,23 @@ void setupHA() doc.clear(); doc.garbageCollect(); - // spa airbubbles switch + // spa temperature unit switch doc["device"] = devicedoc["device"]; payload = ""; - topic = String(HA_PREFIX) + "/switch/layzspa_airbubbles/config"; + topic = String(HA_PREFIX) + F("/switch/layzspa_temperature_unit/config"); Serial.println(topic); - doc["name"] = "Layzspa airbubbles"; - doc["unique_id"] = "switch.layzspa_airbubbles"; - doc["state_topic"] = mqttBaseTopic+"/message"; - doc["command_topic"] = mqttBaseTopic+"/command"; - doc["value_template"] = "{{ value_json.AIR }}"; + doc["name"] = F("Layzspa temperature unit F-C"); + doc["unique_id"] = "switch.layzspa_unit"+mychipid; + doc["state_topic"] = mqttBaseTopic+F("/message"); + doc["command_topic"] = mqttBaseTopic+F("/command"); + doc["value_template"] = F("{{ value_json.UNT }}"); doc["expire_after"] = 700; - doc["icon"] = "mdi:chart-bubble"; - doc["availability_topic"] = mqttBaseTopic+"/Status"; - doc["payload_available"] = "Alive"; - doc["payload_not_available"] = "Dead"; - doc["payload_on"] = "{CMD:2,VALUE:true,XTIME:0,INTERVAL:0}"; - doc["payload_off"] = "{CMD:2,VALUE:false,XTIME:0,INTERVAL:0}"; + doc["icon"] = F("mdi:circle-outline"); + doc["availability_topic"] = mqttBaseTopic+F("/Status"); + doc["payload_available"] = F("Alive"); + doc["payload_not_available"] = F("Dead"); + doc["payload_on"] = F("{CMD:1,VALUE:true,XTIME:0,INTERVAL:0}"); + doc["payload_off"] = F("{CMD:1,VALUE:false,XTIME:0,INTERVAL:0}"); doc["state_on"] = 1; doc["state_off"] = 0; if (serializeJson(doc, payload) == 0) @@ -1750,25 +1768,19 @@ void setupHA() doc.clear(); doc.garbageCollect(); - // spa pump switch + // spa reset chlorine timer button doc["device"] = devicedoc["device"]; payload = ""; - topic = String(HA_PREFIX) + "/switch/layzspa_pump/config"; + topic = String(HA_PREFIX) + F("/button/layzspa_reset_chlorine/config"); Serial.println(topic); - doc["name"] = "Layzspa pump"; - doc["unique_id"] = "switch.layzspa_pump"; - doc["state_topic"] = mqttBaseTopic+"/message"; - doc["command_topic"] = mqttBaseTopic+"/command"; - doc["value_template"] = "{{ value_json.FLT }}"; - doc["expire_after"] = 700; - doc["icon"] = "mdi:pump"; - doc["availability_topic"] = mqttBaseTopic+"/Status"; - doc["payload_available"] = "Alive"; - doc["payload_not_available"] = "Dead"; - doc["payload_on"] = "{CMD:4,VALUE:true,XTIME:0,INTERVAL:0}"; - doc["payload_off"] = "{CMD:4,VALUE:false,XTIME:0,INTERVAL:0}"; - doc["state_on"] = 1; - doc["state_off"] = 0; + doc["name"] = F("Layzspa reset chlorine timer"); + doc["unique_id"] = "button.layzspa_reset_chlorine"+mychipid; + doc["command_topic"] = mqttBaseTopic+F("/command"); + doc["payload_press"] = F("{CMD:9,VALUE:true,XTIME:0,INTERVAL:0}"); + doc["icon"] = F("mdi:restart"); + doc["availability_topic"] = mqttBaseTopic+F("/Status"); + doc["payload_available"] = F("Alive"); + doc["payload_not_available"] = F("Dead"); if (serializeJson(doc, payload) == 0) { Serial.println(F("Failed to serialize HA message!")); @@ -1780,25 +1792,19 @@ void setupHA() doc.clear(); doc.garbageCollect(); - // spa temperature unit switch + // spa reset filter timer button doc["device"] = devicedoc["device"]; payload = ""; - topic = String(HA_PREFIX) + "/switch/layzspa_temperature_unit/config"; + topic = String(HA_PREFIX) + F("/button/layzspa_reset_filter/config"); Serial.println(topic); - doc["name"] = "Layzspa temperature unit"; - doc["unique_id"] = "switch.layzspa_unit"; - doc["state_topic"] = mqttBaseTopic+"/message"; - doc["command_topic"] = mqttBaseTopic+"/command"; - doc["value_template"] = "{{ value_json.UNT }}"; - doc["expire_after"] = 700; - doc["icon"] = "mdi:temperature-celsius"; - doc["availability_topic"] = mqttBaseTopic+"/Status"; - doc["payload_available"] = "Alive"; - doc["payload_not_available"] = "Dead"; - doc["payload_on"] = "{CMD:1,VALUE:true,XTIME:0,INTERVAL:0}"; - doc["payload_off"] = "{CMD:1,VALUE:false,XTIME:0,INTERVAL:0}"; - doc["state_on"] = 1; - doc["state_off"] = 0; + doc["name"] = F("Layzspa reset filter timer"); + doc["unique_id"] = "button.layzspa_reset_filter"+mychipid; + doc["command_topic"] = mqttBaseTopic+F("/command"); + doc["payload_press"] = F("{CMD:10,VALUE:true,XTIME:0,INTERVAL:0}"); + doc["icon"] = F("mdi:restart"); + doc["availability_topic"] = mqttBaseTopic+F("/Status"); + doc["payload_available"] = F("Alive"); + doc["payload_not_available"] = F("Dead"); if (serializeJson(doc, payload) == 0) { Serial.println(F("Failed to serialize HA message!")); @@ -1810,19 +1816,20 @@ void setupHA() doc.clear(); doc.garbageCollect(); - // spa reset chlorine timer button + // spa restart esp button doc["device"] = devicedoc["device"]; payload = ""; - topic = String(HA_PREFIX) + "/button/layzspa_reset_chlorine/config"; + topic = String(HA_PREFIX) + F("/button/layzspa_restart_esp/config"); Serial.println(topic); - doc["name"] = "Layzspa reset chlorine timer"; - doc["unique_id"] = "button.layzspa_reset_chlorine"; - doc["command_topic"] = mqttBaseTopic+"/command"; - doc["payload_press"] = "{CMD:9,VALUE:true,XTIME:0,INTERVAL:0}"; - doc["icon"] = "mdi:restart"; - doc["availability_topic"] = mqttBaseTopic+"/Status"; - doc["payload_available"] = "Alive"; - doc["payload_not_available"] = "Dead"; + doc["name"] = F("Layzspa restart esp"); + doc["unique_id"] = "button.layzspa_restart_esp"+mychipid; + doc["command_topic"] = mqttBaseTopic+F("/command"); + doc["payload_press"] = F("{CMD:6,VALUE:true,XTIME:0,INTERVAL:0}"); + doc["icon"] = F("mdi:restart"); + doc["device_class"] = F("restart"); + doc["availability_topic"] = mqttBaseTopic+F("/Status"); + doc["payload_available"] = F("Alive"); + doc["payload_not_available"] = F("Dead"); if (serializeJson(doc, payload) == 0) { Serial.println(F("Failed to serialize HA message!")); @@ -1834,19 +1841,57 @@ void setupHA() doc.clear(); doc.garbageCollect(); - // spa reset filter timer button + doc.clear(); + doc.garbageCollect(); + + setupClimate(); +} + +void setupClimate() +{ + String mychipid = String((unsigned int)ESP.getChipId()); + int maxtemp, mintemp; + String tempunit, tempunit2; + if(bwc.getState(UNITSTATE)) + { + maxtemp = 40; + mintemp = 20; + tempunit = "C"; + tempunit2 = "°C"; + } + else + { + maxtemp = 104; + mintemp = 68; + tempunit = "F"; + tempunit2 = "°F"; + } + String topic; + String payload; + DynamicJsonDocument devicedoc(512); + DynamicJsonDocument doc(2048); + devicedoc["device"]["configuration_url"] = "http://" + WiFi.localIP().toString(); + devicedoc["device"]["connections"].add(serialized("[\"mac\",\"" + WiFi.macAddress()+"\"]" )); + devicedoc["device"]["identifiers"] = ESP.getChipId(); + devicedoc["device"]["manufacturer"] = "Visualapproach"; + devicedoc["device"]["model"] = "NodeMCU 12E"; + devicedoc["device"]["name"] = "Layzspa WiFi controller"; + devicedoc["device"]["sw_version"] = FW_VERSION; + + // spa temperature sensor doc["device"] = devicedoc["device"]; payload = ""; - topic = String(HA_PREFIX) + "/button/layzspa_reset_filter/config"; + topic = String(HA_PREFIX) + F("/sensor/layzspa_temperature/config"); Serial.println(topic); - doc["name"] = "Layzspa reset filter timer"; - doc["unique_id"] = "button.layzspa_reset_filter"; - doc["command_topic"] = mqttBaseTopic+"/command"; - doc["payload_press"] = "{CMD:10,VALUE:true,XTIME:0,INTERVAL:0}"; - doc["icon"] = "mdi:restart"; - doc["availability_topic"] = mqttBaseTopic+"/Status"; - doc["payload_available"] = "Alive"; - doc["payload_not_available"] = "Dead"; + doc["name"] = F("Layzspa temperature"); + doc["unique_id"] = "sensor.layzspa_temperature"+mychipid; + doc["state_topic"] = mqttBaseTopic+F("/message"); + doc["unit_of_measurement"] = tempunit2; + doc["value_template"] = F("{{ value_json.TMP }}"); + doc["expire_after"] = 700; + doc["availability_topic"] = mqttBaseTopic+F("/Status"); + doc["payload_available"] = F("Alive"); + doc["payload_not_available"] = F("Dead"); if (serializeJson(doc, payload) == 0) { Serial.println(F("Failed to serialize HA message!")); @@ -1858,20 +1903,20 @@ void setupHA() doc.clear(); doc.garbageCollect(); - // spa restart esp button + // spa target temperature sensor doc["device"] = devicedoc["device"]; payload = ""; - topic = String(HA_PREFIX) + "/button/layzspa_restart_esp/config"; + topic = String(HA_PREFIX) + F("/sensor/layzspa_target_temperature/config"); Serial.println(topic); - doc["name"] = "Layzspa restart esp"; - doc["unique_id"] = "button.layzspa_restart_esp"; - doc["command_topic"] = mqttBaseTopic+"/command"; - doc["payload_press"] = "{CMD:6,VALUE:true,XTIME:0,INTERVAL:0}"; - doc["icon"] = "mdi:restart"; - doc["device_class"] = "restart"; - doc["availability_topic"] = mqttBaseTopic+"/Status"; - doc["payload_available"] = "Alive"; - doc["payload_not_available"] = "Dead"; + doc["name"] = F("Layzspa target temperature"); + doc["unique_id"] = "sensor.layzspa_target_temperature"+mychipid; + doc["state_topic"] = mqttBaseTopic+F("/message"); + doc["unit_of_measurement"] = tempunit2; + doc["value_template"] = F("{{ value_json.TGT }}"); + doc["expire_after"] = 700; + doc["availability_topic"] = mqttBaseTopic+F("/Status"); + doc["payload_available"] = F("Alive"); + doc["payload_not_available"] = F("Dead"); if (serializeJson(doc, payload) == 0) { Serial.println(F("Failed to serialize HA message!")); @@ -1883,34 +1928,36 @@ void setupHA() doc.clear(); doc.garbageCollect(); + // spa climate control + doc["device"] = devicedoc["device"]; payload = ""; - topic = String(HA_PREFIX) + "/climate/layzspa_climate/config"; + topic = String(HA_PREFIX) + F("/climate/layzspa_climate/config"); Serial.println(topic); - doc["name"] = "Layzspa temperature control"; - doc["unique_id"] = "button.layzspa_climate"; - doc["max_temp"] = 40; - doc["min_temp"] = 20; + doc["name"] = F("Layzspa temperature control"); + doc["unique_id"] = "button.layzspa_climate"+mychipid; + doc["max_temp"] = maxtemp; + doc["min_temp"] = mintemp; doc["precision"] = 1.0; - doc["temperature_unit"] = "C"; + doc["temperature_unit"] = tempunit; doc["modes"].add(serialized("\"off\", \"heat\"")); - doc["mode_state_topic"] = mqttBaseTopic+"/message"; - doc["mode_state_template"] = "{% if value_json.RED == 1 %}heat{% elif value_json.GRN == 1 %}heat{% else %}off{% endif %}"; - doc["action_topic"] = mqttBaseTopic+"/message"; - doc["action_template"] = "{% if value_json.RED == 1 %}heating{% elif value_json.GRN == 1 %}idle{% else %}off{% endif %}"; - doc["temperature_state_topic"] = mqttBaseTopic+"/message"; - doc["temperature_state_template"] = "{{ value_json.TGT }}"; - doc["current_temperature_topic"] = mqttBaseTopic+"/message"; - doc["current_temperature_template"] = "{{ value_json.TMP }}"; - doc["temperature_command_topic"] = mqttBaseTopic+"/command"; - doc["temperature_command_template"] = "{CMD:0,VALUE:{{ value|int }},XTIME:0,INTERVAL:0}"; - doc["power_command_topic"] = mqttBaseTopic+"/command"; - doc["payload_on"] = "{CMD:3,VALUE:1,XTIME:0,INTERVAL:0}"; - doc["payload_off"] = "{CMD:3,VALUE:0,XTIME:0,INTERVAL:0}"; - doc["availability_topic"] = mqttBaseTopic+"/Status"; - doc["payload_available"] = "Alive"; - doc["payload_not_available"] = "Dead"; + doc["mode_state_topic"] = mqttBaseTopic+F("/message"); + doc["mode_state_template"] = F("{% if value_json.RED == 1 %}heat{% elif value_json.GRN == 1 %}heat{% else %}off{% endif %}"); + doc["action_topic"] = mqttBaseTopic+F("/message"); + doc["action_template"] = F("{% if value_json.RED == 1 %}heating{% elif value_json.GRN == 1 %}idle{% else %}off{% endif %}"); + doc["temperature_state_topic"] = mqttBaseTopic+F("/message"); + doc["temperature_state_template"] = F("{{ value_json.TGT }}"); + doc["current_temperature_topic"] = mqttBaseTopic+F("/message"); + doc["current_temperature_template"] = F("{{ value_json.TMP }}"); + doc["temperature_command_topic"] = mqttBaseTopic+F("/command"); + doc["temperature_command_template"] = F("{CMD:0,VALUE:{{ value|int }},XTIME:0,INTERVAL:0}"); + doc["power_command_topic"] = mqttBaseTopic+F("/command"); + doc["payload_on"] = F("{CMD:3,VALUE:1,XTIME:0,INTERVAL:0}"); + doc["payload_off"] = F("{CMD:3,VALUE:0,XTIME:0,INTERVAL:0}"); + doc["availability_topic"] = mqttBaseTopic+F("/Status"); + doc["payload_available"] = F("Alive"); + doc["payload_not_available"] = F("Dead"); if (serializeJson(doc, payload) == 0) { Serial.println(F("Failed to serialize HA message!")); @@ -1919,8 +1966,4 @@ void setupHA() mqttClient.publish(topic.c_str(), payload.c_str(), true); mqttClient.loop(); Serial.println(payload); - doc.clear(); - doc.garbageCollect(); - - -} +} \ No newline at end of file diff --git a/Code/6-wire-version/src/main.h b/Code/6-wire-version/src/main.h index 887ff3c9..f0b50b42 100644 --- a/Code/6-wire-version/src/main.h +++ b/Code/6-wire-version/src/main.h @@ -58,6 +58,8 @@ int mqtt_connect_count; /** */ String prevButtonName = ""; /** */ +bool prevunit = 1; +/** */ Ticker updateMqttTimer; /** */ bool sendMQTTFlag = false; @@ -111,4 +113,5 @@ void handleRestart(); void startMqtt(); void mqttCallback(char* topic, byte* payload, unsigned int length); void mqttConnect(); -void setupHA(); \ No newline at end of file +void setupHA(); +void setupClimate(); \ No newline at end of file From c1a68a6a86c05341f9b0320231ae3c5ee27d0026 Mon Sep 17 00:00:00 2001 From: visualapproach Date: Fri, 18 Mar 2022 18:50:24 +0100 Subject: [PATCH 06/10] 6w: resetting timers trigger mqtt/ws msg --- Code/6-wire-version/lib/BWC/BWC_8266.cpp | 3 +++ Code/6-wire-version/lib/BWC54149E/BWC54149E_8266.cpp | 3 +++ 2 files changed, 6 insertions(+) diff --git a/Code/6-wire-version/lib/BWC/BWC_8266.cpp b/Code/6-wire-version/lib/BWC/BWC_8266.cpp index 30208bde..aab3802d 100644 --- a/Code/6-wire-version/lib/BWC/BWC_8266.cpp +++ b/Code/6-wire-version/lib/BWC/BWC_8266.cpp @@ -698,14 +698,17 @@ void BWC::_handleCommandQ(void) { _airtime_ms = 0; _cost = 0; _saveSettingsNeeded = true; + _cio.dataAvailable = true; break; case RESETCLTIMER: _cltime = _timestamp; _saveSettingsNeeded = true; + _cio.dataAvailable = true; break; case RESETFTIMER: _ftime = _timestamp; _saveSettingsNeeded = true; + _cio.dataAvailable = true; break; case SETJETS: _qButton(HYDROJETS, JETSSTATE, _commandQ[0][1], 5000); diff --git a/Code/6-wire-version/lib/BWC54149E/BWC54149E_8266.cpp b/Code/6-wire-version/lib/BWC54149E/BWC54149E_8266.cpp index 6ac8f709..c202c214 100644 --- a/Code/6-wire-version/lib/BWC54149E/BWC54149E_8266.cpp +++ b/Code/6-wire-version/lib/BWC54149E/BWC54149E_8266.cpp @@ -674,14 +674,17 @@ void BWC::_handleCommandQ(void) { _airtime_ms = 0; _cost = 0; _saveSettingsNeeded = true; + _cio.dataAvailable = true; break; case RESETCLTIMER: _cltime = _timestamp; _saveSettingsNeeded = true; + _cio.dataAvailable = true; break; case RESETFTIMER: _ftime = _timestamp; _saveSettingsNeeded = true; + _cio.dataAvailable = true; break; case SETJETS: _qButton(HYDROJETS, JETSSTATE, _commandQ[0][1], 5000); From 98492134bf7433e37451af7cf205c1db269638f4 Mon Sep 17 00:00:00 2001 From: visualapproach Date: Fri, 18 Mar 2022 18:58:15 +0100 Subject: [PATCH 07/10] update build instructions (HA) --- Build-instructions-Bestway-WiFi-remote.pdf | Bin 991106 -> 1104888 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/Build-instructions-Bestway-WiFi-remote.pdf b/Build-instructions-Bestway-WiFi-remote.pdf index d23ab7c2648273b2c10c4c46dc3ba663230a6317..ce4bd0b7253720e820bc31e25e3e6905e57741af 100644 GIT binary patch delta 177411 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

?6Ynt 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 delta 64173 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 From 6455547b0b521232ca18960e2af4d9eabec6d4ca Mon Sep 17 00:00:00 2001 From: visualapproach Date: Fri, 25 Mar 2022 16:58:03 +0100 Subject: [PATCH 08/10] 6w: clock period metric Measures minimum time between clock edges to track bad connection --- Code/6-wire-version/lib/BWC/BWC_8266.cpp | 9 + Code/6-wire-version/lib/BWC/BWC_8266.h | 209 ++++++++++++----------- Code/6-wire-version/src/config.h | 2 +- 3 files changed, 115 insertions(+), 105 deletions(-) diff --git a/Code/6-wire-version/lib/BWC/BWC_8266.cpp b/Code/6-wire-version/lib/BWC/BWC_8266.cpp index aab3802d..68e72c14 100644 --- a/Code/6-wire-version/lib/BWC/BWC_8266.cpp +++ b/Code/6-wire-version/lib/BWC/BWC_8266.cpp @@ -166,6 +166,13 @@ void IRAM_ATTR CIO::packetHandler(void) { //CIO comm //Read incoming bits, and take action after a complete byte void IRAM_ATTR CIO::clkHandler(void) { + //sanity check on clock signal + static uint32_t prev_us = 0; + uint32_t us = micros(); + uint32_t period = 0; + if(us > prev_us) period = us - prev_us; //will be negative on rollover (once every hour-ish) + prev_us = us; + if(period < clk_per) clk_per = period; if (!_packet) return; //CS line is active, so send/receive bits on DATA line @@ -794,6 +801,8 @@ String BWC::getJSONTimes() { doc["CLINT"] = _clinterval; doc["KWH"] = _cost/_price; doc["TTTT"] = _tttt; + doc["MINCLK"] = _cio.clk_per; + _cio.clk_per = 1000; //reset minimum clock period // Serialize JSON to string String jsonmsg; diff --git a/Code/6-wire-version/lib/BWC/BWC_8266.h b/Code/6-wire-version/lib/BWC/BWC_8266.h index d57d621b..1a7fae08 100644 --- a/Code/6-wire-version/lib/BWC/BWC_8266.h +++ b/Code/6-wire-version/lib/BWC/BWC_8266.h @@ -25,27 +25,28 @@ class CIO { public: void begin(int cio_cs_pin, int cio_data_pin, int cio_clk_pin); - void loop(void); + void loop(void); void eopHandler(void); void packetHandler(void); void clkHandler(void); - void stop(void); + void stop(void); volatile bool newData = false; - bool dataAvailable = false; - bool stateChanged = false; //save states when true + bool dataAvailable = false; + bool stateChanged = false; //save states when true volatile uint16_t button = 0x1B1B; //no button uint8_t payload[11]; - uint8_t states[14]; - uint8_t brightness; - bool targetIsDisplayed = false; - //uint16_t lastPressedButton; + uint8_t states[14]; + uint8_t brightness; + bool targetIsDisplayed = false; + //uint16_t lastPressedButton; + volatile uint32_t clk_per; //lowest time between clock edges. Should be ~20 us. private: //add anti glitch method volatile int _byteCount = 0; - volatile int _bitCount = 0; + volatile int _bitCount = 0; volatile bool _dataIsOutput = false; volatile byte _receivedByte; volatile int _CIO_cmd_matches = 0; @@ -56,12 +57,12 @@ class CIO { int _CS_PIN; int _CLK_PIN; int _DATA_PIN; - uint8_t _prevPayload[11]; - bool _prevUNT; - bool _prevHTR; - bool _prevFLT; - - char _getChar(uint8_t value); + uint8_t _prevPayload[11]; + bool _prevUNT; + bool _prevHTR; + bool _prevFLT; + + char _getChar(uint8_t value); }; class DSP { @@ -71,113 +72,113 @@ class DSP { uint8_t payload[11] = {0xC0, 0x01, 0xFF, 0x01, 0xFF, 0x01, 0xFF, B00000001, 0xFF, 0x01, 0xFF}; void begin(int dsp_cs_pin, int dsp_data_pin, int dsp_clk_pin, int dsp_audio_pin); - uint16_t getButton(void); + uint16_t getButton(void); void updateDSP(uint8_t brightness); void textOut(String txt); - void LEDshow(); - void playIntro(); - void beep(); - void beep2(); + void LEDshow(); + void playIntro(); + void beep(); + void beep2(); private: void _sendBitsToDSP(uint32_t outBits, int bitsToSend); uint16_t _receiveBitsFromDSP(); char _getCode(char value); - - unsigned long _dspLastRefreshTime = 0; - unsigned long _dspLastGetButton = 0; - uint16_t _oldButton = ButtonCodes[NOBTN]; - //Pins - int _CS_PIN; - int _CLK_PIN; - int _DATA_PIN; - int _AUDIO_PIN; + + unsigned long _dspLastRefreshTime = 0; + unsigned long _dspLastGetButton = 0; + uint16_t _oldButton = ButtonCodes[NOBTN]; + //Pins + int _CS_PIN; + int _CLK_PIN; + int _DATA_PIN; + int _AUDIO_PIN; }; class BWC { public: - BWC(); - void begin(void); - void begin2(); + BWC(); + void begin(void); + void begin2(); void begin(int, int, int, int, int, int, int); void loop(); - bool qCommand(uint32_t cmd, uint32_t val, uint32_t xtime, uint32_t interval); - bool newData(); - void saveEventlog(); - String getJSONStates(); - String getJSONTimes(); - String getJSONSettings(); - void setJSONSettings(String message); - String getJSONCommandQueue(); - void print(String txt); - uint8_t getState(int state); - Ticker saveSettingsTimer; - void saveSettingsFlag(); - void saveSettings(); - bool maxeffort = false; - String getPressedButton(); - void reloadCommandQueue(); - void reloadSettings(); - String getButtonName(); - void saveDebugInfo(String s); - void stop(void); + bool qCommand(uint32_t cmd, uint32_t val, uint32_t xtime, uint32_t interval); + bool newData(); + void saveEventlog(); + String getJSONStates(); + String getJSONTimes(); + String getJSONSettings(); + void setJSONSettings(String message); + String getJSONCommandQueue(); + void print(String txt); + uint8_t getState(int state); + Ticker saveSettingsTimer; + void saveSettingsFlag(); + void saveSettings(); + bool maxeffort = false; + String getPressedButton(); + void reloadCommandQueue(); + void reloadSettings(); + String getButtonName(); + void saveDebugInfo(String s); + void stop(void); private: CIO _cio; DSP _dsp; - uint8_t _dspBrightness; - uint32_t _commandQ[MAXCOMMANDS][4]; - int _qCommandLen = 0; //length of commandQ - int32_t _buttonQ[MAXBUTTONS][4]; - int _qButtonLen = 0; //length of buttonQ - uint32_t _timestamp; - bool _newData = false; - uint32_t _cltime; - uint32_t _ftime; - uint32_t _uptime; - uint32_t _pumptime; - uint32_t _heatingtime; - uint32_t _airtime; - uint32_t _jettime; - uint32_t _uptime_ms; - uint32_t _pumptime_ms; - uint32_t _heatingtime_ms; - uint32_t _airtime_ms; - uint32_t _jettime_ms; - int32_t _timezone; - float _price; - uint32_t _finterval; - uint32_t _clinterval; - bool _audio; - float _cost; - bool _restoreStatesOnStart = false; - bool _saveSettingsNeeded = false; - bool _saveEventlogNeeded = false; - bool _saveCmdqNeeded = false; - bool _saveStatesNeeded = false; - int _latestTarget; - int _tickerCount; - bool _sliderPrio = true; - uint32_t _tttt_time0; //time at previous temperature change - uint32_t _tttt_time1; //time at last temperature change - int _tttt_temp0; //temp after previous change - int _tttt_temp1; //temp after last change - int _tttt; //time to target temperature after subtracting running time since last calculation - int _tttt_calculated; //constant between calculations - - void _qButton(uint32_t btn, uint32_t state, uint32_t value, int32_t maxduration); - void _handleCommandQ(void); - void _handleButtonQ(void); - void _startNTP(); - void _loadSettings(); - void _loadCommandQueue(); - void _saveCommandQueue(); - void _saveRebootInfo(); - void _updateTimes(); - void _restoreStates(); - void _saveStates(); - int _CodeToButton(uint16_t val); + uint8_t _dspBrightness; + uint32_t _commandQ[MAXCOMMANDS][4]; + int _qCommandLen = 0; //length of commandQ + int32_t _buttonQ[MAXBUTTONS][4]; + int _qButtonLen = 0; //length of buttonQ + uint32_t _timestamp; + bool _newData = false; + uint32_t _cltime; + uint32_t _ftime; + uint32_t _uptime; + uint32_t _pumptime; + uint32_t _heatingtime; + uint32_t _airtime; + uint32_t _jettime; + uint32_t _uptime_ms; + uint32_t _pumptime_ms; + uint32_t _heatingtime_ms; + uint32_t _airtime_ms; + uint32_t _jettime_ms; + int32_t _timezone; + float _price; + uint32_t _finterval; + uint32_t _clinterval; + bool _audio; + float _cost; + bool _restoreStatesOnStart = false; + bool _saveSettingsNeeded = false; + bool _saveEventlogNeeded = false; + bool _saveCmdqNeeded = false; + bool _saveStatesNeeded = false; + int _latestTarget; + int _tickerCount; + bool _sliderPrio = true; + uint32_t _tttt_time0; //time at previous temperature change + uint32_t _tttt_time1; //time at last temperature change + int _tttt_temp0; //temp after previous change + int _tttt_temp1; //temp after last change + int _tttt; //time to target temperature after subtracting running time since last calculation + int _tttt_calculated; //constant between calculations + + void _qButton(uint32_t btn, uint32_t state, uint32_t value, int32_t maxduration); + void _handleCommandQ(void); + void _handleButtonQ(void); + void _startNTP(); + void _loadSettings(); + void _loadCommandQueue(); + void _saveCommandQueue(); + void _saveRebootInfo(); + void _updateTimes(); + void _restoreStates(); + void _saveStates(); + int _CodeToButton(uint16_t val); }; #endif diff --git a/Code/6-wire-version/src/config.h b/Code/6-wire-version/src/config.h index e9b0abde..2e402cf3 100644 --- a/Code/6-wire-version/src/config.h +++ b/Code/6-wire-version/src/config.h @@ -2,7 +2,7 @@ #include #define DEVICE_NAME "layzspa" -#define FW_VERSION "2022-03-18" +#define FW_VERSION "2022-03-25" #define HA_PREFIX "homeassistant" /* From fc0370e30b09f83aa60620d34278c42010382a98 Mon Sep 17 00:00:00 2001 From: visualapproach Date: Sat, 26 Mar 2022 12:01:23 +0100 Subject: [PATCH 09/10] 6w: 2 fixes: Wrong unit in HA after ESP restart Drifting target temp after restart --- Code/6-wire-version/lib/BWC/BWC_8266.cpp | 731 +++++++++--------- .../lib/BWC54149E/BWC54149E_8266.cpp | 698 +++++++++-------- 2 files changed, 733 insertions(+), 696 deletions(-) diff --git a/Code/6-wire-version/lib/BWC/BWC_8266.cpp b/Code/6-wire-version/lib/BWC/BWC_8266.cpp index 68e72c14..fe194821 100644 --- a/Code/6-wire-version/lib/BWC/BWC_8266.cpp +++ b/Code/6-wire-version/lib/BWC/BWC_8266.cpp @@ -5,7 +5,7 @@ CIO *pointerToClass; //set flag instead of saving. This may avoid crashes. Some functions appears to crash when called from a timer. // static void tick(void){ - // pointerToBWC->saveSettingsFlag(); + // pointerToBWC->saveSettingsFlag(); // } static void IRAM_ATTR chipselectpin(void) { @@ -25,6 +25,21 @@ void CIO::begin(int cio_cs_pin, int cio_data_pin, int cio_clk_pin) { pinMode(_CLK_PIN, INPUT); attachInterrupt(digitalPinToInterrupt(_CS_PIN), chipselectpin, CHANGE); attachInterrupt(digitalPinToInterrupt(_CLK_PIN), clockpin, CHANGE); //Write on falling edge and read on rising edge + while(!newData) delay(1); //wait for an update from cio + //initialize states + states[LOCKEDSTATE] = (_payload[LCK_IDX] & (1 << LCK_BIT)) > 0; + states[POWERSTATE] = (_payload[PWR_IDX] & (1 << PWR_BIT)) > 0; + states[UNITSTATE] = (_payload[C_IDX] & (1 << C_BIT)) > 0; + states[BUBBLESSTATE] = (_payload[AIR_IDX] & (1 << AIR_BIT)) > 0; + states[HEATGRNSTATE] = (_payload[GRNHTR_IDX] & (1 << GRNHTR_BIT)) > 0; + states[HEATREDSTATE] = (_payload[REDHTR_IDX] & (1 << REDHTR_BIT)) > 0; + states[HEATSTATE] = states[HEATGRNSTATE] || states[HEATREDSTATE]; + states[PUMPSTATE] = (_payload[FLT_IDX] & (1 << FLT_BIT)) > 0; + states[CHAR1] = (uint8_t)_getChar(_payload[DGT1_IDX]); + states[CHAR2] = (uint8_t)_getChar(_payload[DGT2_IDX]); + states[CHAR3] = (uint8_t)_getChar(_payload[DGT3_IDX]); + if(HASJETS) states[JETSSTATE] = (_payload[HJT_IDX] & (1 << HJT_BIT)) > 0; + else states[JETSSTATE] = 0; } void CIO::stop(){ @@ -43,67 +58,67 @@ char CIO::_getChar(uint8_t value) { } void CIO::loop(void) { - //newdata is true when a data packet has arrived from cio - if(newData) { - newData = false; - static int capturePhase = 0; - static uint32_t buttonReleaseTime; - static uint16_t prevButton = ButtonCodes[NOBTN]; + //newdata is true when a data packet has arrived from cio + if(newData) { + newData = false; + static int capturePhase = 0; + static uint32_t buttonReleaseTime; + static uint16_t prevButton = ButtonCodes[NOBTN]; //require two consecutive messages to be equal before registering - static uint8_t prev_checksum = 0; + static uint8_t prev_checksum = 0; uint8_t checksum = 0; for(int i = 0; i < 11; i++){ - checksum += _payload[i]; - } + checksum += _payload[i]; + } if(checksum != prev_checksum) { prev_checksum = checksum; return; } prev_checksum = checksum; - //copy private array to public array - for(int i = 0; i < 11; i++){ - payload[i] = _payload[i]; - } - - //determine if anything changed, so we can update webclients - for(int i = 0; i < 11; i++){ - if (payload[i] != _prevPayload[i]) dataAvailable = true; - _prevPayload[i] = payload[i]; - } - - brightness = _brightness & 7; //extract only the brightness bits (0-7) - //extract information from payload to a better format - states[LOCKEDSTATE] = (payload[LCK_IDX] & (1 << LCK_BIT)) > 0; - states[POWERSTATE] = (payload[PWR_IDX] & (1 << PWR_BIT)) > 0; - states[UNITSTATE] = (payload[C_IDX] & (1 << C_BIT)) > 0; - states[BUBBLESSTATE] = (payload[AIR_IDX] & (1 << AIR_BIT)) > 0; - states[HEATGRNSTATE] = (payload[GRNHTR_IDX] & (1 << GRNHTR_BIT)) > 0; - states[HEATREDSTATE] = (payload[REDHTR_IDX] & (1 << REDHTR_BIT)) > 0; - states[HEATSTATE] = states[HEATGRNSTATE] || states[HEATREDSTATE]; - states[PUMPSTATE] = (payload[FLT_IDX] & (1 << FLT_BIT)) > 0; - states[CHAR1] = (uint8_t)_getChar(payload[DGT1_IDX]); - states[CHAR2] = (uint8_t)_getChar(payload[DGT2_IDX]); - states[CHAR3] = (uint8_t)_getChar(payload[DGT3_IDX]); + //copy private array to public array + for(int i = 0; i < 11; i++){ + payload[i] = _payload[i]; + } + + //determine if anything changed, so we can update webclients + for(int i = 0; i < 11; i++){ + if (payload[i] != _prevPayload[i]) dataAvailable = true; + _prevPayload[i] = payload[i]; + } + + brightness = _brightness & 7; //extract only the brightness bits (0-7) + //extract information from payload to a better format + states[LOCKEDSTATE] = (payload[LCK_IDX] & (1 << LCK_BIT)) > 0; + states[POWERSTATE] = (payload[PWR_IDX] & (1 << PWR_BIT)) > 0; + states[UNITSTATE] = (payload[C_IDX] & (1 << C_BIT)) > 0; + states[BUBBLESSTATE] = (payload[AIR_IDX] & (1 << AIR_BIT)) > 0; + states[HEATGRNSTATE] = (payload[GRNHTR_IDX] & (1 << GRNHTR_BIT)) > 0; + states[HEATREDSTATE] = (payload[REDHTR_IDX] & (1 << REDHTR_BIT)) > 0; + states[HEATSTATE] = states[HEATGRNSTATE] || states[HEATREDSTATE]; + states[PUMPSTATE] = (payload[FLT_IDX] & (1 << FLT_BIT)) > 0; + states[CHAR1] = (uint8_t)_getChar(payload[DGT1_IDX]); + states[CHAR2] = (uint8_t)_getChar(payload[DGT2_IDX]); + states[CHAR3] = (uint8_t)_getChar(payload[DGT3_IDX]); if(HASJETS) states[JETSSTATE] = (payload[HJT_IDX] & (1 << HJT_BIT)) > 0; else states[JETSSTATE] = 0; - //Determine if display is showing target temp or actual temp or anything else. - //capture TARGET after UP/DOWN has been pressed... - if( ((button == ButtonCodes[UP]) || (button == ButtonCodes[DOWN])) && (prevButton != ButtonCodes[UP]) && (prevButton != ButtonCodes[DOWN]) ) capturePhase = 1; - //...until 2 seconds after UP/DOWN released - if( (button == ButtonCodes[UP]) || (button == ButtonCodes[DOWN]) ) buttonReleaseTime = millis(); - if(millis()-buttonReleaseTime > 2000) capturePhase = 0; - //convert text on display to a value if the chars are recognized + //Determine if display is showing target temp or actual temp or anything else. + //capture TARGET after UP/DOWN has been pressed... + if( ((button == ButtonCodes[UP]) || (button == ButtonCodes[DOWN])) && (prevButton != ButtonCodes[UP]) && (prevButton != ButtonCodes[DOWN]) ) capturePhase = 1; + //...until 2 seconds after UP/DOWN released + if( (button == ButtonCodes[UP]) || (button == ButtonCodes[DOWN]) ) buttonReleaseTime = millis(); + if(millis()-buttonReleaseTime > 2000) capturePhase = 0; + //convert text on display to a value if the chars are recognized if(states[CHAR1] == '*' || states[CHAR2] == '*' || states[CHAR3] == '*') return; - String tempstring = String((char)states[CHAR1])+String((char)states[CHAR2])+String((char)states[CHAR3]); - uint8_t tmpTemp = tempstring.toInt(); - //capture only if showing plausible values (not blank screen while blinking) - if( (capturePhase == 1) && (tmpTemp > 19) ) { - states[TARGET] = tmpTemp; - } - //wait 4 seconds after UP/DOWN is released to be sure that actual temp is shown - if( (capturePhase == 0) && (millis()-buttonReleaseTime > 10000) && payload[DGT3_IDX]!=0xED && payload[DGT3_IDX]!=0) states[TEMPERATURE] = tmpTemp; - prevButton = button; + String tempstring = String((char)states[CHAR1])+String((char)states[CHAR2])+String((char)states[CHAR3]); + uint8_t tmpTemp = tempstring.toInt(); + //capture only if showing plausible values (not blank screen while blinking) + if( (capturePhase == 1) && (tmpTemp > 19) ) { + states[TARGET] = tmpTemp; + } + //wait 4 seconds after UP/DOWN is released to be sure that actual temp is shown + if( (capturePhase == 0) && (millis()-buttonReleaseTime > 10000) && payload[DGT3_IDX]!=0xED && payload[DGT3_IDX]!=0) states[TEMPERATURE] = tmpTemp; + prevButton = button; if(states[UNITSTATE] != _prevUNT || states[HEATSTATE] != _prevHTR || states[PUMPSTATE] != _prevFLT) { stateChanged = true; @@ -111,7 +126,7 @@ void CIO::loop(void) { _prevHTR = states[HEATSTATE]; _prevFLT = states[PUMPSTATE]; } - } + } } //end of packet @@ -139,7 +154,7 @@ void IRAM_ATTR CIO::eopHandler(void) { _brightness = msg; _CIO_cmd_matches = 0; newData = true; - } + } if (_CIO_cmd_matches == 2) { _CIO_cmd_matches = 3; } @@ -191,7 +206,7 @@ void IRAM_ATTR CIO::clkHandler(void) { WRITE_PERI_REG( PIN_OUT_CLEAR, 1 << _DATA_PIN); } _sendBit++; - if(_sendBit > 15) _sendBit = 0; + if(_sendBit > 15) _sendBit = 0; } //read bits on high clock (rising edge) @@ -220,18 +235,18 @@ void IRAM_ATTR CIO::clkHandler(void) { uint16_t DSP::getButton(void) { if(millis() - _dspLastGetButton > 50){ - uint16_t newButton = 0; - _dspLastGetButton = millis(); - //send request - //pinMode(_DATA_PIN, OUTPUT); - digitalWrite(_CS_PIN, LOW); //start of packet - delayMicroseconds(50); - _sendBitsToDSP(DSP_CMD2_DATAREAD, 8); //request button presses - newButton = _receiveBitsFromDSP(); - digitalWrite(_CS_PIN, HIGH); //end of packet - delayMicroseconds(30); - _oldButton = newButton; - return (newButton); + uint16_t newButton = 0; + _dspLastGetButton = millis(); + //send request + //pinMode(_DATA_PIN, OUTPUT); + digitalWrite(_CS_PIN, LOW); //start of packet + delayMicroseconds(50); + _sendBitsToDSP(DSP_CMD2_DATAREAD, 8); //request button presses + newButton = _receiveBitsFromDSP(); + digitalWrite(_CS_PIN, HIGH); //end of packet + delayMicroseconds(30); + _oldButton = newButton; + return (newButton); } else return (_oldButton); } @@ -259,7 +274,7 @@ uint16_t DSP::_receiveBitsFromDSP() { delayMicroseconds(20); digitalWrite(_CLK_PIN, HIGH); //clock trailing edge delayMicroseconds(20); - int j = (i+8)%16; //bit 8-16 then 0-7 + int j = (i+8)%16; //bit 8-16 then 0-7 result |= digitalRead(_DATA_PIN) << j; } return result; @@ -275,32 +290,32 @@ char DSP::_getCode(char value) { } void DSP::updateDSP(uint8_t brightness) { - //refresh display with ~10Hz - if(millis() -_dspLastRefreshTime > 99){ - _dspLastRefreshTime = millis(); - delayMicroseconds(30); - digitalWrite(_CS_PIN, LOW); //start of packet - _sendBitsToDSP(DSP_CMD1_MODE6_11_7, 8); - digitalWrite(_CS_PIN, HIGH); //end of packet - - delayMicroseconds(50); - digitalWrite(_CS_PIN, LOW);//start of packet - _sendBitsToDSP(DSP_CMD2_DATAWRITE, 8); - digitalWrite(_CS_PIN, HIGH);//end of packet - - //payload - delayMicroseconds(50); - digitalWrite(_CS_PIN, LOW);//start of packet - for (int i = 0; i < 11; i++) - _sendBitsToDSP(payload[i], 8); - digitalWrite(_CS_PIN, HIGH);//end of packet - - delayMicroseconds(50); - digitalWrite(_CS_PIN, LOW);//start of packet - _sendBitsToDSP(DSP_DIM_BASE+DSP_DIM_ON+brightness, 8); - digitalWrite(_CS_PIN, HIGH);//end of packet - delayMicroseconds(50); - } + //refresh display with ~10Hz + if(millis() -_dspLastRefreshTime > 99){ + _dspLastRefreshTime = millis(); + delayMicroseconds(30); + digitalWrite(_CS_PIN, LOW); //start of packet + _sendBitsToDSP(DSP_CMD1_MODE6_11_7, 8); + digitalWrite(_CS_PIN, HIGH); //end of packet + + delayMicroseconds(50); + digitalWrite(_CS_PIN, LOW);//start of packet + _sendBitsToDSP(DSP_CMD2_DATAWRITE, 8); + digitalWrite(_CS_PIN, HIGH);//end of packet + + //payload + delayMicroseconds(50); + digitalWrite(_CS_PIN, LOW);//start of packet + for (int i = 0; i < 11; i++) + _sendBitsToDSP(payload[i], 8); + digitalWrite(_CS_PIN, HIGH);//end of packet + + delayMicroseconds(50); + digitalWrite(_CS_PIN, LOW);//start of packet + _sendBitsToDSP(DSP_DIM_BASE+DSP_DIM_ON+brightness, 8); + digitalWrite(_CS_PIN, HIGH);//end of packet + delayMicroseconds(50); + } } void DSP::textOut(String txt) { @@ -341,18 +356,18 @@ void DSP::LEDshow() { } void DSP::begin(int dsp_cs_pin, int dsp_data_pin, int dsp_clk_pin, int dsp_audio_pin) { - _CS_PIN = dsp_cs_pin; - _DATA_PIN = dsp_data_pin; - _CLK_PIN = dsp_clk_pin; - _AUDIO_PIN = dsp_audio_pin; - - pinMode(_CS_PIN, OUTPUT); - pinMode(_DATA_PIN, INPUT); - pinMode(_CLK_PIN, OUTPUT); - pinMode(_AUDIO_PIN, OUTPUT); - digitalWrite(_CS_PIN, HIGH); //Active LOW - digitalWrite(_CLK_PIN, HIGH); //shift on falling, latch on rising - digitalWrite(_AUDIO_PIN, LOW); + _CS_PIN = dsp_cs_pin; + _DATA_PIN = dsp_data_pin; + _CLK_PIN = dsp_clk_pin; + _AUDIO_PIN = dsp_audio_pin; + + pinMode(_CS_PIN, OUTPUT); + pinMode(_DATA_PIN, INPUT); + pinMode(_CLK_PIN, OUTPUT); + pinMode(_AUDIO_PIN, OUTPUT); + digitalWrite(_CS_PIN, HIGH); //Active LOW + digitalWrite(_CLK_PIN, HIGH); //shift on falling, latch on rising + digitalWrite(_AUDIO_PIN, LOW); } void DSP::playIntro() { @@ -405,25 +420,25 @@ void DSP::beep2() { BWC::BWC(){} void BWC::begin(void){ - _cio.begin(D1, D7, D2); - _dsp.begin(D3, D5, D4, D6); - begin2(); + _cio.begin(D1, D7, D2); + _dsp.begin(D3, D5, D4, D6); + begin2(); } void BWC::begin( - int cio_cs_pin, - int cio_data_pin, - int cio_clk_pin, - int dsp_cs_pin, - int dsp_data_pin, - int dsp_clk_pin, - int dsp_audio_pin - ) - { - //start CIO and DSP modules - _cio.begin(cio_cs_pin, cio_data_pin, cio_clk_pin); - _dsp.begin(dsp_cs_pin, dsp_data_pin, dsp_clk_pin, dsp_audio_pin); - begin2(); + int cio_cs_pin, + int cio_data_pin, + int cio_clk_pin, + int dsp_cs_pin, + int dsp_data_pin, + int dsp_clk_pin, + int dsp_audio_pin + ) + { + //start CIO and DSP modules + _cio.begin(cio_cs_pin, cio_data_pin, cio_clk_pin); + _dsp.begin(dsp_cs_pin, dsp_data_pin, dsp_clk_pin, dsp_audio_pin); + begin2(); } void BWC::begin2(){ @@ -538,19 +553,19 @@ void BWC::saveDebugInfo(String s){ int BWC::_CodeToButton(uint16_t val){ - for(unsigned int i = 0; i < sizeof(ButtonCodes)/sizeof(uint16_t); i++){ - if(val == ButtonCodes[i]) return i; - } - return 0; + for(unsigned int i = 0; i < sizeof(ButtonCodes)/sizeof(uint16_t); i++){ + if(val == ButtonCodes[i]) return i; + } + return 0; } void BWC::_qButton(uint32_t btn, uint32_t state, uint32_t value, int32_t maxduration) { - if(_qButtonLen == MAXBUTTONS) return; //maybe textout an error message if queue is full? - _buttonQ[_qButtonLen][0] = btn; - _buttonQ[_qButtonLen][1] = state; - _buttonQ[_qButtonLen][2] = value; - _buttonQ[_qButtonLen][3] = maxduration; - _qButtonLen++; + if(_qButtonLen == MAXBUTTONS) return; //maybe textout an error message if queue is full? + _buttonQ[_qButtonLen][0] = btn; + _buttonQ[_qButtonLen][1] = state; + _buttonQ[_qButtonLen][2] = value; + _buttonQ[_qButtonLen][3] = maxduration; + _qButtonLen++; } void BWC::_handleButtonQ(void) { @@ -559,35 +574,41 @@ void BWC::_handleButtonQ(void) { elapsedTime = millis() - prevMillis; prevMillis = millis(); - if(_qButtonLen > 0){ + if(_qButtonLen > 0) + { // First subtract elapsed time from maxduration _buttonQ[0][3] -= elapsedTime; - //check if state is as desired, or duration is up. If so - remove row. Else set BTNCODE - if( (_cio.states[_buttonQ[0][1]] == _buttonQ[0][2]) || (_buttonQ[0][3] <= 0) ){ - if(_buttonQ[0][0] == UP || _buttonQ[0][0] == DOWN) maxeffort = false; - //remove row - for(int i = 0; i < _qButtonLen-1; i++){ - _buttonQ[i][0] = _buttonQ[i+1][0]; - _buttonQ[i][1] = _buttonQ[i+1][1]; - _buttonQ[i][2] = _buttonQ[i+1][2]; - _buttonQ[i][3] = _buttonQ[i+1][3]; - } - _qButtonLen--; - _cio.button = ButtonCodes[NOBTN]; - } else { - if(_buttonQ[0][0] == UP || _buttonQ[0][0] == DOWN) maxeffort = true; - //set buttoncode - _cio.button = ButtonCodes[_buttonQ[0][0]]; - } - } else { + //check if state is as desired, or duration is up. If so - remove row. Else set BTNCODE + if( (_cio.states[_buttonQ[0][1]] == _buttonQ[0][2]) || (_buttonQ[0][3] <= 0) ) + { + if(_buttonQ[0][0] == UP || _buttonQ[0][0] == DOWN) maxeffort = false; + //remove row + for(int i = 0; i < _qButtonLen-1; i++){ + _buttonQ[i][0] = _buttonQ[i+1][0]; + _buttonQ[i][1] = _buttonQ[i+1][1]; + _buttonQ[i][2] = _buttonQ[i+1][2]; + _buttonQ[i][3] = _buttonQ[i+1][3]; + } + _qButtonLen--; + _cio.button = ButtonCodes[NOBTN]; + } + else + { + if(_buttonQ[0][0] == UP || _buttonQ[0][0] == DOWN) maxeffort = true; + //set buttoncode + _cio.button = ButtonCodes[_buttonQ[0][0]]; + } + } + else + { static uint16_t prevbtn = ButtonCodes[NOBTN]; - //no queue so let dsp value through - uint16_t pressedButton = _dsp.getButton(); + //no queue so let dsp value through + uint16_t pressedButton = _dsp.getButton(); int index = _CodeToButton(pressedButton); //if button is not enabled, NOBTN will result (buttoncodes[0]) - _cio.button = ButtonCodes[index * EnabledButtons[index]]; - //prioritize manual temp setting by not competing with the set target command - if (pressedButton == ButtonCodes[UP] || pressedButton == ButtonCodes[DOWN]) _sliderPrio = false; + _cio.button = ButtonCodes[index * EnabledButtons[index]]; + //prioritize manual temp setting by not competing with the set target command + if (pressedButton == ButtonCodes[UP] || pressedButton == ButtonCodes[DOWN]) _sliderPrio = false; //make noise if(_audio) { @@ -597,58 +618,58 @@ void BWC::_handleButtonQ(void) { } } prevbtn = pressedButton; - } + } } bool BWC::qCommand(uint32_t cmd, uint32_t val, uint32_t xtime, uint32_t interval) { - //handle special commands - if(cmd == RESETQ){ - _qButtonLen = 0; - _qCommandLen = 0; - _saveCommandQueue(); - return true; - } - - //add parameters to _commandQ[rows][parameter columns] and sort the array on xtime. - int row = _qCommandLen; - if (_qCommandLen == MAXCOMMANDS) return false; - //sort array on xtime - for (int i = 0; i < _qCommandLen; i++) { - if (xtime < _commandQ[i][2]){ - //insert row at [i] - row = i; - break; - } - } - //make room for new row - for (int i = _qCommandLen; i > (row); i--){ - _commandQ[i][0] = _commandQ[i-1][0]; - _commandQ[i][1] = _commandQ[i-1][1]; - _commandQ[i][2] = _commandQ[i-1][2]; - _commandQ[i][3] = _commandQ[i-1][3]; - } - //add new command - _commandQ[row][0] = cmd; - _commandQ[row][1] = val; - _commandQ[row][2] = xtime; - _commandQ[row][3] = interval; - _qCommandLen++; - delay(0); - _saveCommandQueue(); - return true; + //handle special commands + if(cmd == RESETQ){ + _qButtonLen = 0; + _qCommandLen = 0; + _saveCommandQueue(); + return true; + } + + //add parameters to _commandQ[rows][parameter columns] and sort the array on xtime. + int row = _qCommandLen; + if (_qCommandLen == MAXCOMMANDS) return false; + //sort array on xtime + for (int i = 0; i < _qCommandLen; i++) { + if (xtime < _commandQ[i][2]){ + //insert row at [i] + row = i; + break; + } + } + //make room for new row + for (int i = _qCommandLen; i > (row); i--){ + _commandQ[i][0] = _commandQ[i-1][0]; + _commandQ[i][1] = _commandQ[i-1][1]; + _commandQ[i][2] = _commandQ[i-1][2]; + _commandQ[i][3] = _commandQ[i-1][3]; + } + //add new command + _commandQ[row][0] = cmd; + _commandQ[row][1] = val; + _commandQ[row][2] = xtime; + _commandQ[row][3] = interval; + _qCommandLen++; + delay(0); + _saveCommandQueue(); + return true; } void BWC::_handleCommandQ(void) { - bool restartESP = false; - if(_qCommandLen > 0) { - //cmp time with xtime. If more, then execute (adding buttons to buttonQ). - - if (_timestamp >= _commandQ[0][2]){ - _qButton(POWER, POWERSTATE, 1, 5000); //press POWER button until states[POWERSTATE] is 1, max 5000 ms - _qButton(LOCK, LOCKEDSTATE, 0, 5000); //press LOCK button until states[LOCKEDSTATE] is 0 - switch (_commandQ[0][0]) { - case SETTARGET: + bool restartESP = false; + if(_qCommandLen > 0) { + //cmp time with xtime. If more, then execute (adding buttons to buttonQ). + + if (_timestamp >= _commandQ[0][2]){ + _qButton(POWER, POWERSTATE, 1, 5000); //press POWER button until states[POWERSTATE] is 1, max 5000 ms + _qButton(LOCK, LOCKEDSTATE, 0, 5000); //press LOCK button until states[LOCKEDSTATE] is 0 + switch (_commandQ[0][0]) { + case SETTARGET: { _latestTarget = _commandQ[0][1]; //Fiddling with the hardware buttons is ignored while this command executes. @@ -673,74 +694,75 @@ void BWC::_handleCommandQ(void) { // if(_cio.states[TARGET] < _commandQ[0][1]) _qButton(UP, TARGET, _commandQ[0][1], 10000); break; } - case SETUNIT: - _qButton(UNIT, UNITSTATE, _commandQ[0][1], 5000); - _qButton(NOBTN, CHAR3, 0xFF, 700); - _qButton(UP, CHAR3, _commandQ[0][1], 700); - _latestTarget = 0; - break; - case SETBUBBLES: - _qButton(BUBBLES, BUBBLESSTATE, _commandQ[0][1], 5000); - break; - case SETHEATER: - _qButton(HEAT, HEATSTATE, _commandQ[0][1], 5000); - break; - case SETPUMP: - _qButton(PUMP, PUMPSTATE, _commandQ[0][1], 5000); - break; - case REBOOTESP: - restartESP = true; - break; - case GETTARGET: - _qButton(UP, CHAR3, _commandQ[0][1], 700); - break; - case RESETTIMES: - _uptime = 0; - _pumptime = 0; - _heatingtime = 0; - _airtime = 0; - _uptime_ms = 0; - _pumptime_ms = 0; - _heatingtime_ms = 0; - _airtime_ms = 0; - _cost = 0; - _saveSettingsNeeded = true; + case SETUNIT: + _qButton(UNIT, UNITSTATE, _commandQ[0][1], 5000); + _qButton(NOBTN, CHAR3, 0xFF, 700); + _qButton(UP, CHAR3, _commandQ[0][1], 700); + _latestTarget = 0; //force update + break; + case SETBUBBLES: + _qButton(BUBBLES, BUBBLESSTATE, _commandQ[0][1], 5000); + break; + case SETHEATER: + _qButton(HEAT, HEATSTATE, _commandQ[0][1], 5000); + break; + case SETPUMP: + _qButton(PUMP, PUMPSTATE, _commandQ[0][1], 5000); + break; + case REBOOTESP: + restartESP = true; + break; + case GETTARGET: + _qButton(UP, CHAR3, 32, 500); //ignore desired value and wait for first blink. 32 = ' ' + _qButton(NOBTN, CHAR1, 0xFF, 5000); //block further presses until blinking stops + break; + case RESETTIMES: + _uptime = 0; + _pumptime = 0; + _heatingtime = 0; + _airtime = 0; + _uptime_ms = 0; + _pumptime_ms = 0; + _heatingtime_ms = 0; + _airtime_ms = 0; + _cost = 0; + _saveSettingsNeeded = true; _cio.dataAvailable = true; - break; - case RESETCLTIMER: - _cltime = _timestamp; - _saveSettingsNeeded = true; + break; + case RESETCLTIMER: + _cltime = _timestamp; + _saveSettingsNeeded = true; _cio.dataAvailable = true; - break; - case RESETFTIMER: - _ftime = _timestamp; - _saveSettingsNeeded = true; + break; + case RESETFTIMER: + _ftime = _timestamp; + _saveSettingsNeeded = true; _cio.dataAvailable = true; - break; - case SETJETS: - _qButton(HYDROJETS, JETSSTATE, _commandQ[0][1], 5000); - break; + break; + case SETJETS: + _qButton(HYDROJETS, JETSSTATE, _commandQ[0][1], 5000); + break; case SETBRIGHTNESS: _dspBrightness = _commandQ[0][1] & 7; break; - } - //If interval > 0 then append to commandQ with updated xtime. - if(_commandQ[0][3] > 0) qCommand(_commandQ[0][0],_commandQ[0][1],_commandQ[0][2]+_commandQ[0][3],_commandQ[0][3]); - //remove from commandQ and decrease qCommandLen - for(int i = 0; i < _qCommandLen-1; i++){ - _commandQ[i][0] = _commandQ[i+1][0]; - _commandQ[i][1] = _commandQ[i+1][1]; - _commandQ[i][2] = _commandQ[i+1][2]; - _commandQ[i][3] = _commandQ[i+1][3]; - } - _qCommandLen--; - _saveCommandQueue(); - if(restartESP) { - saveSettings(); - ESP.restart(); - } - } - } + } + //If interval > 0 then append to commandQ with updated xtime. + if(_commandQ[0][3] > 0) qCommand(_commandQ[0][0],_commandQ[0][1],_commandQ[0][2]+_commandQ[0][3],_commandQ[0][3]); + //remove from commandQ and decrease qCommandLen + for(int i = 0; i < _qCommandLen-1; i++){ + _commandQ[i][0] = _commandQ[i+1][0]; + _commandQ[i][1] = _commandQ[i+1][1]; + _commandQ[i][2] = _commandQ[i+1][2]; + _commandQ[i][3] = _commandQ[i+1][3]; + } + _qCommandLen--; + _saveCommandQueue(); + if(restartESP) { + saveSettings(); + ESP.restart(); + } + } + } } @@ -774,8 +796,8 @@ String BWC::getJSONStates() { String jsonmsg; if (serializeJson(doc, jsonmsg) == 0) { jsonmsg = "{\"error\": \"Failed to serialize message\"}"; - } - return jsonmsg; + } + return jsonmsg; } String BWC::getJSONTimes() { @@ -808,8 +830,8 @@ String BWC::getJSONTimes() { String jsonmsg; if (serializeJson(doc, jsonmsg) == 0) { jsonmsg = "{\"error\": \"Failed to serialize message\"}"; - } - return jsonmsg; + } + return jsonmsg; } String BWC::getJSONSettings(){ @@ -835,8 +857,8 @@ String BWC::getJSONSettings(){ String jsonmsg; if (serializeJson(doc, jsonmsg) == 0) { jsonmsg = "{\"error\": \"Failed to serialize message\"}"; - } - return jsonmsg; + } + return jsonmsg; } void BWC::setJSONSettings(String message){ @@ -868,10 +890,10 @@ String BWC::getJSONCommandQueue(){ // Set the values in the document doc["LEN"] = _qCommandLen; for(int i = 0; i < _qCommandLen; i++){ - doc["CMD"][i] = _commandQ[i][0]; - doc["VALUE"][i] = _commandQ[i][1]; - doc["XTIME"][i] = _commandQ[i][2]; - doc["INTERVAL"][i] = _commandQ[i][3]; + doc["CMD"][i] = _commandQ[i][0]; + doc["VALUE"][i] = _commandQ[i][1]; + doc["XTIME"][i] = _commandQ[i][2]; + doc["INTERVAL"][i] = _commandQ[i][3]; } // Serialize JSON to file @@ -883,10 +905,10 @@ String BWC::getJSONCommandQueue(){ } bool BWC::newData(){ - if(maxeffort) return false; + if(maxeffort) return false; bool result = _cio.dataAvailable; - _cio.dataAvailable = false; - if (result && _audio) _dsp.beep(); + _cio.dataAvailable = false; + if (result && _audio) _dsp.beep(); return result; } @@ -940,17 +962,17 @@ void BWC::_loadSettings(){ } void BWC::saveSettingsFlag(){ - //ticker fails if duration is more than 71 min. So we use a counter every 60 minutes - if(++_tickerCount >= 3){ - _saveSettingsNeeded = true; - _tickerCount = 0; - } + //ticker fails if duration is more than 71 min. So we use a counter every 60 minutes + if(++_tickerCount >= 3){ + _saveSettingsNeeded = true; + _tickerCount = 0; + } } void BWC::saveSettings(){ if(maxeffort) { - _saveSettingsNeeded = true; - return; + _saveSettingsNeeded = true; + return; } //kill the dog ESP.wdtDisable(); @@ -962,15 +984,15 @@ void BWC::saveSettings(){ } DynamicJsonDocument doc(1024); - _heatingtime += _heatingtime_ms/1000; - _pumptime += _pumptime_ms/1000; - _airtime += _airtime_ms/1000; - _jettime += _jettime_ms/1000; - _uptime += _uptime_ms/1000; - _heatingtime_ms = 0; - _pumptime_ms = 0; - _airtime_ms = 0; - _uptime_ms = 0; + _heatingtime += _heatingtime_ms/1000; + _pumptime += _pumptime_ms/1000; + _airtime += _airtime_ms/1000; + _jettime += _jettime_ms/1000; + _uptime += _uptime_ms/1000; + _heatingtime_ms = 0; + _pumptime_ms = 0; + _airtime_ms = 0; + _uptime_ms = 0; // Set the values in the document doc["CLTIME"] = _cltime; doc["FTIME"] = _ftime; @@ -1015,10 +1037,10 @@ void BWC::_loadCommandQueue(){ // Set the values in the variables _qCommandLen = doc["LEN"]; for(int i = 0; i < _qCommandLen; i++){ - _commandQ[i][0] = doc["CMD"][i]; - _commandQ[i][1] = doc["VALUE"][i]; - _commandQ[i][2] = doc["XTIME"][i]; - _commandQ[i][3] = doc["INTERVAL"][i]; + _commandQ[i][0] = doc["CMD"][i]; + _commandQ[i][1] = doc["VALUE"][i]; + _commandQ[i][2] = doc["XTIME"][i]; + _commandQ[i][3] = doc["INTERVAL"][i]; } file.close(); @@ -1026,8 +1048,8 @@ void BWC::_loadCommandQueue(){ void BWC::_saveCommandQueue(){ if(maxeffort) { - _saveCmdqNeeded = true; - return; + _saveCmdqNeeded = true; + return; } //kill the dog ESP.wdtDisable(); @@ -1044,10 +1066,10 @@ void BWC::_saveCommandQueue(){ // Set the values in the document doc["LEN"] = _qCommandLen; for(int i = 0; i < _qCommandLen; i++){ - doc["CMD"][i] = _commandQ[i][0]; - doc["VALUE"][i] = _commandQ[i][1]; - doc["XTIME"][i] = _commandQ[i][2]; - doc["INTERVAL"][i] = _commandQ[i][3]; + doc["CMD"][i] = _commandQ[i][0]; + doc["VALUE"][i] = _commandQ[i][1]; + doc["XTIME"][i] = _commandQ[i][2]; + doc["INTERVAL"][i] = _commandQ[i][3]; } // Serialize JSON to file @@ -1061,19 +1083,19 @@ void BWC::_saveCommandQueue(){ } void BWC::reloadCommandQueue(){ - _loadCommandQueue(); - return; + _loadCommandQueue(); + return; } void BWC::reloadSettings(){ - _loadSettings(); - return; + _loadSettings(); + return; } void BWC::_saveStates() { if(maxeffort) { - _saveStatesNeeded = true; - return; + _saveStatesNeeded = true; + return; } //kill the dog ESP.wdtDisable(); @@ -1123,15 +1145,14 @@ void BWC::_restoreStates() { qCommand(SETUNIT, unt, DateTime.now()+10, 0); qCommand(SETPUMP, flt, DateTime.now()+12, 0); qCommand(SETHEATER, htr, DateTime.now()+14, 0); -Serial.println("restoring states"); -Serial.println(DateTime.now()); + Serial.println("restoring states"); file.close(); } void BWC::saveEventlog(){ if(maxeffort) { - _saveEventlogNeeded = true; - return; + _saveEventlogNeeded = true; + return; } _saveEventlogNeeded = false; //kill the dog @@ -1146,7 +1167,7 @@ void BWC::saveEventlog(){ // Set the values in the document for(unsigned int i = 0; i < sizeof(_cio.states); i++){ - doc[i] = _cio.states[i]; + doc[i] = _cio.states[i]; } doc["timestamp"] = DateTime.format(DateFormatter::SIMPLE); @@ -1181,40 +1202,40 @@ void BWC::_saveRebootInfo(){ } void BWC::_updateTimes(){ - uint32_t now = millis(); - static uint32_t prevtime = now; - int elapsedtime = now-prevtime; - - prevtime = now; - if (elapsedtime < 0) return; //millis() rollover every 49 days - if(_cio.states[HEATREDSTATE]){ - _heatingtime_ms += elapsedtime; - } - if(_cio.states[PUMPSTATE]){ - _pumptime_ms += elapsedtime; - } - if(_cio.states[BUBBLESSTATE]){ - _airtime_ms += elapsedtime; - } - if(_cio.states[JETSSTATE]){ - _jettime_ms += elapsedtime; - } - _uptime_ms += elapsedtime; - - if(_uptime_ms > 1000000000){ - _heatingtime += _heatingtime_ms/1000; - _pumptime += _pumptime_ms/1000; - _airtime += _airtime_ms/1000; - _jettime += _jettime_ms/1000; - _uptime += _uptime_ms/1000; - _heatingtime_ms = 0; - _pumptime_ms = 0; - _airtime_ms = 0; - _jettime_ms = 0; - _uptime_ms = 0; - } - - _cost = _price*( + uint32_t now = millis(); + static uint32_t prevtime = now; + int elapsedtime = now-prevtime; + + prevtime = now; + if (elapsedtime < 0) return; //millis() rollover every 49 days + if(_cio.states[HEATREDSTATE]){ + _heatingtime_ms += elapsedtime; + } + if(_cio.states[PUMPSTATE]){ + _pumptime_ms += elapsedtime; + } + if(_cio.states[BUBBLESSTATE]){ + _airtime_ms += elapsedtime; + } + if(_cio.states[JETSSTATE]){ + _jettime_ms += elapsedtime; + } + _uptime_ms += elapsedtime; + + if(_uptime_ms > 1000000000){ + _heatingtime += _heatingtime_ms/1000; + _pumptime += _pumptime_ms/1000; + _airtime += _airtime_ms/1000; + _jettime += _jettime_ms/1000; + _uptime += _uptime_ms/1000; + _heatingtime_ms = 0; + _pumptime_ms = 0; + _airtime_ms = 0; + _jettime_ms = 0; + _uptime_ms = 0; + } + + _cost = _price*( (_heatingtime+_heatingtime_ms/1000)/3600.0 * 1900 + //s -> h ->Wh (_pumptime+_pumptime_ms/1000)/3600.0 * 40 + (_airtime+_airtime_ms/1000)/3600.0 * 800 + @@ -1224,22 +1245,22 @@ void BWC::_updateTimes(){ } void BWC::print(String txt){ - _dsp.textOut(txt); + _dsp.textOut(txt); } uint8_t BWC::getState(int state){ - return _cio.states[state]; + return _cio.states[state]; } String BWC::getPressedButton(){ - uint16_t btn = _dsp.getButton(); - uint8_t hib, lob; - String s; - hib = (uint8_t)(btn>>8); - lob = (uint8_t)(btn & 0xFF); - s = hib < 16 ? "0" + String(hib, HEX) : String(hib, HEX); - s += lob < 16 ? "0" + String(lob, HEX) : String(lob, HEX); - return s; + uint16_t btn = _dsp.getButton(); + uint8_t hib, lob; + String s; + hib = (uint8_t)(btn>>8); + lob = (uint8_t)(btn & 0xFF); + s = hib < 16 ? "0" + String(hib, HEX) : String(hib, HEX); + s += lob < 16 ? "0" + String(lob, HEX) : String(lob, HEX); + return s; } String BWC::getButtonName() { diff --git a/Code/6-wire-version/lib/BWC54149E/BWC54149E_8266.cpp b/Code/6-wire-version/lib/BWC54149E/BWC54149E_8266.cpp index c202c214..6ec02f6b 100644 --- a/Code/6-wire-version/lib/BWC54149E/BWC54149E_8266.cpp +++ b/Code/6-wire-version/lib/BWC54149E/BWC54149E_8266.cpp @@ -5,7 +5,7 @@ CIO *pointerToClass; //set flag instead of saving. This may avoid crashes. Some functions appears to crash when called from a timer. // static void tick(void){ - // pointerToBWC->saveSettingsFlag(); + // pointerToBWC->saveSettingsFlag(); // } static void IRAM_ATTR LEDdatapin(void) { @@ -26,6 +26,21 @@ void CIO::begin(int cio_td_pin, int cio_clk_pin, int cio_ld_pin) { digitalWrite(_CIO_TD_PIN, 1); //idle high attachInterrupt(digitalPinToInterrupt(_CIO_LD_PIN), LEDdatapin, CHANGE); attachInterrupt(digitalPinToInterrupt(_CIO_CLK_PIN), clockpin, CHANGE); //Write on falling edge and read on rising edge + while(!newData) delay(1); //wait for an update from cio + //initialize states + states[LOCKEDSTATE] = (_payload[LCK_IDX] & (1 << LCK_BIT)) > 0; + states[POWERSTATE] = (_payload[PWR_IDX] & (1 << PWR_BIT)) > 0; + states[UNITSTATE] = (_payload[C_IDX] & (1 << C_BIT)) > 0; + states[BUBBLESSTATE] = (_payload[AIR_IDX] & (1 << AIR_BIT)) > 0; + states[HEATGRNSTATE] = (_payload[GRNHTR_IDX] & (1 << GRNHTR_BIT)) > 0; + states[HEATREDSTATE] = (_payload[REDHTR_IDX] & (1 << REDHTR_BIT)) > 0; + states[HEATSTATE] = states[HEATGRNSTATE] || states[HEATREDSTATE]; + states[PUMPSTATE] = (_payload[FLT_IDX] & (1 << FLT_BIT)) > 0; + states[CHAR1] = (uint8_t)_getChar(_payload[DGT1_IDX]); + states[CHAR2] = (uint8_t)_getChar(_payload[DGT2_IDX]); + states[CHAR3] = (uint8_t)_getChar(_payload[DGT3_IDX]); + if(HASJETS) states[JETSSTATE] = (_payload[HJT_IDX] & (1 << HJT_BIT)) > 0; + else states[JETSSTATE] = 0; } void CIO::stop(){ @@ -45,23 +60,23 @@ char CIO::_getChar(uint8_t value) { } void CIO::loop(void) { - //newdata is true when a data packet has arrived from cio - if(newData) { - newData = false; - static int capturePhase = 0; - static uint32_t buttonReleaseTime; - static uint16_t prevButton = ButtonCodes[NOBTN]; + //newdata is true when a data packet has arrived from cio + if(newData) { + newData = false; + static int capturePhase = 0; + static uint32_t buttonReleaseTime; + static uint16_t prevButton = ButtonCodes[NOBTN]; /* * This model is only sending messages when something updated * so this section is not useful */ /* //require two consecutive messages to be equal before registering - static uint8_t prev_checksum = 0; + static uint8_t prev_checksum = 0; uint8_t checksum = 0; for(unsigned int i = 0; i < sizeof(payload); i++){ - checksum += _payload[i]; - } + checksum += _payload[i]; + } if(checksum != prev_checksum) { prev_checksum = checksum; return; @@ -69,49 +84,49 @@ void CIO::loop(void) { prev_checksum = checksum; */ - //copy private array to public array - for(unsigned int i = 0; i < sizeof(payload); i++){ - payload[i] = _payload[i]; - } - - //determine if anything changed, so we can update webclients - for(unsigned int i = 0; i < sizeof(payload); i++){ - if (payload[i] != _prevPayload[i]) dataAvailable = true; - _prevPayload[i] = payload[i]; - } - - //brightness = _brightness & 7; //extract only the brightness bits (0-7) - //extract information from payload to a better format - states[LOCKEDSTATE] = (payload[LCK_IDX] & (1 << LCK_BIT)) > 0; - states[POWERSTATE] = 1; //(payload[PWR_IDX] & (1 << PWR_BIT)) > 0; - states[UNITSTATE] = (payload[C_IDX] & (1 << C_BIT)) > 0; - states[BUBBLESSTATE] = (payload[AIR_IDX] & (1 << AIR_BIT)) > 0; - states[HEATGRNSTATE] = (payload[GRNHTR_IDX] & (1 << GRNHTR_BIT)) > 0; - states[HEATREDSTATE] = (payload[REDHTR_IDX] & (1 << REDHTR_BIT)) > 0; - states[HEATSTATE] = states[HEATGRNSTATE] || states[HEATREDSTATE]; - states[PUMPSTATE] = (payload[FLT_IDX] & (1 << FLT_BIT)) > 0; - states[CHAR1] = (uint8_t)_getChar(payload[DGT1_IDX]); - states[CHAR2] = (uint8_t)_getChar(payload[DGT2_IDX]); - states[CHAR3] = (uint8_t)_getChar(payload[DGT3_IDX]); + //copy private array to public array + for(unsigned int i = 0; i < sizeof(payload); i++){ + payload[i] = _payload[i]; + } + + //determine if anything changed, so we can update webclients + for(unsigned int i = 0; i < sizeof(payload); i++){ + if (payload[i] != _prevPayload[i]) dataAvailable = true; + _prevPayload[i] = payload[i]; + } + + //brightness = _brightness & 7; //extract only the brightness bits (0-7) + //extract information from payload to a better format + states[LOCKEDSTATE] = (payload[LCK_IDX] & (1 << LCK_BIT)) > 0; + states[POWERSTATE] = 1; //(payload[PWR_IDX] & (1 << PWR_BIT)) > 0; + states[UNITSTATE] = (payload[C_IDX] & (1 << C_BIT)) > 0; + states[BUBBLESSTATE] = (payload[AIR_IDX] & (1 << AIR_BIT)) > 0; + states[HEATGRNSTATE] = (payload[GRNHTR_IDX] & (1 << GRNHTR_BIT)) > 0; + states[HEATREDSTATE] = (payload[REDHTR_IDX] & (1 << REDHTR_BIT)) > 0; + states[HEATSTATE] = states[HEATGRNSTATE] || states[HEATREDSTATE]; + states[PUMPSTATE] = (payload[FLT_IDX] & (1 << FLT_BIT)) > 0; + states[CHAR1] = (uint8_t)_getChar(payload[DGT1_IDX]); + states[CHAR2] = (uint8_t)_getChar(payload[DGT2_IDX]); + states[CHAR3] = (uint8_t)_getChar(payload[DGT3_IDX]); if(HASJETS) states[JETSSTATE] = (payload[HJT_IDX] & (1 << HJT_BIT)) > 0; else states[JETSSTATE] = 0; - //Determine if display is showing target temp or actual temp or anything else. - //capture TARGET after UP/DOWN has been pressed... - if( ((button == ButtonCodes[UP]) || (button == ButtonCodes[DOWN])) && (prevButton != ButtonCodes[UP]) && (prevButton != ButtonCodes[DOWN]) ) capturePhase = 1; - //...until 2 seconds after UP/DOWN released - if( (button == ButtonCodes[UP]) || (button == ButtonCodes[DOWN]) ) buttonReleaseTime = millis(); - if(millis()-buttonReleaseTime > 2000) capturePhase = 0; - //convert text on display to a value if the chars are recognized + //Determine if display is showing target temp or actual temp or anything else. + //capture TARGET after UP/DOWN has been pressed... + if( ((button == ButtonCodes[UP]) || (button == ButtonCodes[DOWN])) && (prevButton != ButtonCodes[UP]) && (prevButton != ButtonCodes[DOWN]) ) capturePhase = 1; + //...until 2 seconds after UP/DOWN released + if( (button == ButtonCodes[UP]) || (button == ButtonCodes[DOWN]) ) buttonReleaseTime = millis(); + if(millis()-buttonReleaseTime > 2000) capturePhase = 0; + //convert text on display to a value if the chars are recognized if(states[CHAR1] == '*' || states[CHAR2] == '*' || states[CHAR3] == '*') return; - String tempstring = String((char)states[CHAR1])+String((char)states[CHAR2])+String((char)states[CHAR3]); - uint8_t tmpTemp = tempstring.toInt(); - //capture only if showing plausible values (not blank screen while blinking) - if( (capturePhase == 1) && (tmpTemp > 19) ) { - states[TARGET] = tmpTemp; - } - //wait 4 seconds after UP/DOWN is released to be sure that actual temp is shown - if( (capturePhase == 0) && (millis()-buttonReleaseTime > 10000) && payload[DGT3_IDX]!=0xED && payload[DGT3_IDX]!=0) states[TEMPERATURE] = tmpTemp; - prevButton = button; + String tempstring = String((char)states[CHAR1])+String((char)states[CHAR2])+String((char)states[CHAR3]); + uint8_t tmpTemp = tempstring.toInt(); + //capture only if showing plausible values (not blank screen while blinking) + if( (capturePhase == 1) && (tmpTemp > 19) ) { + states[TARGET] = tmpTemp; + } + //wait 4 seconds after UP/DOWN is released to be sure that actual temp is shown + if( (capturePhase == 0) && (millis()-buttonReleaseTime > 10000) && payload[DGT3_IDX]!=0xED && payload[DGT3_IDX]!=0) states[TEMPERATURE] = tmpTemp; + prevButton = button; if(states[UNITSTATE] != _prevUNT || states[HEATSTATE] != _prevHTR || states[PUMPSTATE] != _prevFLT) { stateChanged = true; @@ -119,7 +134,7 @@ void CIO::loop(void) { _prevHTR = states[HEATSTATE]; _prevFLT = states[PUMPSTATE]; } - } + } } //CIO comm @@ -169,8 +184,8 @@ void IRAM_ATTR CIO::clkHandler(void) { uint16_t DSP::getButton(void) { if(millis() - _dspLastGetButton > 20){ - uint16_t newButton = 0; - _dspLastGetButton = millis(); + uint16_t newButton = 0; + _dspLastGetButton = millis(); //startbit digitalWrite(_DSP_CLK_PIN, LOW); delayMicroseconds(CLKPW); @@ -225,48 +240,48 @@ char DSP::_getCode(char value) { } void DSP::updateDSP(uint8_t brightness) { - //refresh display with ~10Hz - if(millis() -_dspLastRefreshTime > 99){ - _dspLastRefreshTime = millis(); - digitalWrite(_DSP_LD_PIN, LOW); //start of packet + //refresh display with ~10Hz + if(millis() -_dspLastRefreshTime > 99){ + _dspLastRefreshTime = millis(); + digitalWrite(_DSP_LD_PIN, LOW); //start of packet delayMicroseconds(CLKPW); - _sendBitsToDSP(CMD1, 8); + _sendBitsToDSP(CMD1, 8); //end of packet: clock low, make sure LD is low before rising clock then LD digitalWrite(_DSP_CLK_PIN, LOW); - digitalWrite(_DSP_LD_PIN, LOW); + digitalWrite(_DSP_LD_PIN, LOW); delayMicroseconds(CLKPW); digitalWrite(_DSP_CLK_PIN, HIGH); delayMicroseconds(CLKPW); - digitalWrite(_DSP_LD_PIN, HIGH); + digitalWrite(_DSP_LD_PIN, HIGH); delayMicroseconds(CLKPW); - digitalWrite(_DSP_LD_PIN, LOW); //start of packet + digitalWrite(_DSP_LD_PIN, LOW); //start of packet delayMicroseconds(CLKPW); - _sendBitsToDSP(CMD2, 8); + _sendBitsToDSP(CMD2, 8); for(unsigned int i=0; i 0){ + if(_qButtonLen > 0){ // First subtract elapsed time from maxduration _buttonQ[0][3] -= elapsedTime; - //check if state is as desired, or duration is up. If so - remove row. Else set BTNCODE - if( (_cio.states[_buttonQ[0][1]] == _buttonQ[0][2]) || (_buttonQ[0][3] <= 0) ){ - if(_buttonQ[0][0] == UP || _buttonQ[0][0] == DOWN) maxeffort = false; - //remove row - for(int i = 0; i < _qButtonLen-1; i++){ - _buttonQ[i][0] = _buttonQ[i+1][0]; - _buttonQ[i][1] = _buttonQ[i+1][1]; - _buttonQ[i][2] = _buttonQ[i+1][2]; - _buttonQ[i][3] = _buttonQ[i+1][3]; - } - _qButtonLen--; - _cio.button = ButtonCodes[NOBTN]; - } else { - if(_buttonQ[0][0] == UP || _buttonQ[0][0] == DOWN) maxeffort = true; - //set buttoncode - _cio.button = ButtonCodes[_buttonQ[0][0]]; - } - } else { + //check if state is as desired, or duration is up. If so - remove row. Else set BTNCODE + if( (_cio.states[_buttonQ[0][1]] == _buttonQ[0][2]) || (_buttonQ[0][3] <= 0) ){ + if(_buttonQ[0][0] == UP || _buttonQ[0][0] == DOWN) maxeffort = false; + //remove row + for(int i = 0; i < _qButtonLen-1; i++){ + _buttonQ[i][0] = _buttonQ[i+1][0]; + _buttonQ[i][1] = _buttonQ[i+1][1]; + _buttonQ[i][2] = _buttonQ[i+1][2]; + _buttonQ[i][3] = _buttonQ[i+1][3]; + } + _qButtonLen--; + _cio.button = ButtonCodes[NOBTN]; + } else { + if(_buttonQ[0][0] == UP || _buttonQ[0][0] == DOWN) maxeffort = true; + //set buttoncode + _cio.button = ButtonCodes[_buttonQ[0][0]]; + } + } else { static uint16_t prevbtn = ButtonCodes[NOBTN]; - //no queue so let dsp value through - uint16_t pressedButton = _dsp.getButton(); + //no queue so let dsp value through + uint16_t pressedButton = _dsp.getButton(); int index = _CodeToButton(pressedButton); //if button is not enabled, NOBTN will result (buttoncodes[0]) - _cio.button = ButtonCodes[index * EnabledButtons[index]]; - //prioritize manual temp setting by not competing with the set target command - if (pressedButton == ButtonCodes[UP] || pressedButton == ButtonCodes[DOWN]) _sliderPrio = false; + _cio.button = ButtonCodes[index * EnabledButtons[index]]; + //prioritize manual temp setting by not competing with the set target command + if (pressedButton == ButtonCodes[UP] || pressedButton == ButtonCodes[DOWN]) _sliderPrio = false; //make noise if(_audio) { @@ -566,58 +581,58 @@ void BWC::_handleButtonQ(void) { } } prevbtn = pressedButton; - } + } } bool BWC::qCommand(uint32_t cmd, uint32_t val, uint32_t xtime, uint32_t interval) { - //handle special commands - if(cmd == RESETQ){ - _qButtonLen = 0; - _qCommandLen = 0; - _saveCommandQueue(); - return true; - } - - //add parameters to _commandQ[rows][parameter columns] and sort the array on xtime. - int row = _qCommandLen; - if (_qCommandLen == MAXCOMMANDS) return false; - //sort array on xtime - for (int i = 0; i < _qCommandLen; i++) { - if (xtime < _commandQ[i][2]){ - //insert row at [i] - row = i; - break; - } - } - //make room for new row - for (int i = _qCommandLen; i > (row); i--){ - _commandQ[i][0] = _commandQ[i-1][0]; - _commandQ[i][1] = _commandQ[i-1][1]; - _commandQ[i][2] = _commandQ[i-1][2]; - _commandQ[i][3] = _commandQ[i-1][3]; - } - //add new command - _commandQ[row][0] = cmd; - _commandQ[row][1] = val; - _commandQ[row][2] = xtime; - _commandQ[row][3] = interval; - _qCommandLen++; - delay(0); - _saveCommandQueue(); - return true; + //handle special commands + if(cmd == RESETQ){ + _qButtonLen = 0; + _qCommandLen = 0; + _saveCommandQueue(); + return true; + } + + //add parameters to _commandQ[rows][parameter columns] and sort the array on xtime. + int row = _qCommandLen; + if (_qCommandLen == MAXCOMMANDS) return false; + //sort array on xtime + for (int i = 0; i < _qCommandLen; i++) { + if (xtime < _commandQ[i][2]){ + //insert row at [i] + row = i; + break; + } + } + //make room for new row + for (int i = _qCommandLen; i > (row); i--){ + _commandQ[i][0] = _commandQ[i-1][0]; + _commandQ[i][1] = _commandQ[i-1][1]; + _commandQ[i][2] = _commandQ[i-1][2]; + _commandQ[i][3] = _commandQ[i-1][3]; + } + //add new command + _commandQ[row][0] = cmd; + _commandQ[row][1] = val; + _commandQ[row][2] = xtime; + _commandQ[row][3] = interval; + _qCommandLen++; + delay(0); + _saveCommandQueue(); + return true; } void BWC::_handleCommandQ(void) { - bool restartESP = false; - if(_qCommandLen > 0) { - //cmp time with xtime. If more, then execute (adding buttons to buttonQ). - - if (_timestamp >= _commandQ[0][2]){ - _qButton(POWER, POWERSTATE, 1, 5000); //press POWER button until states[POWERSTATE] is 1, max 5000 ms - _qButton(LOCK, LOCKEDSTATE, 0, 5000); //press LOCK button until states[LOCKEDSTATE] is 0 - switch (_commandQ[0][0]) { - case SETTARGET: + bool restartESP = false; + if(_qCommandLen > 0) { + //cmp time with xtime. If more, then execute (adding buttons to buttonQ). + + if (_timestamp >= _commandQ[0][2]){ + _qButton(POWER, POWERSTATE, 1, 5000); //press POWER button until states[POWERSTATE] is 1, max 5000 ms + _qButton(LOCK, LOCKEDSTATE, 0, 5000); //press LOCK button until states[LOCKEDSTATE] is 0 + switch (_commandQ[0][0]) { + case SETTARGET: { _latestTarget = _commandQ[0][1]; //Fiddling with the hardware buttons is ignored while this command executes. @@ -642,74 +657,75 @@ void BWC::_handleCommandQ(void) { // if(_cio.states[TARGET] < _commandQ[0][1]) _qButton(UP, TARGET, _commandQ[0][1], 10000); break; } - case SETUNIT: - _qButton(UNIT, UNITSTATE, _commandQ[0][1], 5000); - _qButton(NOBTN, CHAR3, 0xFF, 700); - _qButton(UP, CHAR3, _commandQ[0][1], 700); - _latestTarget = 0; - break; - case SETBUBBLES: - _qButton(BUBBLES, BUBBLESSTATE, _commandQ[0][1], 5000); - break; - case SETHEATER: - _qButton(HEAT, HEATSTATE, _commandQ[0][1], 5000); - break; - case SETPUMP: - _qButton(PUMP, PUMPSTATE, _commandQ[0][1], 5000); - break; - case REBOOTESP: - restartESP = true; - break; - case GETTARGET: - _qButton(UP, CHAR3, _commandQ[0][1], 700); - break; - case RESETTIMES: - _uptime = 0; - _pumptime = 0; - _heatingtime = 0; - _airtime = 0; - _uptime_ms = 0; - _pumptime_ms = 0; - _heatingtime_ms = 0; - _airtime_ms = 0; - _cost = 0; - _saveSettingsNeeded = true; + case SETUNIT: + _qButton(UNIT, UNITSTATE, _commandQ[0][1], 5000); + _qButton(NOBTN, CHAR3, 0xFF, 700); + _qButton(UP, CHAR3, _commandQ[0][1], 700); + _latestTarget = 0; //force update + break; + case SETBUBBLES: + _qButton(BUBBLES, BUBBLESSTATE, _commandQ[0][1], 5000); + break; + case SETHEATER: + _qButton(HEAT, HEATSTATE, _commandQ[0][1], 5000); + break; + case SETPUMP: + _qButton(PUMP, PUMPSTATE, _commandQ[0][1], 5000); + break; + case REBOOTESP: + restartESP = true; + break; + case GETTARGET: + _qButton(UP, CHAR3, 32, 500); //ignore desired value and wait for first blink. 32 = ' ' + _qButton(NOBTN, CHAR1, 0xFF, 5000); //block further presses until blinking stops + break; + case RESETTIMES: + _uptime = 0; + _pumptime = 0; + _heatingtime = 0; + _airtime = 0; + _uptime_ms = 0; + _pumptime_ms = 0; + _heatingtime_ms = 0; + _airtime_ms = 0; + _cost = 0; + _saveSettingsNeeded = true; _cio.dataAvailable = true; - break; - case RESETCLTIMER: - _cltime = _timestamp; - _saveSettingsNeeded = true; + break; + case RESETCLTIMER: + _cltime = _timestamp; + _saveSettingsNeeded = true; _cio.dataAvailable = true; - break; - case RESETFTIMER: - _ftime = _timestamp; - _saveSettingsNeeded = true; + break; + case RESETFTIMER: + _ftime = _timestamp; + _saveSettingsNeeded = true; _cio.dataAvailable = true; - break; - case SETJETS: - _qButton(HYDROJETS, JETSSTATE, _commandQ[0][1], 5000); - break; + break; + case SETJETS: + _qButton(HYDROJETS, JETSSTATE, _commandQ[0][1], 5000); + break; case SETBRIGHTNESS: _dspBrightness = _commandQ[0][1] & 7; break; - } - //If interval > 0 then append to commandQ with updated xtime. - if(_commandQ[0][3] > 0) qCommand(_commandQ[0][0],_commandQ[0][1],_commandQ[0][2]+_commandQ[0][3],_commandQ[0][3]); - //remove from commandQ and decrease qCommandLen - for(int i = 0; i < _qCommandLen-1; i++){ - _commandQ[i][0] = _commandQ[i+1][0]; - _commandQ[i][1] = _commandQ[i+1][1]; - _commandQ[i][2] = _commandQ[i+1][2]; - _commandQ[i][3] = _commandQ[i+1][3]; - } - _qCommandLen--; - _saveCommandQueue(); - if(restartESP) { - saveSettings(); - ESP.restart(); - } - } - } + } + //If interval > 0 then append to commandQ with updated xtime. + if(_commandQ[0][3] > 0) qCommand(_commandQ[0][0],_commandQ[0][1],_commandQ[0][2]+_commandQ[0][3],_commandQ[0][3]); + //remove from commandQ and decrease qCommandLen + for(int i = 0; i < _qCommandLen-1; i++){ + _commandQ[i][0] = _commandQ[i+1][0]; + _commandQ[i][1] = _commandQ[i+1][1]; + _commandQ[i][2] = _commandQ[i+1][2]; + _commandQ[i][3] = _commandQ[i+1][3]; + } + _qCommandLen--; + _saveCommandQueue(); + if(restartESP) { + saveSettings(); + ESP.restart(); + } + } + } } @@ -743,8 +759,8 @@ String BWC::getJSONStates() { String jsonmsg; if (serializeJson(doc, jsonmsg) == 0) { jsonmsg = "{\"error\": \"Failed to serialize message\"}"; - } - return jsonmsg; + } + return jsonmsg; } String BWC::getJSONTimes() { @@ -775,8 +791,8 @@ String BWC::getJSONTimes() { String jsonmsg; if (serializeJson(doc, jsonmsg) == 0) { jsonmsg = "{\"error\": \"Failed to serialize message\"}"; - } - return jsonmsg; + } + return jsonmsg; } String BWC::getJSONSettings(){ @@ -802,8 +818,8 @@ String BWC::getJSONSettings(){ String jsonmsg; if (serializeJson(doc, jsonmsg) == 0) { jsonmsg = "{\"error\": \"Failed to serialize message\"}"; - } - return jsonmsg; + } + return jsonmsg; } void BWC::setJSONSettings(String message){ @@ -835,10 +851,10 @@ String BWC::getJSONCommandQueue(){ // Set the values in the document doc["LEN"] = _qCommandLen; for(int i = 0; i < _qCommandLen; i++){ - doc["CMD"][i] = _commandQ[i][0]; - doc["VALUE"][i] = _commandQ[i][1]; - doc["XTIME"][i] = _commandQ[i][2]; - doc["INTERVAL"][i] = _commandQ[i][3]; + doc["CMD"][i] = _commandQ[i][0]; + doc["VALUE"][i] = _commandQ[i][1]; + doc["XTIME"][i] = _commandQ[i][2]; + doc["INTERVAL"][i] = _commandQ[i][3]; } // Serialize JSON to file @@ -850,10 +866,10 @@ String BWC::getJSONCommandQueue(){ } bool BWC::newData(){ - if(maxeffort) return false; + if(maxeffort) return false; bool result = _cio.dataAvailable; - _cio.dataAvailable = false; - if (result && _audio) _dsp.beep(); + _cio.dataAvailable = false; + if (result && _audio) _dsp.beep(); return result; } @@ -907,17 +923,17 @@ void BWC::_loadSettings(){ } void BWC::saveSettingsFlag(){ - //ticker fails if duration is more than 71 min. So we use a counter every 60 minutes - if(++_tickerCount >= 3){ - _saveSettingsNeeded = true; - _tickerCount = 0; - } + //ticker fails if duration is more than 71 min. So we use a counter every 60 minutes + if(++_tickerCount >= 3){ + _saveSettingsNeeded = true; + _tickerCount = 0; + } } void BWC::saveSettings(){ if(maxeffort) { - _saveSettingsNeeded = true; - return; + _saveSettingsNeeded = true; + return; } //kill the dog ESP.wdtDisable(); @@ -929,15 +945,15 @@ void BWC::saveSettings(){ } DynamicJsonDocument doc(1024); - _heatingtime += _heatingtime_ms/1000; - _pumptime += _pumptime_ms/1000; - _airtime += _airtime_ms/1000; - _jettime += _jettime_ms/1000; - _uptime += _uptime_ms/1000; - _heatingtime_ms = 0; - _pumptime_ms = 0; - _airtime_ms = 0; - _uptime_ms = 0; + _heatingtime += _heatingtime_ms/1000; + _pumptime += _pumptime_ms/1000; + _airtime += _airtime_ms/1000; + _jettime += _jettime_ms/1000; + _uptime += _uptime_ms/1000; + _heatingtime_ms = 0; + _pumptime_ms = 0; + _airtime_ms = 0; + _uptime_ms = 0; // Set the values in the document doc["CLTIME"] = _cltime; doc["FTIME"] = _ftime; @@ -984,10 +1000,10 @@ void BWC::_loadCommandQueue(){ // Set the values in the variables _qCommandLen = doc["LEN"]; for(int i = 0; i < _qCommandLen; i++){ - _commandQ[i][0] = doc["CMD"][i]; - _commandQ[i][1] = doc["VALUE"][i]; - _commandQ[i][2] = doc["XTIME"][i]; - _commandQ[i][3] = doc["INTERVAL"][i]; + _commandQ[i][0] = doc["CMD"][i]; + _commandQ[i][1] = doc["VALUE"][i]; + _commandQ[i][2] = doc["XTIME"][i]; + _commandQ[i][3] = doc["INTERVAL"][i]; } file.close(); @@ -995,8 +1011,8 @@ void BWC::_loadCommandQueue(){ void BWC::_saveCommandQueue(){ if(maxeffort) { - _saveCmdqNeeded = true; - return; + _saveCmdqNeeded = true; + return; } //kill the dog ESP.wdtDisable(); @@ -1013,10 +1029,10 @@ void BWC::_saveCommandQueue(){ // Set the values in the document doc["LEN"] = _qCommandLen; for(int i = 0; i < _qCommandLen; i++){ - doc["CMD"][i] = _commandQ[i][0]; - doc["VALUE"][i] = _commandQ[i][1]; - doc["XTIME"][i] = _commandQ[i][2]; - doc["INTERVAL"][i] = _commandQ[i][3]; + doc["CMD"][i] = _commandQ[i][0]; + doc["VALUE"][i] = _commandQ[i][1]; + doc["XTIME"][i] = _commandQ[i][2]; + doc["INTERVAL"][i] = _commandQ[i][3]; } // Serialize JSON to file @@ -1030,19 +1046,19 @@ void BWC::_saveCommandQueue(){ } void BWC::reloadCommandQueue(){ - _loadCommandQueue(); - return; + _loadCommandQueue(); + return; } void BWC::reloadSettings(){ - _loadSettings(); - return; + _loadSettings(); + return; } void BWC::_saveStates() { if(maxeffort) { - _saveStatesNeeded = true; - return; + _saveStatesNeeded = true; + return; } //kill the dog ESP.wdtDisable(); @@ -1098,8 +1114,8 @@ void BWC::_restoreStates() { void BWC::saveEventlog(){ if(maxeffort) { - _saveEventlogNeeded = true; - return; + _saveEventlogNeeded = true; + return; } _saveEventlogNeeded = false; //kill the dog @@ -1114,7 +1130,7 @@ void BWC::saveEventlog(){ // Set the values in the document for(unsigned int i = 0; i < sizeof(_cio.states); i++){ - doc[i] = _cio.states[i]; + doc[i] = _cio.states[i]; } doc["timestamp"] = DateTime.format(DateFormatter::SIMPLE); @@ -1149,40 +1165,40 @@ void BWC::_saveRebootInfo(){ } void BWC::_updateTimes(){ - uint32_t now = millis(); - static uint32_t prevtime = now; - int elapsedtime = now-prevtime; - - prevtime = now; - if (elapsedtime < 0) return; //millis() rollover every 49 days - if(_cio.states[HEATREDSTATE]){ - _heatingtime_ms += elapsedtime; - } - if(_cio.states[PUMPSTATE]){ - _pumptime_ms += elapsedtime; - } - if(_cio.states[BUBBLESSTATE]){ - _airtime_ms += elapsedtime; - } - if(_cio.states[JETSSTATE]){ - _jettime_ms += elapsedtime; - } - _uptime_ms += elapsedtime; - - if(_uptime_ms > 1000000000){ - _heatingtime += _heatingtime_ms/1000; - _pumptime += _pumptime_ms/1000; - _airtime += _airtime_ms/1000; - _jettime += _jettime_ms/1000; - _uptime += _uptime_ms/1000; - _heatingtime_ms = 0; - _pumptime_ms = 0; - _airtime_ms = 0; - _jettime_ms = 0; - _uptime_ms = 0; - } - - _cost = _price*( + uint32_t now = millis(); + static uint32_t prevtime = now; + int elapsedtime = now-prevtime; + + prevtime = now; + if (elapsedtime < 0) return; //millis() rollover every 49 days + if(_cio.states[HEATREDSTATE]){ + _heatingtime_ms += elapsedtime; + } + if(_cio.states[PUMPSTATE]){ + _pumptime_ms += elapsedtime; + } + if(_cio.states[BUBBLESSTATE]){ + _airtime_ms += elapsedtime; + } + if(_cio.states[JETSSTATE]){ + _jettime_ms += elapsedtime; + } + _uptime_ms += elapsedtime; + + if(_uptime_ms > 1000000000){ + _heatingtime += _heatingtime_ms/1000; + _pumptime += _pumptime_ms/1000; + _airtime += _airtime_ms/1000; + _jettime += _jettime_ms/1000; + _uptime += _uptime_ms/1000; + _heatingtime_ms = 0; + _pumptime_ms = 0; + _airtime_ms = 0; + _jettime_ms = 0; + _uptime_ms = 0; + } + + _cost = _price*( (_heatingtime+_heatingtime_ms/1000)/3600.0 * 1900 + //s -> h ->Wh (_pumptime+_pumptime_ms/1000)/3600.0 * 40 + (_airtime+_airtime_ms/1000)/3600.0 * 800 + @@ -1192,22 +1208,22 @@ void BWC::_updateTimes(){ } void BWC::print(String txt){ - _dsp.textOut(txt); + _dsp.textOut(txt); } uint8_t BWC::getState(int state){ - return _cio.states[state]; + return _cio.states[state]; } String BWC::getPressedButton(){ - uint16_t btn = _dsp.getButton(); - uint8_t hib, lob; - String s; - hib = (uint8_t)(btn>>8); - lob = (uint8_t)(btn & 0xFF); - s = hib < 16 ? "0" + String(hib, HEX) : String(hib, HEX); - s += lob < 16 ? "0" + String(lob, HEX) : String(lob, HEX); - return s; + uint16_t btn = _dsp.getButton(); + uint8_t hib, lob; + String s; + hib = (uint8_t)(btn>>8); + lob = (uint8_t)(btn & 0xFF); + s = hib < 16 ? "0" + String(hib, HEX) : String(hib, HEX); + s += lob < 16 ? "0" + String(lob, HEX) : String(lob, HEX); + return s; } String BWC::getButtonName() { From 414ce007ba81aaaf2237422de7786a32532708ff Mon Sep 17 00:00:00 2001 From: visualapproach Date: Sat, 26 Mar 2022 12:02:09 +0100 Subject: [PATCH 10/10] fw version update --- Code/6-wire-version/src/config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/6-wire-version/src/config.h b/Code/6-wire-version/src/config.h index 2e402cf3..2544391e 100644 --- a/Code/6-wire-version/src/config.h +++ b/Code/6-wire-version/src/config.h @@ -2,7 +2,7 @@ #include #define DEVICE_NAME "layzspa" -#define FW_VERSION "2022-03-25" +#define FW_VERSION "2022-03-26" #define HA_PREFIX "homeassistant" /*