From 7ea6bd00dd93b45aff8ef44b0da1830ee1ea3d77 Mon Sep 17 00:00:00 2001 From: Thomas Popp Date: Wed, 12 Jun 2024 16:21:58 +0200 Subject: [PATCH] feat(pv-overrides): show solar and pv icons on hmi controller --- AquaMQTT/include/message/MainStatusMessage.h | 10 +- AquaMQTT/include/mqtt/MQTTDefinitions.h | 2 + AquaMQTT/include/state/MainStateProxy.h | 73 ++++++++ AquaMQTT/src/message/MainStatusMessage.cpp | 38 ++++- AquaMQTT/src/state/MainStateProxy.cpp | 170 +++++++++++++++++++ AquaMQTT/src/task/HMITask.cpp | 9 +- AquaMQTT/src/task/MQTTTask.cpp | 43 ++++- MQTT.md | 32 ++-- PROTOCOL.md | 2 +- README-PV.md | 17 +- 10 files changed, 357 insertions(+), 39 deletions(-) create mode 100644 AquaMQTT/include/state/MainStateProxy.h create mode 100644 AquaMQTT/src/state/MainStateProxy.cpp diff --git a/AquaMQTT/include/message/MainStatusMessage.h b/AquaMQTT/include/message/MainStatusMessage.h index c78a31a..6bc651a 100644 --- a/AquaMQTT/include/message/MainStatusMessage.h +++ b/AquaMQTT/include/message/MainStatusMessage.h @@ -39,6 +39,12 @@ class MainStatusMessage bool statePV(); + void enableStatePV(bool enabled); + + bool stateSolar(); + + void enableStateSolar(bool enabled); + uint8_t settingPwmFirst(); uint8_t settingPwmSecond(); @@ -79,7 +85,7 @@ class MainStatusMessage bool statesChanged() const; - bool statePVChanged() const; + bool statePVOrSolarChanged() const; uint8_t errorCode() const; @@ -120,7 +126,7 @@ class MainStatusMessage bool mSettingBoilerCapacityChanged; bool mSettingBoilerBrandChanged; bool mSettingCapabilitiesChanged; - bool mPVStateChanged; + bool mPVOrSolarStateChanged; bool mErrorCodeChanged; }; diff --git a/AquaMQTT/include/mqtt/MQTTDefinitions.h b/AquaMQTT/include/mqtt/MQTTDefinitions.h index 00f22b4..60105bb 100644 --- a/AquaMQTT/include/mqtt/MQTTDefinitions.h +++ b/AquaMQTT/include/mqtt/MQTTDefinitions.h @@ -82,6 +82,7 @@ const char MAIN_STATE_HEAT_ELEMENT[] PROGMEM = { "stateElement" }; const char MAIN_STATE_EXT_BOILER[] PROGMEM = { "stateExtBoiler" }; const char MAIN_STATE_DEFROST[] PROGMEM = { "stateDefrost" }; const char MAIN_STATE_PV[] PROGMEM = { "statePV" }; +const char MAIN_STATE_SOLAR[] PROGMEM = { "stateSolar" }; const char MAIN_SETTING_PWM_01[] PROGMEM = { "settingPWM_1" }; const char MAIN_SETTING_PWM_02[] PROGMEM = { "settingPWM_2" }; @@ -135,6 +136,7 @@ const char STATS_MSG_SENT[] PROGMEM = { "msgSent" }; const char STATS_MSG_CRC_NOK[] PROGMEM = { "msgCRCNOK" }; const char STATS_DROPPED_BYTES[] PROGMEM = { "droppedBytes" }; const char STATS_ACTIVE_OVERRIDES[] PROGMEM = { "activeOverrides" }; +const char STATS_ACTIVE_OVERRIDES_MAIN[] PROGMEM = { "activeOverridesMain" }; const char STATS_ENABLE_FLAG_PV_HEATPUMP[] PROGMEM = { "flagPVModeHeatPump" }; const char STATS_ENABLE_FLAG_PV_HEATELEMENT[] PROGMEM = { "flagPVModeHeatElement" }; diff --git a/AquaMQTT/include/state/MainStateProxy.h b/AquaMQTT/include/state/MainStateProxy.h new file mode 100644 index 0000000..935e2ec --- /dev/null +++ b/AquaMQTT/include/state/MainStateProxy.h @@ -0,0 +1,73 @@ +#ifndef AQUAMQTT_MAINSTATEPROXY_H +#define AQUAMQTT_MAINSTATEPROXY_H + +#include "message/MainStatusMessage.h" +#include "mqtt/IMQTTCallback.h" +#include "state/DHWState.h" + +namespace aquamqtt +{ + +struct AquaMqttMainOverrides +{ + bool pvState; + bool solarState; +}; + +/** + * MainStateProxy accesses messages emitted by the main controller through DHW + * state and applies overrides for customizing the HMI + */ + +class MainStateProxy : public mqtt::IMQTTCallback +{ +public: + static MainStateProxy& getInstance(); + + virtual ~MainStateProxy() = default; + + MainStateProxy(const MainStateProxy&) = delete; + +private: + MainStateProxy(); + +public: + MainStateProxy& operator=(const MainStateProxy&) = delete; + + void setListener(TaskHandle_t handle); + + void applyMainOverrides(uint8_t* buffer); + + bool copyFrame(uint8_t frameId, uint8_t* buffer); + + void onOperationModeChanged(std::unique_ptr value) override; + + void onOperationTypeChanged(std::unique_ptr type) override; + + void onInstallationModeChanged(std::unique_ptr mode) override; + + void onWaterTempTargetChanged(std::unique_ptr value) override; + + void onHeatingElementEnabledChanged(std::unique_ptr enabled) override; + + void onEmergencyModeEnabledChanged(std::unique_ptr enabled) override; + + void onPVModeHeatpumpEnabled(bool enabled) override; + + void onPVModeHeatElementEnabled(bool enabled) override; + + void onResetOverrides() override; + + AquaMqttMainOverrides getOverrides(); + +private: + TaskHandle_t mNotify; + SemaphoreHandle_t mMutex; + + bool mPVModeHeatPump; + bool mPVModeHeatElement; +}; + +} // namespace aquamqtt + +#endif // AQUAMQTT_MAINSTATEPROXY_H diff --git a/AquaMQTT/src/message/MainStatusMessage.cpp b/AquaMQTT/src/message/MainStatusMessage.cpp index f7570e9..287618c 100644 --- a/AquaMQTT/src/message/MainStatusMessage.cpp +++ b/AquaMQTT/src/message/MainStatusMessage.cpp @@ -49,6 +49,11 @@ bool MainStatusMessage::stateDefrost() } bool MainStatusMessage::statePV() +{ + return mData[22] & 0x10; +} + +bool MainStatusMessage::stateSolar() { return mData[22] & 0x20; } @@ -137,7 +142,7 @@ void MainStatusMessage::compareWith(uint8_t* data) mSettingBoilerCapacityChanged = true; mSettingBoilerBrandChanged = true; mSettingCapabilitiesChanged = true; - mPVStateChanged = true; + mPVOrSolarStateChanged = true; mErrorCodeChanged = true; return; } @@ -191,7 +196,7 @@ void MainStatusMessage::compareWith(uint8_t* data) mSettingAntiLegionellaTargetChanged = true; break; case 22: - mPVStateChanged = true; + mPVOrSolarStateChanged = true; break; case 23: mErrorCodeChanged = true; @@ -231,7 +236,7 @@ MainStatusMessage::MainStatusMessage(uint8_t* data) , mSettingBoilerCapacityChanged(false) , mSettingBoilerBrandChanged(false) , mSettingCapabilitiesChanged(false) - , mPVStateChanged(false) + , mPVOrSolarStateChanged(false) , mErrorCodeChanged(false) { } @@ -295,15 +300,14 @@ bool MainStatusMessage::settingCapabilitiesChanged() const { return mSettingCapabilitiesChanged; } -bool MainStatusMessage::statePVChanged() const +bool MainStatusMessage::statePVOrSolarChanged() const { - return mPVStateChanged; + return mPVOrSolarStateChanged; } bool MainStatusMessage::errorCodeChanged() const { return mErrorCodeChanged; } - uint8_t MainStatusMessage::errorCode() const { if (mData[23] == UINT8_MAX) @@ -312,5 +316,27 @@ uint8_t MainStatusMessage::errorCode() const } return mData[23]; } +void MainStatusMessage::enableStatePV(bool enabled) +{ + if (enabled) + { + mData[22] |= 0x10; + } + else + { + mData[22] &= ~0x10; + } +} +void MainStatusMessage::enableStateSolar(bool enabled) +{ + if (enabled) + { + mData[22] |= 0x20; + } + else + { + mData[22] &= ~0x20; + } +} } // namespace message } // namespace aquamqtt \ No newline at end of file diff --git a/AquaMQTT/src/state/MainStateProxy.cpp b/AquaMQTT/src/state/MainStateProxy.cpp new file mode 100644 index 0000000..0f915c3 --- /dev/null +++ b/AquaMQTT/src/state/MainStateProxy.cpp @@ -0,0 +1,170 @@ +#include "state/MainStateProxy.h" + +#include "config/Configuration.h" + +namespace aquamqtt +{ + +MainStateProxy& MainStateProxy::getInstance() +{ + static MainStateProxy instance; + return instance; +} + +MainStateProxy::MainStateProxy() + : IMQTTCallback() + , mMutex(xSemaphoreCreateMutex()) + , mNotify(nullptr) + , mPVModeHeatPump(false) + , mPVModeHeatElement(false) +{ +} + +void MainStateProxy::setListener(TaskHandle_t handle) +{ + if (!xSemaphoreTake(mMutex, portMAX_DELAY)) + { + return; + } + + mNotify = handle; + + xSemaphoreGive(mMutex); +} + +void MainStateProxy::applyMainOverrides(uint8_t* buffer) +{ + if (!xSemaphoreTake(mMutex, portMAX_DELAY)) + { + return; + } + + message::MainStatusMessage message(buffer); + + // we only want to modify the message if a custom pv mode is active -> else leave state as it is + if (mPVModeHeatElement) + { + // let the hmi show the pv icon in case the heat element pv state is enabled + message.enableStatePV(true); + } + + if (mPVModeHeatPump) + { + // let the hmi show the solar icon in case the heat element pv state is enabled + message.enableStateSolar(true); + } + + xSemaphoreGive(mMutex); +} + +bool MainStateProxy::copyFrame(uint8_t frameId, uint8_t* buffer) +{ + if (frameId != aquamqtt::message::MAIN_MESSAGE_IDENTIFIER) + { + return aquamqtt::DHWState::getInstance().copyFrame(frameId, buffer); + } + + bool hasMainMessage = aquamqtt::DHWState::getInstance().copyFrame(frameId, buffer); + if (hasMainMessage && aquamqtt::config::OPERATION_MODE == config::EOperationMode::MITM) + { + applyMainOverrides(buffer); + } + return hasMainMessage; +} + +void MainStateProxy::onOperationModeChanged(std::unique_ptr value) +{ + // noop +} + +void MainStateProxy::onWaterTempTargetChanged(std::unique_ptr value) +{ + // noop +} + +void MainStateProxy::onHeatingElementEnabledChanged(std::unique_ptr enabled) +{ + // noop +} + +void MainStateProxy::onEmergencyModeEnabledChanged(std::unique_ptr enabled) +{ + // noop +} + +void MainStateProxy::onPVModeHeatpumpEnabled(bool enabled) +{ + + if (!xSemaphoreTake(mMutex, portMAX_DELAY)) + { + return; + } + + mPVModeHeatPump = enabled; + + // message 193 has changed + if (mNotify != nullptr) + { + xTaskNotifyIndexed(mNotify, 0, (1UL << 7UL), eSetBits); + } + + xSemaphoreGive(mMutex); +} + +void MainStateProxy::onPVModeHeatElementEnabled(bool enabled) +{ + if (!xSemaphoreTake(mMutex, portMAX_DELAY)) + { + return; + } + + mPVModeHeatElement = enabled; + + // message 193 has changed + if (mNotify != nullptr) + { + xTaskNotifyIndexed(mNotify, 0, (1UL << 7UL), eSetBits); + } + + xSemaphoreGive(mMutex); +} + +void MainStateProxy::onOperationTypeChanged(std::unique_ptr type) +{ + // noop +} + +void MainStateProxy::onInstallationModeChanged(std::unique_ptr mode) +{ + // noop +} + +void MainStateProxy::onResetOverrides() +{ + // noop +} +AquaMqttMainOverrides MainStateProxy::getOverrides() +{ + if (!xSemaphoreTake(mMutex, portMAX_DELAY)) + { + return AquaMqttMainOverrides{}; + } + + AquaMqttMainOverrides retVal{}; + + if (mPVModeHeatPump) + { + retVal.solarState = true; + } + + if (mPVModeHeatElement) + { + retVal.pvState = true; + } + + xSemaphoreGive(mMutex); + + return retVal; +} + +} // namespace aquamqtt \ No newline at end of file diff --git a/AquaMQTT/src/task/HMITask.cpp b/AquaMQTT/src/task/HMITask.cpp index 89791ff..daf5026 100644 --- a/AquaMQTT/src/task/HMITask.cpp +++ b/AquaMQTT/src/task/HMITask.cpp @@ -6,6 +6,7 @@ #include "message/ErrorMessage.h" #include "message/MessageConstants.h" #include "state/HMIStateProxy.h" +#include "state/MainStateProxy.h" namespace aquamqtt { @@ -165,7 +166,7 @@ void HMITask::flushReadBuffer() } void HMITask::sendMessage193() { - if (DHWState::getInstance().copyFrame(message::MAIN_MESSAGE_IDENTIFIER, mTransferBuffer)) + if (MainStateProxy::getInstance().copyFrame(message::MAIN_MESSAGE_IDENTIFIER, mTransferBuffer)) { uint16_t crc = mCRC.ccitt(mTransferBuffer, message::MAIN_MESSAGE_LENGTH); Serial1.write(message::MAIN_MESSAGE_IDENTIFIER); @@ -182,7 +183,7 @@ void HMITask::sendMessage193() } void HMITask::sendMessage67() { - if (DHWState::getInstance().copyFrame(message::ENERGY_MESSAGE_IDENTIFIER, mTransferBuffer)) + if (MainStateProxy::getInstance().copyFrame(message::ENERGY_MESSAGE_IDENTIFIER, mTransferBuffer)) { uint16_t crc = mCRC.ccitt(mTransferBuffer, message::ENERGY_MESSAGE_LENGTH); Serial1.write(message::ENERGY_MESSAGE_IDENTIFIER); @@ -203,7 +204,7 @@ void HMITask::sendMessage74() // check if the HMI is requesting an error message uint8_t requestId = UINT8_MAX; { - if (DHWState::getInstance().copyFrame(aquamqtt::message::HMI_MESSAGE_IDENTIFIER, mTransferBuffer)) + if (MainStateProxy::getInstance().copyFrame(aquamqtt::message::HMI_MESSAGE_IDENTIFIER, mTransferBuffer)) { aquamqtt::message::HMIMessage hmiMessage(mTransferBuffer); requestId = hmiMessage.errorRequestId(); @@ -220,7 +221,7 @@ void HMITask::sendMessage74() // check if we have the requested error message in cache uint8_t availableRequestId = 0; { - if (DHWState::getInstance().copyFrame(aquamqtt::message::ERROR_MESSAGE_IDENTIFIER, mTransferBuffer)) + if (MainStateProxy::getInstance().copyFrame(aquamqtt::message::ERROR_MESSAGE_IDENTIFIER, mTransferBuffer)) { aquamqtt::message::ErrorMessage errorMessage(mTransferBuffer); availableRequestId = errorMessage.errorRequestId(); diff --git a/AquaMQTT/src/task/MQTTTask.cpp b/AquaMQTT/src/task/MQTTTask.cpp index bc08db9..f9003c8 100644 --- a/AquaMQTT/src/task/MQTTTask.cpp +++ b/AquaMQTT/src/task/MQTTTask.cpp @@ -7,6 +7,7 @@ #include "message/ErrorMessage.h" #include "mqtt/MQTTDefinitions.h" #include "state/HMIStateProxy.h" +#include "state/MainStateProxy.h" namespace aquamqtt { @@ -180,21 +181,29 @@ void MQTTTask::messageReceived(String& topic, String& payload) (strlen(optionalSubscribeTopicSetPvHeatPumpFlag) != 0) && strstr_P(topic.c_str(), optionalSubscribeTopicSetPvHeatPumpFlag) != nullptr) { - HMIStateProxy::getInstance().onPVModeHeatpumpEnabled(strcmp(payload.c_str(), "1") == 0); + bool enabled = strcmp(payload.c_str(), "1") == 0; + HMIStateProxy::getInstance().onPVModeHeatpumpEnabled(enabled); + MainStateProxy::getInstance().onPVModeHeatpumpEnabled(enabled); } else if (strstr_P(topic.c_str(), STATS_ENABLE_FLAG_PV_HEATPUMP) != nullptr) { - HMIStateProxy::getInstance().onPVModeHeatpumpEnabled(strcmp(payload.c_str(), "1") == 0); + bool enabled = strcmp(payload.c_str(), "1") == 0; + HMIStateProxy::getInstance().onPVModeHeatpumpEnabled(enabled); + MainStateProxy::getInstance().onPVModeHeatpumpEnabled(enabled); } else if ( (strlen(optionalSubscribeTopicSetPvHeatElementFlag) != 0) && strstr_P(topic.c_str(), optionalSubscribeTopicSetPvHeatElementFlag) != nullptr) { - HMIStateProxy::getInstance().onPVModeHeatElementEnabled(strcmp(payload.c_str(), "1") == 0); + bool enabled = strcmp(payload.c_str(), "1") == 0; + HMIStateProxy::getInstance().onPVModeHeatElementEnabled(enabled); + MainStateProxy::getInstance().onPVModeHeatElementEnabled(enabled); } else if (strstr_P(topic.c_str(), STATS_ENABLE_FLAG_PV_HEATELEMENT) != nullptr) { - HMIStateProxy::getInstance().onPVModeHeatElementEnabled(strcmp(payload.c_str(), "1") == 0); + bool enabled = strcmp(payload.c_str(), "1") == 0; + HMIStateProxy::getInstance().onPVModeHeatElementEnabled(enabled); + MainStateProxy::getInstance().onPVModeHeatElementEnabled(enabled); } else if (strstr_P(topic.c_str(), AQUAMQTT_RESET_OVERRIDES) != nullptr) { @@ -208,6 +217,7 @@ void MQTTTask::spawn() esp_task_wdt_add(mTaskHandle); DHWState::getInstance().setListener(mTaskHandle); HMIStateProxy::getInstance().setListener(mTaskHandle); + MainStateProxy::getInstance().setListener(mTaskHandle); } [[noreturn]] void MQTTTask::innerTask(void* pvParameters) @@ -313,7 +323,7 @@ void MQTTTask::loop() if ((notify & 1 << 7) != 0 || fullUpdate) { - if (DHWState::getInstance().copyFrame(aquamqtt::message::MAIN_MESSAGE_IDENTIFIER, mTransferBuffer)) + if (MainStateProxy::getInstance().copyFrame(aquamqtt::message::MAIN_MESSAGE_IDENTIFIER, mTransferBuffer)) { updateMainStatus(fullUpdate); @@ -327,7 +337,7 @@ void MQTTTask::loop() if ((notify & 1 << 6) != 0 || fullUpdate) { - if (DHWState::getInstance().copyFrame(aquamqtt::message::ENERGY_MESSAGE_IDENTIFIER, mTransferBuffer)) + if (MainStateProxy::getInstance().copyFrame(aquamqtt::message::ENERGY_MESSAGE_IDENTIFIER, mTransferBuffer)) { updateEnergyStats(fullUpdate); @@ -341,7 +351,7 @@ void MQTTTask::loop() if ((notify & 1 << 5) != 0) { - if (DHWState::getInstance().copyFrame(aquamqtt::message::ERROR_MESSAGE_IDENTIFIER, mTransferBuffer)) + if (MainStateProxy::getInstance().copyFrame(aquamqtt::message::ERROR_MESSAGE_IDENTIFIER, mTransferBuffer)) { updateErrorStatus(); } @@ -436,6 +446,22 @@ void MQTTTask::updateStats() STATS_ACTIVE_OVERRIDES); mMQTTClient.publish(reinterpret_cast(mTopicBuffer), reinterpret_cast(mPayloadBuffer)); + auto mainOverrides = MainStateProxy::getInstance().getOverrides(); + sprintf(reinterpret_cast(mPayloadBuffer), + R"({ "%S": %s, "%S": %s })", + MAIN_STATE_PV, + mainOverrides.pvState ? "1" : "0", + MAIN_STATE_SOLAR, + mainOverrides.solarState ? "1" : "0"); + + sprintf(reinterpret_cast(mTopicBuffer), + "%s%S%S%S", + config::mqttPrefix, + BASE_TOPIC, + STATS_SUBTOPIC, + STATS_ACTIVE_OVERRIDES_MAIN); + mMQTTClient.publish(reinterpret_cast(mTopicBuffer), reinterpret_cast(mPayloadBuffer)); + publishString( STATS_SUBTOPIC, STATS_AQUAMQTT_OVERRIDE_MODE, @@ -488,9 +514,10 @@ void MQTTTask::updateMainStatus(bool fullUpdate) publishi(MAIN_SUBTOPIC, MAIN_STATE_DEFROST, message.stateDefrost()); } - if (message.statePVChanged()) + if (message.statePVOrSolarChanged()) { publishi(MAIN_SUBTOPIC, MAIN_STATE_PV, message.statePV()); + publishi(MAIN_SUBTOPIC, MAIN_STATE_SOLAR, message.stateSolar()); } if (message.settingPwmFirstChanged()) diff --git a/MQTT.md b/MQTT.md index d080dfd..19997f6 100644 --- a/MQTT.md +++ b/MQTT.md @@ -14,20 +14,21 @@ Using the prefix, the `$root` topic is created, which is `$prefix/aquamqtt/` and ### AquaMQTT / Statistics -| Value | MQTT Topic | Format | Unit | Other Information | -|----------------------|-------------------------------------|--------|------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| Last Will | `$root/stats/lwlState` | Enum | | ONLINE, OFFLINE -- retained | -| OperationMode | `$root/stats/aquamqttMode` | Enum | | LISTENER, MITM | -| Active Overrides | `$root/stats/activeOverrides` | json | | Active Overrides are flagged either with 1 (overridden) or 0 (not overridden) Example Payload: `{ "operationMode": 0, "operationType": 0, "waterTempTarget": 0, "heatingElementEnabled": 0, "emergencyModeEnabled": 0, "configInstallation": 0 , "time/date": 1 }` | -| Override Modes | `$root/stats/overrideMode` | Enum | | `STANDARD`, `PV HP`, `PV HE` or `PV BOOST`. See [README-PV.md](/README-PV.md) for additional information. | -| Flag PV heat pump | `$root/stats/flagPVModeHeatPump` | bool | | Status of the pv heat pump flag. See [README-PV.md](/README-PV.md) for additional information. | -| Flag PV heat element | `$root/stats/flagPVModeHeatElement` | bool | | Status of the pv heat element flag. See [README-PV.md](/README-PV.md) for additional information. | -| IP Address | `$root/stats/ipAddress` | string | | e.g. 192.168.188.62 | -| RSSI | `$root/stats/rssiDb` | int | dB | | -| Messages OK | `$root/stats/$channel/msgHandled` | uint64 | | | -| Messages IGNORED | `$root/stats/$channel/msgUnhandled` | uint64 | | | -| Messages CRC NOK | `$root/stats/$channel/msgCRCNOK` | uint64 | | | -| Dropped Bytes | `$root/stats/$channel/droppedBytes` | uint64 | | | +| Value | MQTT Topic | Format | Unit | Other Information | +|-------------------------|-------------------------------------|--------|------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Last Will | `$root/stats/lwlState` | Enum | | ONLINE, OFFLINE -- retained | +| OperationMode | `$root/stats/aquamqttMode` | Enum | | LISTENER, MITM | +| Active Overrides (HMI) | `$root/stats/activeOverrides` | json | | Active Overrides are flagged either with 1 (overridden) or 0 (not overridden) Example Payload: `{ "operationMode": 0, "operationType": 0, "waterTempTarget": 0, "heatingElementEnabled": 0, "emergencyModeEnabled": 0, "configInstallation": 0 , "time/date": 1 }` | +| Active Overrides (MAIN) | `$root/stats/activeOverridesMain` | json | | Active Overrides are flagged either with 1 (overridden) or 0 (not overridden) Example Payload: `{ "statePV": 1, "stateSolar": 1 }` | +| Override Modes | `$root/stats/overrideMode` | Enum | | `STANDARD`, `PV HP`, `PV HE` or `PV BOOST`. See [README-PV.md](/README-PV.md) for additional information. | +| Flag PV heat pump | `$root/stats/flagPVModeHeatPump` | bool | | Status of the pv heat pump flag. See [README-PV.md](/README-PV.md) for additional information. | +| Flag PV heat element | `$root/stats/flagPVModeHeatElement` | bool | | Status of the pv heat element flag. See [README-PV.md](/README-PV.md) for additional information. | +| IP Address | `$root/stats/ipAddress` | string | | e.g. 192.168.188.62 | +| RSSI | `$root/stats/rssiDb` | int | dB | | +| Messages OK | `$root/stats/$channel/msgHandled` | uint64 | | | +| Messages IGNORED | `$root/stats/$channel/msgUnhandled` | uint64 | | | +| Messages CRC NOK | `$root/stats/$channel/msgCRCNOK` | uint64 | | | +| Dropped Bytes | `$root/stats/$channel/droppedBytes` | uint64 | | | `$channel` is either `hmi` and `main` or `listener` depending on the AquaMQTT operation mode. @@ -66,7 +67,8 @@ Using the prefix, the `$root` topic is created, which is `$prefix/aquamqtt/` and | State: Heatpump On/Off | `$root/main/stateHeatpump` | bool | | | | State: Heating Element On/Off | `$root/main/stateElement` | bool | | | | State: Boiler Backup On/Off | `$root/main/stateExtBoiler` | bool | | | -| State: Defrost On/Off Date | `$root/main/stateDefrost` | bool | | | +| State: Defrost On/Off | `$root/main/stateDefrost` | bool | | | +| State: Solar Input Signal Detected | `$root/main/stateSolar` | bool | | | | State: PV Input Signal Detected | `$root/main/statePV` | bool | | | | Setting: 1st Fan-Level PWM | `$root/main/settingPWM_1` | uint8 | % | | | Setting: 2nd Fan-Level PWM | `$root/main/settingPWM_2` | uint8 | % | | diff --git a/PROTOCOL.md b/PROTOCOL.md index 3ded8ff..ed7592f 100644 --- a/PROTOCOL.md +++ b/PROTOCOL.md @@ -408,7 +408,7 @@ Request Error No 2 with Request Id: 77 35 18 2 65 252 0 240 32 240 6 60 16 16 | 18 - 19 | 0 0 | Fan-Speed | Either 0 (off) or 650 (lowspeed) or 810 (highspeed) Maybe rpm? Does this reflect the PWM settings? | | 20 | 44 | Setting: Min T Target | *Adjustable from HMI controller* | | 21 | 62 | Setting: Anti-Legionella T Target | *Adjustable from HMI controller* | -| 22 | 0 | State: PV-Input | 16 == PV Enabled and Active! | +| 22 | 0 | State: PV and Solar Input | 16 == PV Enabled and Active, 32 == Solar Input Triggered | | 23 | 255 | Error-Code | In Error State this contains Error Code, eg. 7 | | 24 | 255 | Error-Code | In Error State this contains 0 | | 25 | 255 | Error-Code | In Error State this contains 0 | diff --git a/README-PV.md b/README-PV.md index 8872f33..7a3f29c 100644 --- a/README-PV.md +++ b/README-PV.md @@ -1,6 +1,6 @@ # PV Modes -AquaMqtt has been built to utilize local end excess energy produced by photovoltaic energy sources. For doing so, AquaMQTT provides additional operation modes to turn on either heat pump and/or heat element to reach the maximum water temperature. These operation modes can be enabled using two flags which are signaled via [MQTT](./MQTT.md). These flags override various HMI attributes: +AquaMqtt has been built to utilize local end excess energy produced by photovoltaic energy sources. For doing so, AquaMQTT provides additional operation modes to turn on either heat pump and/or heat element to reach the maximum water temperature. The additional operation modes, which are only available in MITM configuration, can be enabled using two flags which are signaled via [MQTT](./MQTT.md). These flags override various HMI attributes: ## Default @@ -20,7 +20,7 @@ flagPVModeHeatElement = false; The heat pump will try to reach maximum allowed temperature using the heat pump, without usage of the heating element. This will consume between 300 and 550W of power, depending on the current water temperature and air temperature. -Active Overrides: +Active Overrides (Direction HMI to MAIN): - Installation Mode is set to `HEATPUMP ONLY` (we don't want to use an external boiler if any connected) - OperationMode is set to "`MAN ECO OFF`" - OperationType is set to "`ALWAYS ON`" @@ -29,6 +29,9 @@ Active Overrides: - Emergeny Mode is turned `off` - Consumes about `300 - 550W` +Active Overrides (Direction MAIN to HMI): +- Solar State is set to `true` (shows Solar Icon on the HMI Display) + *Any other previously set overrides are ignored, if this mode is active!* ## PV Heat-Element Only (PV HE) @@ -40,6 +43,7 @@ flagPVModeHeatElement = true; The heat pump will try to reach maximum allowed temperate using the heating element, without usage of the heat pump. This will consume 1600W of power. +Active Overrides (Direction HMI to MAIN): - Installation Mode is set to `HEATPUMP ONLY` (we don't want to use an external boiler if any connected) - OperationMode is set to "`MAN ECO OFF`" - OperationType is set to "`ALWAYS ON`" @@ -48,6 +52,9 @@ The heat pump will try to reach maximum allowed temperate using the heating elem - Emergency Mode is turned `on` (forces usage of heat element) - Consumes `1600W` +Active Overrides (Direction MAIN to HMI): +- PV State is set to `true` (shows PV Icon on the HMI Display) + *Any other previously set overrides are ignored, if this mode is active!* ## PV BOOST @@ -59,6 +66,7 @@ flagPVModeHeatElement = true; If both flags are set, the heat pump will enter the enter OperationMode "`BOOST`" and therefore utilize both heat pump and heat element to reach and keep maximum temperature. +Active Overrides (Direction HMI to MAIN): - Installation Mode is set to `HEATPUMP ONLY` (we don't want to use an external boiler if any connected) - OperationMode is set to "`BOOST`" - OperationType is set to "`ALWAYS ON`" @@ -66,6 +74,10 @@ If both flags are set, the heat pump will enter the enter OperationMode "`BOOST` - Heating Element is set to `enabled` - Consumes `1600W` + `300 - 550W` +Active Overrides (Direction MAIN to HMI): +- Solar State is set to `true` (shows Solar Icon on the HMI Display) +- PV State is set to `true` (shows PV Icon on the HMI Display) + *Any other previously set overrides are ignored, if this mode is active!* ## How to trigger the flags? @@ -79,7 +91,6 @@ The flags can be triggered using the [MQTT](./MQTT.md) control topics. The curre | Flag PV heat element | `$root/stats/flagPVModeHeatElement` | bool | Status of the pv heat element flag | Set PV Mode Heat Pump Flag | `$root/ctrl/flagPVModeHeatPump` | bool | Note: It is possible to define an additional custom mqtt topic for this attribute within `Configuration.h` | | Set PV Mode Heat Element Flag | `$root/ctrl/flagPVModeHeatElement` | bool | Note: It is possible to define an additional custom mqtt topic for this attribute within `Configuration.h` | - | ## How to automate?