add heatpump pool on/off, pool active, MP100 shunt setpoint and pool pump

Tested with a heatpump (0x08) and MP100 pool module (0x11), custom entities
compared against RC300 operation and a power meter on the circulation pump.

- boiler `poolon` (0x48A offset 0), writable, RC300 writes 01/00
- boiler `hppoolon` (0x488 offset 0 bit 6), pool heating actually active
- pool `poolshuntset` (0x5C4 offset 0, heatpump -> MP100), shunt setpoint;
  `poolshunt` follows within ~2 min
- pool `poolpump` (0x5BA offset 4), 0 = running, 2 = off. This byte is only
  in MP100 -> heatpump telegrams, so the pool module now also handles
  telegrams it sends to other devices
- simulator: `test pool`

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013YrkDbvxEv3ZMS7SPSKCGd
This commit is contained in:
Bingo2023
2026-09-24 17:24:47 +02:00
co-authored by Claude Opus 5.5
parent 09c9e5d53b
commit 1d2b916935
8 changed files with 65 additions and 5 deletions
+1
View File
@@ -19,6 +19,7 @@ This release is based on the latest Espressif/Arduino core version 3. It brings
- `show system` reports the Ethernet status on boards with a PHY, so a failed initialisation or a link that never came up is visible instead of Ethernet being omitted completely. Also shows the loop task's lowest free stack, to help diagnose reboots - `show system` reports the Ethernet status on boards with a PHY, so a failed initialisation or a link that never came up is visible instead of Ethernet being omitted completely. Also shows the loop task's lowest free stack, to help diagnose reboots
- new Application Setting "Automatically check for firmware updates", off by default. When enabled EMS-ESP asks emsesp.org for the latest version once a day on its own, otherwise it only asks when the WebUI wants to show it, so an unattended system never contacts emsesp.org - new Application Setting "Automatically check for firmware updates", off by default. When enabled EMS-ESP asks emsesp.org for the latest version once a day on its own, otherwise it only asks when the WebUI wants to show it, so an unattended system never contacts emsesp.org
- Automatically check and convert older 3.8.x filesystem to the new 3.9.0 format - Automatically check and convert older 3.8.x filesystem to the new 3.9.0 format
- heatpump pool: `poolon` (switch, 0x48A), `hppoolon` (pool heating active, 0x488), MP100 `poolshuntset` (0x5C4) and `poolpump` (0x5BA)
## Fixed ## Fixed
+3 -1
View File
@@ -1210,7 +1210,9 @@ bool EMSESP::process_telegram(const std::shared_ptr<const Telegram> & telegram)
// check all conditions in one loop // check all conditions in one loop
for (const auto & emsdevice : emsdevices) { for (const auto & emsdevice : emsdevices) {
if ((emsdevice->is_device_id(telegram->src) && (telegram->dest == 0 || telegram->dest == EMSbus::ems_bus_id() || telegram->dest == 0x10)) if ((emsdevice->is_device_id(telegram->src) && (telegram->dest == 0 || telegram->dest == EMSbus::ems_bus_id() || telegram->dest == 0x10))
|| (emsdevice->is_device_id(telegram->dest) && telegram->src != EMSbus::ems_bus_id())) { || (emsdevice->is_device_id(telegram->dest) && telegram->src != EMSbus::ems_bus_id())
// the MP100 sends its full status only to the heatpump
|| (emsdevice->device_type() == EMSdevice::DeviceType::POOL && emsdevice->is_device_id(telegram->src))) {
found_device = emsdevice.get(); found_device = emsdevice.get();
if (emsdevice->handle_telegram(telegram)) { if (emsdevice->handle_telegram(telegram)) {
telegram_found = true; telegram_found = true;
+4 -1
View File
@@ -470,7 +470,7 @@ MAKE_TRANSLATION(coolingOn, "coolingon", "cooling on", "Kühlung an", "koelbedri
// MAKE_TRANSLATION(hpHeatingOn, "hpheatingon", "hp heating", "WP Heizen", "WP verwarmingsbedrijf", "VP Uppvärmning", "pompa ciepła, ogrzewanie", "vp oppvarmning", "hp ısınıyor", "riscaldamento pompa calore", "vykurovanie hp", "topení hp") // MAKE_TRANSLATION(hpHeatingOn, "hpheatingon", "hp heating", "WP Heizen", "WP verwarmingsbedrijf", "VP Uppvärmning", "pompa ciepła, ogrzewanie", "vp oppvarmning", "hp ısınıyor", "riscaldamento pompa calore", "vykurovanie hp", "topení hp")
// MAKE_TRANSLATION(hpCoolingOn, "hpcoolingon", "hp cooling", "WP Kühlen", "WP koelbedrijf", "VP Kyla", "pompa ciepła, chłodzenie", "vp kjøling", "hp soğuyor", "raffreddamento pompa calore", "chladenie hp", "chlazení hp") // MAKE_TRANSLATION(hpCoolingOn, "hpcoolingon", "hp cooling", "WP Kühlen", "WP koelbedrijf", "VP Kyla", "pompa ciepła, chłodzenie", "vp kjøling", "hp soğuyor", "raffreddamento pompa calore", "chladenie hp", "chlazení hp")
// MAKE_TRANSLATION(hpWwOn, "hpdhwon", "hp", "WP", "WP", "VP Varmvatten", "pompa ciepła", "vp", "pompe à chaleur", "hp", "pompa calore", "hp", "hp") // MAKE_TRANSLATION(hpWwOn, "hpdhwon", "hp", "WP", "WP", "VP Varmvatten", "pompa ciepła", "vp", "pompe à chaleur", "hp", "pompa calore", "hp", "hp")
// MAKE_TRANSLATION(hpPoolOn, "hppoolon", "hp pool", "WP Pool", "WP zwembadbedrijf", "VP Pool", "pompa ciepła, podgrzewanie basenu", "vp basseng", "tuzlu su pompası hızı", "pompa calore piscina", "hp bazén", "hp bazén") MAKE_TRANSLATION(hpPoolOn, "hppoolon", "hp pool", "WP Pool", "WP zwembadbedrijf", "VP Pool", "pompa ciepła, podgrzewanie basenu", "vp basseng", "tuzlu su pompası hızı", "pompa calore piscina", "hp bazén", "hp bazén")
MAKE_TRANSLATION(hpBrinePumpSpd, "hpbrinepumpspd", "brine pump speed", "Solepumpendrehzahl", "Snelheid pekelpomp", "Hastighet Brine-pump", "wysterowanie pompy glikolu", "hastighet brine-pumpe", "vitesse pompe à saumure", "ısı pompası hızı", "velocità pompa sbrinamento", "rýchlosť čerpadla soľanky", "rychlost čerpadla solanky") MAKE_TRANSLATION(hpBrinePumpSpd, "hpbrinepumpspd", "brine pump speed", "Solepumpendrehzahl", "Snelheid pekelpomp", "Hastighet Brine-pump", "wysterowanie pompy glikolu", "hastighet brine-pumpe", "vitesse pompe à saumure", "ısı pompası hızı", "velocità pompa sbrinamento", "rýchlosť čerpadla soľanky", "rychlost čerpadla solanky")
MAKE_TRANSLATION(hpCompSpd, "hpcompspd", "compressor speed", "Kompressordrehzahl", "Snelheid compressor", "Kompressorhastighet", "wysterowanie sprężarki", "kompressorhastighet", "vitesse du compresseur", "sirkülasyon pompası hızı", "velocità compressore", "rýchlosť kompresora", "rychlost kompresoru") MAKE_TRANSLATION(hpCompSpd, "hpcompspd", "compressor speed", "Kompressordrehzahl", "Snelheid compressor", "Kompressorhastighet", "wysterowanie sprężarki", "kompressorhastighet", "vitesse du compresseur", "sirkülasyon pompası hızı", "velocità compressore", "rýchlosť kompresora", "rychlost kompresoru")
MAKE_TRANSLATION(hpCircSpd, "hpcircspd", "circulation pump speed", "Zirkulationspumpendrehzahl", "Snelheid circulatiepomp", "Hastighet Cirkulationspump", "wysterowanie pompy obiegu grzewczego", "hastighet sirkulationspumpe", "vitesse pompe à circulation", "evaporatör tuzlu su giişi", "velocità pompa circolazione", "otáčky obehového čerpadla", "rychlost oběhového čerpadla") MAKE_TRANSLATION(hpCircSpd, "hpcircspd", "circulation pump speed", "Zirkulationspumpendrehzahl", "Snelheid circulatiepomp", "Hastighet Cirkulationspump", "wysterowanie pompy obiegu grzewczego", "hastighet sirkulationspumpe", "vitesse pompe à circulation", "evaporatör tuzlu su giişi", "velocità pompa circolazione", "otáčky obehového čerpadla", "rychlost oběhového čerpadla")
@@ -856,10 +856,13 @@ MAKE_TRANSLATION(mixerSetTime, "valvesettime", "time to set valve", "Zeit zum ei
MAKE_TRANSLATION(setDiffPress, "setdiffpress", "set differential pressure", "Pumpensolldruck", "", "Tryckskillnad", "różnica ciśnień", "", "", "", "", "nastaviť diferenčný tlak", "nastavení rozdílového tlaku") MAKE_TRANSLATION(setDiffPress, "setdiffpress", "set differential pressure", "Pumpensolldruck", "", "Tryckskillnad", "różnica ciśnień", "", "", "", "", "nastaviť diferenčný tlak", "nastavení rozdílového tlaku")
// mixer pool // mixer pool
MAKE_TRANSLATION(poolOn, "poolon", "pool on", "Pool ein")
MAKE_TRANSLATION(poolSetTemp, "poolsettemp", "pool set temperature", "Sollwert Pooltemperatur", "Streeftemperatuur zwembad", "Pool Temperatur Börvärde", "zadana temperatura basenu", "valgt temp basseng", "température consigne piscine", "hedef havuz sıcaklığı", "temperatura nominale piscina", "nastavená teplota bazéna", "cílová teplota bazénu") MAKE_TRANSLATION(poolSetTemp, "poolsettemp", "pool set temperature", "Sollwert Pooltemperatur", "Streeftemperatuur zwembad", "Pool Temperatur Börvärde", "zadana temperatura basenu", "valgt temp basseng", "température consigne piscine", "hedef havuz sıcaklığı", "temperatura nominale piscina", "nastavená teplota bazéna", "cílová teplota bazénu")
MAKE_TRANSLATION(poolTemp, "pooltemp", "pool temperature", "Pooltemperatur", "Zwembadtemperatuur", "Pooltemperatur", "temperatura basenu", "bassengtemperatur", "température piscine", "havuz sıcaklığı", "temperatura piscina", "teplota bazéna", "teplota bazénu") MAKE_TRANSLATION(poolTemp, "pooltemp", "pool temperature", "Pooltemperatur", "Zwembadtemperatuur", "Pooltemperatur", "temperatura basenu", "bassengtemperatur", "température piscine", "havuz sıcaklığı", "temperatura piscina", "teplota bazéna", "teplota bazénu")
MAKE_TRANSLATION(poolShuntStatus, "poolshuntstatus", "pool shunt status opening/closing", "Poolventil öffnen/schließen", "Zwembadklep status openen/sluiten", "Pool Shunt-status öppen/stängd", "status bocznika basenu", "bassengshunt-status åpen/stengt", "état shunt piscine ouvert/fermé", "havuz şant durumu açılıyor/kapanıyor", "aprire/chiudere valvola regolazione piscina", "stav bazénového bočníka otváranie/zatváranie", "stav šoupátka bazénu (otevírání/zavírání)") MAKE_TRANSLATION(poolShuntStatus, "poolshuntstatus", "pool shunt status opening/closing", "Poolventil öffnen/schließen", "Zwembadklep status openen/sluiten", "Pool Shunt-status öppen/stängd", "status bocznika basenu", "bassengshunt-status åpen/stengt", "état shunt piscine ouvert/fermé", "havuz şant durumu açılıyor/kapanıyor", "aprire/chiudere valvola regolazione piscina", "stav bazénového bočníka otváranie/zatváranie", "stav šoupátka bazénu (otevírání/zavírání)")
MAKE_TRANSLATION(poolShunt, "poolshunt", "pool shunt open/close (0% = pool / 100% = heat)", "Poolventil Öffnung", "Mengklep zwembad stand", "Pool Shunt Öppen/Stängd", "bocznik basenu (0% = basen / 100% = grzanie)", "bassengshunt åpen/stengt (0% = basseng / 100% = varme)", "ouverture/fermeture shunt piscine (0% = piscine / 100% = chaleur).", "havuz şant açık/kapalı (0% = havuz / 100% = ısıtma)", "valvola regolazione piscina (0% = piscina / 100% = caldo)", "pohyb bazéna otvoriť/zatvoriť (0 % = bazén / 100 % = teplo)", "šoupátko bazénu (0% = bazén / 100% = vytápění)") MAKE_TRANSLATION(poolShunt, "poolshunt", "pool shunt open/close (0% = pool / 100% = heat)", "Poolventil Öffnung", "Mengklep zwembad stand", "Pool Shunt Öppen/Stängd", "bocznik basenu (0% = basen / 100% = grzanie)", "bassengshunt åpen/stengt (0% = basseng / 100% = varme)", "ouverture/fermeture shunt piscine (0% = piscine / 100% = chaleur).", "havuz şant açık/kapalı (0% = havuz / 100% = ısıtma)", "valvola regolazione piscina (0% = piscina / 100% = caldo)", "pohyb bazéna otvoriť/zatvoriť (0 % = bazén / 100 % = teplo)", "šoupátko bazénu (0% = bazén / 100% = vytápění)")
MAKE_TRANSLATION(poolShuntSet, "poolshuntset", "pool shunt setpoint (0% = pool / 100% = heat)", "Poolventil Sollstellung")
MAKE_TRANSLATION(poolPump, "poolpump", "pool circulation pump", "Pool Umwälzpumpe")
MAKE_TRANSLATION(hydrTemp, "hydrTemp", "hydraulic header temperature", "Verteilertemperatur", "Temperatuur open verdeler", "Fördelartemperatur", "temperatura kolektora hydraulicznego", "Fordelertemperatur", "température collecteur hydraulique", "hidrolik başlık sıcaklığı", "temperatura del collettore", "teplota hydraulickej hlavice", "teplota hydraulické hlavice") MAKE_TRANSLATION(hydrTemp, "hydrTemp", "hydraulic header temperature", "Verteilertemperatur", "Temperatuur open verdeler", "Fördelartemperatur", "temperatura kolektora hydraulicznego", "Fordelertemperatur", "température collecteur hydraulique", "hidrolik başlık sıcaklığı", "temperatura del collettore", "teplota hydraulickej hlavice", "teplota hydraulické hlavice")
// solar // solar
+17 -1
View File
@@ -632,7 +632,7 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
// register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpHeatingOn_, DeviceValueType::BOOL, FL_(hpHeatingOn), DeviceValueUOM::NONE); // register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpHeatingOn_, DeviceValueType::BOOL, FL_(hpHeatingOn), DeviceValueUOM::NONE);
// register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpCoolingOn_, DeviceValueType::BOOL, FL_(hpCoolingOn), DeviceValueUOM::NONE); // register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpCoolingOn_, DeviceValueType::BOOL, FL_(hpCoolingOn), DeviceValueUOM::NONE);
// register_device_value(DeviceValueTAG::TAG_DHW1, &hpWwOn_, DeviceValueType::BOOL, FL_(hpWwOn), DeviceValueUOM::NONE); // register_device_value(DeviceValueTAG::TAG_DHW1, &hpWwOn_, DeviceValueType::BOOL, FL_(hpWwOn), DeviceValueUOM::NONE);
// register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpPoolOn_, DeviceValueType::BOOL, FL_(hpPoolOn), DeviceValueUOM::NONE); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpPoolOn_, DeviceValueType::BOOL, FL_(hpPoolOn), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpBrinePumpSpd_, DeviceValueType::UINT8, FL_(hpBrinePumpSpd), DeviceValueUOM::PERCENT); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpBrinePumpSpd_, DeviceValueType::UINT8, FL_(hpBrinePumpSpd), DeviceValueUOM::PERCENT);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpSwitchValve_, DeviceValueType::BOOL, FL_(hpSwitchValve), DeviceValueUOM::NONE); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpSwitchValve_, DeviceValueType::BOOL, FL_(hpSwitchValve), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpCompSpd_, DeviceValueType::UINT8, FL_(hpCompSpd), DeviceValueUOM::PERCENT); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpCompSpd_, DeviceValueType::UINT8, FL_(hpCompSpd), DeviceValueUOM::PERCENT);
@@ -666,6 +666,7 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpPh1_, DeviceValueType::INT16, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(hpPh1), DeviceValueUOM::DEGREES); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpPh1_, DeviceValueType::INT16, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(hpPh1), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpTa4_, DeviceValueType::INT16, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(hpTa4), DeviceValueUOM::DEGREES); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpTa4_, DeviceValueType::INT16, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(hpTa4), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpTw1_, DeviceValueType::INT16, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(hpTw1), DeviceValueUOM::DEGREES); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpTw1_, DeviceValueType::INT16, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(hpTw1), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &poolOn_, DeviceValueType::BOOL, FL_(poolOn), DeviceValueUOM::NONE, MAKE_CF_CB(set_pool_on));
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&poolSetTemp_, &poolSetTemp_,
DeviceValueType::UINT8, DeviceValueType::UINT8,
@@ -1815,7 +1816,9 @@ void Boiler::process_HpTemperatures(const std::shared_ptr<const Telegram> & tele
// Heatpump pool unit - type 0x48A // Heatpump pool unit - type 0x48A
// 08 00 FF 00 03 8A 01 4C 01 0C 00 00 0A 00 1E 00 00 01 00 04 4A 00 // 08 00 FF 00 03 8A 01 4C 01 0C 00 00 0A 00 1E 00 00 01 00 04 4A 00
// RC300 switches the pool: 10 08 FF 00 03 8A 01 (on) / 00 (off)
void Boiler::process_HpPool(const std::shared_ptr<const Telegram> & telegram) { void Boiler::process_HpPool(const std::shared_ptr<const Telegram> & telegram) {
has_update(telegram, poolOn_, 0);
has_update(telegram, poolSetTemp_, 1); has_update(telegram, poolSetTemp_, 1);
} }
@@ -2164,8 +2167,11 @@ void Boiler::process_HpSilentMode(const std::shared_ptr<const Telegram> & telegr
} }
// Boiler(0x08) -B-> All(0x00), ?(0x0488), data: 8E 00 00 00 00 00 01 03 // Boiler(0x08) -B-> All(0x00), ?(0x0488), data: 8E 00 00 00 00 00 01 03
// byte 0 bit 6 is set while the heatpump is actually heating the pool
// (switches together with 0x5C4 and MP100 0x5BA offset 2)
void Boiler::process_HpValve(const std::shared_ptr<const Telegram> & telegram) { void Boiler::process_HpValve(const std::shared_ptr<const Telegram> & telegram) {
// has_bitupdate(telegram, auxHeaterStatus_, 0, 2); // has_bitupdate(telegram, auxHeaterStatus_, 0, 2);
has_bitupdate(telegram, hpPoolOn_, 0, 6);
has_update(telegram, auxHeatMixValve_, 7); has_update(telegram, auxHeatMixValve_, 7);
has_update(telegram, pc1Rate_, 13); // percent has_update(telegram, pc1Rate_, 13); // percent
} }
@@ -3161,6 +3167,16 @@ bool Boiler::set_pool_temp(const char * value, const int8_t id) {
return true; return true;
} }
// Switch the pool on/off 0x48A, same as RC300
bool Boiler::set_pool_on(const char * value, const int8_t id) {
bool v;
if (!Helpers::value2bool(value, v)) {
return false;
}
write_command(0x48A, 0, v ? 0x01 : 0x00, 0x48A);
return true;
}
bool Boiler::set_emergency_temp(const char * value, const int8_t id) { bool Boiler::set_emergency_temp(const char * value, const int8_t id) {
int v; int v;
if (!Helpers::value2temperature(value, v)) { if (!Helpers::value2temperature(value, v)) {
+4 -2
View File
@@ -213,7 +213,7 @@ class Boiler : public EMSdevice {
// uint8_t hpHeatingOn_; // uint8_t hpHeatingOn_;
// uint8_t hpCoolingOn_; // uint8_t hpCoolingOn_;
// uint8_t hpWwOn_; // uint8_t hpWwOn_;
// uint8_t hpPoolOn_; uint8_t hpPoolOn_;
int16_t hpTc0_; int16_t hpTc0_;
int16_t hpTc1_; int16_t hpTc1_;
int16_t hpTc3_; int16_t hpTc3_;
@@ -253,7 +253,8 @@ class Boiler : public EMSdevice {
uint8_t hpTargetSpd_; uint8_t hpTargetSpd_;
// Pool unit // Pool unit
int8_t poolSetTemp_; uint8_t poolOn_;
int8_t poolSetTemp_;
// Inputs // Inputs
struct { struct {
@@ -465,6 +466,7 @@ class Boiler : public EMSdevice {
bool set_ww_hyst_on(const char * value, const int8_t id); bool set_ww_hyst_on(const char * value, const int8_t id);
bool set_ww_hyst_off(const char * value, const int8_t id); bool set_ww_hyst_off(const char * value, const int8_t id);
bool set_pool_temp(const char * value, const int8_t id); bool set_pool_temp(const char * value, const int8_t id);
bool set_pool_on(const char * value, const int8_t id);
bool set_emergency_temp(const char * value, const int8_t id); bool set_emergency_temp(const char * value, const int8_t id);
bool set_emergency_ops(const char * value, const int8_t id); bool set_emergency_ops(const char * value, const int8_t id);
+16
View File
@@ -28,6 +28,7 @@ Pool::Pool(uint8_t device_type, uint8_t device_id, uint8_t product_id, const cha
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) { : EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
// Pool module // Pool module
register_telegram_type(0x5BA, "HpPoolStatus", true, MAKE_PF_CB(process_HpPoolStatus), 4); register_telegram_type(0x5BA, "HpPoolStatus", true, MAKE_PF_CB(process_HpPoolStatus), 4);
register_telegram_type(0x5C4, "HpPoolShunt", false, MAKE_PF_CB(process_HpPoolShunt));
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&poolTemp_, &poolTemp_,
DeviceValueType::INT16, DeviceValueType::INT16,
@@ -36,10 +37,19 @@ Pool::Pool(uint8_t device_type, uint8_t device_id, uint8_t product_id, const cha
DeviceValueUOM::DEGREES); DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &poolShuntStatus_, DeviceValueType::ENUM, FL_(enum_shunt), FL_(poolShuntStatus), DeviceValueUOM::NONE); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &poolShuntStatus_, DeviceValueType::ENUM, FL_(enum_shunt), FL_(poolShuntStatus), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &poolShunt_, DeviceValueType::UINT8, FL_(poolShunt), DeviceValueUOM::PERCENT); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &poolShunt_, DeviceValueType::UINT8, FL_(poolShunt), DeviceValueUOM::PERCENT);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &poolShuntSet_, DeviceValueType::UINT8, FL_(poolShuntSet), DeviceValueUOM::PERCENT);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &poolPump_, DeviceValueType::BOOL, FL_(poolPump), DeviceValueUOM::NONE);
} }
// Mixer MP100 for pools - 0x5BA // Mixer MP100 for pools - 0x5BA
// MP100(0x11) -> Boiler(0x08): 11 08 FF 00 04 BA 01 45 02 00 02
// offset 4 (pool circulation pump, 0 = running, 2 = off) is only in the telegram to the boiler,
// the answer to a read request is one byte shorter
void Pool::process_HpPoolStatus(const std::shared_ptr<const Telegram> & telegram) { void Pool::process_HpPoolStatus(const std::shared_ptr<const Telegram> & telegram) {
uint8_t pump = EMS_VALUE_UINT8_NOTSET;
if (telegram->read_value(pump, 4)) {
has_update(poolPump_, pump == 0 ? EMS_VALUE_BOOL_ON : EMS_VALUE_BOOL_OFF);
}
has_update(telegram, poolTemp_, 0); has_update(telegram, poolTemp_, 0);
has_update(telegram, poolShunt_, 3); // 0-100% how much is the shunt open? has_update(telegram, poolShunt_, 3); // 0-100% how much is the shunt open?
telegram->read_value(poolShuntStatus__, 2); telegram->read_value(poolShuntStatus__, 2);
@@ -47,4 +57,10 @@ void Pool::process_HpPoolStatus(const std::shared_ptr<const Telegram> & telegram
has_update(poolShuntStatus_, pss); has_update(poolShuntStatus_, pss);
} }
// Boiler(0x08) -> MP100(0x11), 0x5C4: 08 11 FF 00 04 C4 64
// shunt setpoint from the heatpump, 0% = pool / 100% = heat, poolshunt follows within ~2 min
void Pool::process_HpPoolShunt(const std::shared_ptr<const Telegram> & telegram) {
has_update(telegram, poolShuntSet_, 0);
}
} // namespace emsesp } // namespace emsesp
+3
View File
@@ -31,12 +31,15 @@ class Pool : public EMSdevice {
static uuid::log::Logger logger_; static uuid::log::Logger logger_;
void process_HpPoolStatus(const std::shared_ptr<const Telegram> & telegram); void process_HpPoolStatus(const std::shared_ptr<const Telegram> & telegram);
void process_HpPoolShunt(const std::shared_ptr<const Telegram> & telegram);
private: private:
// MP100 pool // MP100 pool
int16_t poolTemp_; int16_t poolTemp_;
uint8_t poolShuntStatus_; uint8_t poolShuntStatus_;
uint8_t poolShunt_; uint8_t poolShunt_;
uint8_t poolShuntSet_;
uint8_t poolPump_;
uint8_t poolShuntStatus__ = EMS_VALUE_UINT8_NOTSET; // temp value uint8_t poolShuntStatus__ = EMS_VALUE_UINT8_NOTSET; // temp value
}; };
+17
View File
@@ -959,6 +959,23 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
ok = true; ok = true;
} }
if (command == "pool") {
shell.printfln("Testing heatpump with MP100 pool module...");
add_device(0x08, 172); // heatpump
add_device(0x11, 204); // MP100
// RC300 switches pool on, 40.0 C
uart_telegram({0x10, 0x08, 0xFF, 0x00, 0x03, 0x8A, 0x01});
uart_telegram({0x08, 0x00, 0xFF, 0x00, 0x03, 0x8A, 0x01, 0x50, 0x01, 0x0C, 0x00, 0x00, 0x0A, 0x00, 0x1E, 0x00, 0x00, 0x01, 0x00, 0x04});
// HPValve, byte 0 bit 6 = pool heating active
uart_telegram({0x08, 0x00, 0xFF, 0x00, 0x03, 0x88, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00});
// heatpump -> MP100 shunt setpoint 0%
uart_telegram({0x08, 0x11, 0xFF, 0x00, 0x04, 0xC4, 0x00});
// MP100 -> heatpump: 32.5 C, shunt 45%, pump running
uart_telegram({0x11, 0x08, 0xFF, 0x00, 0x04, 0xBA, 0x01, 0x45, 0x02, 0x2D, 0x00});
shell.invoke_command("show values");
ok = true;
}
if (command == "healthcheck") { if (command == "healthcheck") {
// n=1 = EMSESP::system_.HEALTHCHECK_NO_BUS // n=1 = EMSESP::system_.HEALTHCHECK_NO_BUS
// n=2 = EMSESP::system_.HEALTHCHECK_NO_NETWORK // n=2 = EMSESP::system_.HEALTHCHECK_NO_NETWORK