From 0a82c28fbf6a515416e003bb83e7aef30671fbaa Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Sat, 24 Apr 2021 11:18:59 +0200 Subject: [PATCH 1/3] add min/max to values, boiler flags, ww-prefix, ha-prefix to mqtt --- src/dallassensor.cpp | 4 +- src/device_library.h | 5 +- src/devices/boiler.cpp | 145 +++++++++++++++++++------------------ src/devices/boiler.h | 9 ++- src/devices/heatpump.cpp | 4 +- src/devices/mixer.cpp | 8 +- src/devices/solar.cpp | 48 +++++++----- src/devices/solar.h | 8 ++ src/devices/switch.cpp | 4 +- src/devices/thermostat.cpp | 47 ++++++------ src/devices/thermostat.h | 5 +- src/emsdevice.cpp | 48 ++++++++---- src/emsdevice.h | 75 ++++++------------- src/emsesp.cpp | 6 +- src/locale_EN.h | 100 +++++++++++++++++++++---- src/mqtt.cpp | 26 ++++--- src/shower.cpp | 2 +- 17 files changed, 315 insertions(+), 229 deletions(-) diff --git a/src/dallassensor.cpp b/src/dallassensor.cpp index 83a577016..a1dd07fb9 100644 --- a/src/dallassensor.cpp +++ b/src/dallassensor.cpp @@ -391,9 +391,9 @@ void DallasSensor::publish_values(const bool force) { // use '_' as HA doesn't like '-' in the topic name std::string topicname = sensor.to_string(); std::replace(topicname.begin(), topicname.end(), '-', '_'); - snprintf_P(topic, sizeof(topic), PSTR("homeassistant/sensor/%s/dallas_sensor%s/config"), Mqtt::base().c_str(), topicname.c_str()); + snprintf_P(topic, sizeof(topic), PSTR("sensor/%s/dallas_sensor%s/config"), Mqtt::base().c_str(), topicname.c_str()); } else { - snprintf_P(topic, sizeof(topic), PSTR("homeassistant/sensor/%s/dallas_sensor%d/config"), Mqtt::base().c_str(), sensor_no); + snprintf_P(topic, sizeof(topic), PSTR("sensor/%s/dallas_sensor%d/config"), Mqtt::base().c_str(), sensor_no); } Mqtt::publish_ha(topic, config.as()); diff --git a/src/device_library.h b/src/device_library.h index bfd296b15..8acff9f5c 100644 --- a/src/device_library.h +++ b/src/device_library.h @@ -27,7 +27,7 @@ { 64, DeviceType::BOILER, F("BK13/BK15/Smartline/GB1x2"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, { 72, DeviceType::BOILER, F("GB125/MC10"), DeviceFlags::EMS_DEVICE_FLAG_EMS}, { 84, DeviceType::BOILER, F("Logamax Plus GB022"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, -{ 95, DeviceType::BOILER, F("Condens 2500/Logamax/Logomatic/Cerapur Top/Greenstar/Generic HT3"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, +{ 95, DeviceType::BOILER, F("Condens 2500/Logamax/Logomatic/Cerapur Top/Greenstar/Generic HT3"), DeviceFlags::EMS_DEVICE_FLAG_HT3}, {115, DeviceType::BOILER, F("Topline/GB162"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, {122, DeviceType::BOILER, F("Proline"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, {123, DeviceType::BOILER, F("GBx72/Trendline/Cerapur/Greenstar Si/27i"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, @@ -35,7 +35,7 @@ {133, DeviceType::BOILER, F("GB125/Logamatic MC110"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, {167, DeviceType::BOILER, F("Cerapur Aero"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, {170, DeviceType::BOILER, F("Logano GB212"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, -{172, DeviceType::BOILER, F("Enviline/Compress 6000AW/Hybrid 7000iAW/SupraEco"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, +{172, DeviceType::BOILER, F("Enviline/Compress 6000AW/Hybrid 7000iAW/SupraEco"), DeviceFlags::EMS_DEVICE_FLAG_HEATPUMP}, {195, DeviceType::BOILER, F("Condens 5000i/Greenstar 8000"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, {203, DeviceType::BOILER, F("Logamax U122/Cerapur"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, {208, DeviceType::BOILER, F("Logamax Plus/GB192/Condens GC9000"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, @@ -80,6 +80,7 @@ {157, DeviceType::THERMOSTAT, F("RC200/CW100"), DeviceFlags::EMS_DEVICE_FLAG_RC100}, // 0x18 {158, DeviceType::THERMOSTAT, F("RC300/RC310/Moduline 3000/1010H/CW400/Sense II"), DeviceFlags::EMS_DEVICE_FLAG_RC300}, // 0x10 {165, DeviceType::THERMOSTAT, F("RC100/Moduline 1000/1010"), DeviceFlags::EMS_DEVICE_FLAG_RC100}, // 0x18, 0x38 +{216, DeviceType::THERMOSTAT, F("CRF200S"), DeviceFlags::EMS_DEVICE_FLAG_RC100}, // 0x18 // Thermostat - Sieger - 0x10 / 0x17 { 66, DeviceType::THERMOSTAT, F("ES72/RC20"), DeviceFlags::EMS_DEVICE_FLAG_RC20_N}, // 0x17 or remote diff --git a/src/devices/boiler.cpp b/src/devices/boiler.cpp index 21179aaad..e7ae503b5 100644 --- a/src/devices/boiler.cpp +++ b/src/devices/boiler.cpp @@ -33,15 +33,15 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const uint8_t hs = device_id - EMSdevice::EMS_DEVICE_ID_BOILER_1; // heating source id, count from 0 // Runtime of each heatingsource in 0x06DC, ff register_telegram_type(0x6DC + hs, F("CascadeMessage"), false, MAKE_PF_CB(process_CascadeMessage)); - register_device_value(TAG_HS1 + hs, &burnWorkMin_, DeviceValueType::TIME, nullptr, F("burnWorkMin"), F("total burner operating time"), DeviceValueUOM::MINUTES); + register_device_value(TAG_HS1 + hs, &burnWorkMin_, DeviceValueType::TIME, nullptr, FL_(burnWorkMin), DeviceValueUOM::MINUTES); // selBurnpower in D2 and E4 // register_telegram_type(0xD2, F("CascadePowerMessage"), false, MAKE_PF_CB(process_CascadePowerMessage)); // individual Flowtemps and powervalues for each heatingsource in E4 register_telegram_type(0xE4, F("UBAMonitorFastPlus"), false, MAKE_PF_CB(process_UBAMonitorFastPlus)); - register_device_value(TAG_HS1 + hs, &selFlowTemp_, DeviceValueType::UINT, nullptr, F("selFlowTemp"), F("selected flow temperature"), DeviceValueUOM::DEGREES); - register_device_value(TAG_HS1 + hs, &selBurnPow_, DeviceValueType::UINT, nullptr, F("selBurnPow"), F("burner selected max power"), DeviceValueUOM::PERCENT); - register_device_value(TAG_HS1 + hs, &curFlowTemp_, DeviceValueType::USHORT, FL_(div10), F("curFlowTemp"), F("current flow temperature"), DeviceValueUOM::DEGREES); - register_device_value(TAG_HS1 + hs, &curBurnPow_, DeviceValueType::UINT, nullptr, F("curBurnPow"), F("burner current power"), DeviceValueUOM::PERCENT); + register_device_value(TAG_HS1 + hs, &selFlowTemp_, DeviceValueType::UINT, nullptr, FL_(selFlowTemp), DeviceValueUOM::DEGREES); + register_device_value(TAG_HS1 + hs, &selBurnPow_, DeviceValueType::UINT, nullptr, FL_(selBurnPow), DeviceValueUOM::PERCENT); + register_device_value(TAG_HS1 + hs, &curFlowTemp_, DeviceValueType::USHORT, FL_(div10), FL_(curFlowTemp), DeviceValueUOM::DEGREES); + register_device_value(TAG_HS1 + hs, &curBurnPow_, DeviceValueType::UINT, nullptr, FL_(curBurnPow), DeviceValueUOM::PERCENT); return; } // register values for master boiler/cascade module @@ -57,14 +57,14 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const // EMS1.0 and maybe EMS+? register_telegram_type(0x18, F("UBAMonitorFast"), false, MAKE_PF_CB(process_UBAMonitorFast)); register_telegram_type(0x19, F("UBAMonitorSlow"), true, MAKE_PF_CB(process_UBAMonitorSlow)); + register_telegram_type(0x1A, F("UBASetPoints"), false, MAKE_PF_CB(process_UBASetPoints)); register_telegram_type(0x35, F("UBAFlags"), false, MAKE_PF_CB(process_UBAFlags)); // only EMS 1.0 register_telegram_type(0x16, F("UBAParameters"), true, MAKE_PF_CB(process_UBAParameters)); register_telegram_type(0x33, F("UBAParameterWW"), true, MAKE_PF_CB(process_UBAParameterWW)); register_telegram_type(0x34, F("UBAMonitorWW"), false, MAKE_PF_CB(process_UBAMonitorWW)); // only EMS+ - if ((flags & 0x0F) != EMSdevice::EMS_DEVICE_FLAG_EMS) { - register_telegram_type(0x1A, F("UBASetPoints"), false, MAKE_PF_CB(process_UBASetPoints)); + if (model() != EMSdevice::EMS_DEVICE_FLAG_EMS && model() != EMSdevice::EMS_DEVICE_FLAG_HT3) { register_telegram_type(0x26, F("UBASettingsWW"), true, MAKE_PF_CB(process_UBASettingsWW)); register_telegram_type(0x2A, F("MC110Status"), false, MAKE_PF_CB(process_MC110Status)); register_telegram_type(0xD1, F("UBAOutdoorTemp"), false, MAKE_PF_CB(process_UBAOutdoorTemp)); @@ -74,19 +74,20 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const register_telegram_type(0xE6, F("UBAParametersPlus"), true, MAKE_PF_CB(process_UBAParametersPlus)); register_telegram_type(0xE9, F("UBAMonitorWWPlus"), false, MAKE_PF_CB(process_UBAMonitorWWPlus)); register_telegram_type(0xEA, F("UBAParameterWWPlus"), true, MAKE_PF_CB(process_UBAParameterWWPlus)); + } + if (model() == EMSdevice::EMS_DEVICE_FLAG_HEATPUMP) { register_telegram_type(0x494, F("UBAEnergySupplied"), false, MAKE_PF_CB(process_UBAEnergySupplied)); register_telegram_type(0x495, F("UBAInformation"), false, MAKE_PF_CB(process_UBAInformation)); } - // MQTT commands for boiler topic - register_cmd(MQTT_TOPIC(wwtapactivated), MAKE_CF_CB(set_tapwarmwater_activated)); - register_cmd(MQTT_TOPIC(reset), MAKE_CF_CB(set_reset)); + register_device_value(TAG_BOILER_DATA, &dummybool_, DeviceValueType::BOOL, nullptr, FL_(wwtapactivated), DeviceValueUOM::NONE, MAKE_CF_CB(set_tapwarmwater_activated)); + register_device_value(TAG_BOILER_DATA, &dummy8u_, DeviceValueType::ENUM, FL_(enum_reset), FL_(reset), DeviceValueUOM::NONE, MAKE_CF_CB(set_reset)); // add values - reserve_device_values(50); + // reserve_device_values(90); // main - boiler_data topic - register_device_value(TAG_BOILER_DATA, &id_, DeviceValueType::UINT, nullptr, F("id"), nullptr, DeviceValueUOM::NONE); // empty full name to prevent being shown in web or console + register_device_value(TAG_BOILER_DATA, &id_, DeviceValueType::UINT, nullptr, FL_(ID), DeviceValueUOM::NONE); id_ = product_id; register_device_value(TAG_BOILER_DATA, &heatingActive_, DeviceValueType::BOOL, nullptr, FL_(heatingActive), DeviceValueUOM::NONE); @@ -127,61 +128,64 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const register_device_value(TAG_BOILER_DATA, &lastCode_, DeviceValueType::TEXT, nullptr, FL_(lastCode), DeviceValueUOM::NONE); register_device_value(TAG_BOILER_DATA, &serviceCode_, DeviceValueType::TEXT, nullptr, FL_(serviceCode), DeviceValueUOM::NONE); register_device_value(TAG_BOILER_DATA, &serviceCodeNumber_, DeviceValueType::USHORT, nullptr, FL_(serviceCodeNumber), DeviceValueUOM::NONE); - - register_device_value(TAG_BOILER_DATA, &upTimeControl_, DeviceValueType::TIME, FL_(div60), FL_(upTimeControl), DeviceValueUOM::MINUTES); - register_device_value(TAG_BOILER_DATA, &upTimeCompHeating_, DeviceValueType::TIME, FL_(div60), FL_(upTimeCompHeating), DeviceValueUOM::MINUTES); - register_device_value(TAG_BOILER_DATA, &upTimeCompCooling_, DeviceValueType::TIME, FL_(div60), FL_(upTimeCompCooling), DeviceValueUOM::MINUTES); - register_device_value(TAG_BOILER_DATA, &upTimeCompWw_, DeviceValueType::TIME, FL_(div60), FL_(upTimeCompWw), DeviceValueUOM::MINUTES); - register_device_value(TAG_BOILER_DATA, &heatingStarts_, DeviceValueType::ULONG, nullptr, FL_(heatingStarts), DeviceValueUOM::NONE); - register_device_value(TAG_BOILER_DATA, &coolingStarts_, DeviceValueType::ULONG, nullptr, FL_(coolingStarts), DeviceValueUOM::NONE); - register_device_value(TAG_BOILER_DATA, &nrgConsTotal_, DeviceValueType::ULONG, nullptr, FL_(nrgConsTotal), DeviceValueUOM::NONE); - register_device_value(TAG_BOILER_DATA, &nrgConsCompTotal_, DeviceValueType::ULONG, nullptr, FL_(nrgConsCompTotal), DeviceValueUOM::NONE); - register_device_value(TAG_BOILER_DATA, &nrgConsCompHeating_, DeviceValueType::ULONG, nullptr, FL_(nrgConsCompHeating), DeviceValueUOM::NONE); - register_device_value(TAG_BOILER_DATA, &nrgConsCompWw_, DeviceValueType::ULONG, nullptr, FL_(nrgConsCompWw), DeviceValueUOM::NONE); - register_device_value(TAG_BOILER_DATA, &nrgConsCompCooling_, DeviceValueType::ULONG, nullptr, FL_(nrgConsCompCooling), DeviceValueUOM::NONE); - register_device_value(TAG_BOILER_DATA, &nrgSuppTotal_, DeviceValueType::ULONG, nullptr, FL_(nrgSuppTotal), DeviceValueUOM::NONE); - register_device_value(TAG_BOILER_DATA, &nrgSuppHeating_, DeviceValueType::ULONG, nullptr, FL_(nrgSuppHeating), DeviceValueUOM::NONE); - register_device_value(TAG_BOILER_DATA, &nrgSuppWw_, DeviceValueType::ULONG, nullptr, FL_(nrgSuppWw), DeviceValueUOM::NONE); - register_device_value(TAG_BOILER_DATA, &nrgSuppCooling_, DeviceValueType::ULONG, nullptr, FL_(nrgSuppCooling), DeviceValueUOM::NONE); - register_device_value(TAG_BOILER_DATA, &auxElecHeatNrgConsTotal_, DeviceValueType::ULONG, nullptr, FL_(auxElecHeatNrgConsTotal), DeviceValueUOM::NONE); - register_device_value(TAG_BOILER_DATA, &auxElecHeatNrgConsHeating_, DeviceValueType::ULONG, nullptr, FL_(auxElecHeatNrgConsHeating), DeviceValueUOM::NONE); - register_device_value(TAG_BOILER_DATA, &auxElecHeatNrgConsDHW_, DeviceValueType::ULONG, nullptr, FL_(auxElecHeatNrgConsDHW), DeviceValueUOM::NONE); register_device_value(TAG_BOILER_DATA, &maintenanceMessage_, DeviceValueType::TEXT, nullptr, FL_(maintenanceMessage), DeviceValueUOM::NONE); register_device_value(TAG_BOILER_DATA, &maintenanceDate_, DeviceValueType::TEXT, nullptr, FL_(maintenanceDate), DeviceValueUOM::NONE); - register_device_value(TAG_BOILER_DATA, &maintenanceType_, DeviceValueType::ENUM, FL_(enum_off_time_date), FL_(maintenance), DeviceValueUOM::NONE, MAKE_CF_CB(set_maintenance)); + register_device_value(TAG_BOILER_DATA, &maintenanceType_, DeviceValueType::ENUM, FL_(enum_off_time_date), FL_(maintenanceType), DeviceValueUOM::NONE, MAKE_CF_CB(set_maintenance)); register_device_value(TAG_BOILER_DATA, &maintenanceTime_, DeviceValueType::USHORT, nullptr, FL_(maintenanceTime), DeviceValueUOM::HOURS); + // heatpump info + if (model() == EMS_DEVICE_FLAG_HEATPUMP) { + register_device_value(TAG_BOILER_DATA, &upTimeControl_, DeviceValueType::TIME, FL_(div60), FL_(upTimeControl), DeviceValueUOM::MINUTES); + register_device_value(TAG_BOILER_DATA, &upTimeCompHeating_, DeviceValueType::TIME, FL_(div60), FL_(upTimeCompHeating), DeviceValueUOM::MINUTES); + register_device_value(TAG_BOILER_DATA, &upTimeCompCooling_, DeviceValueType::TIME, FL_(div60), FL_(upTimeCompCooling), DeviceValueUOM::MINUTES); + register_device_value(TAG_BOILER_DATA, &upTimeCompWw_, DeviceValueType::TIME, FL_(div60), FL_(upTimeCompWw), DeviceValueUOM::MINUTES); + register_device_value(TAG_BOILER_DATA, &heatingStarts_, DeviceValueType::ULONG, nullptr, FL_(heatingStarts), DeviceValueUOM::NONE); + register_device_value(TAG_BOILER_DATA, &coolingStarts_, DeviceValueType::ULONG, nullptr, FL_(coolingStarts), DeviceValueUOM::NONE); + register_device_value(TAG_BOILER_DATA, &nrgConsTotal_, DeviceValueType::ULONG, nullptr, FL_(nrgConsTotal), DeviceValueUOM::NONE); + register_device_value(TAG_BOILER_DATA, &nrgConsCompTotal_, DeviceValueType::ULONG, nullptr, FL_(nrgConsCompTotal), DeviceValueUOM::NONE); + register_device_value(TAG_BOILER_DATA, &nrgConsCompHeating_, DeviceValueType::ULONG, nullptr, FL_(nrgConsCompHeating), DeviceValueUOM::NONE); + register_device_value(TAG_BOILER_DATA, &nrgConsCompWw_, DeviceValueType::ULONG, nullptr, FL_(nrgConsCompWw), DeviceValueUOM::NONE); + register_device_value(TAG_BOILER_DATA, &nrgConsCompCooling_, DeviceValueType::ULONG, nullptr, FL_(nrgConsCompCooling), DeviceValueUOM::NONE); + register_device_value(TAG_BOILER_DATA, &auxElecHeatNrgConsTotal_, DeviceValueType::ULONG, nullptr, FL_(auxElecHeatNrgConsTotal), DeviceValueUOM::NONE); + register_device_value(TAG_BOILER_DATA, &auxElecHeatNrgConsHeating_, DeviceValueType::ULONG, nullptr, FL_(auxElecHeatNrgConsHeating), DeviceValueUOM::NONE); + register_device_value(TAG_BOILER_DATA, &auxElecHeatNrgConsWW_, DeviceValueType::ULONG, nullptr, FL_(auxElecHeatNrgConsWW), DeviceValueUOM::NONE); + + register_device_value(TAG_BOILER_DATA, &nrgSuppTotal_, DeviceValueType::ULONG, nullptr, FL_(nrgSuppTotal), DeviceValueUOM::NONE); + register_device_value(TAG_BOILER_DATA, &nrgSuppHeating_, DeviceValueType::ULONG, nullptr, FL_(nrgSuppHeating), DeviceValueUOM::NONE); + register_device_value(TAG_BOILER_DATA, &nrgSuppWw_, DeviceValueType::ULONG, nullptr, FL_(nrgSuppWw), DeviceValueUOM::NONE); + register_device_value(TAG_BOILER_DATA, &nrgSuppCooling_, DeviceValueType::ULONG, nullptr, FL_(nrgSuppCooling), DeviceValueUOM::NONE); + } // warm water - boiler_data_ww topic - register_device_value(TAG_BOILER_DATA_WW, &wWSelTemp_, DeviceValueType::UINT, nullptr, FL_(wWSelTemp), DeviceValueUOM::DEGREES); - register_device_value(TAG_BOILER_DATA_WW, &wWSetTemp_, DeviceValueType::UINT, nullptr, FL_(wWSetTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_warmwater_temp)); - register_device_value(TAG_BOILER_DATA_WW, &wWType_, DeviceValueType::ENUM, FL_(enum_flow), FL_(wWType), DeviceValueUOM::NONE); - register_device_value(TAG_BOILER_DATA_WW, &wWComfort_, DeviceValueType::ENUM, FL_(enum_comfort), FL_(wWComfort), DeviceValueUOM::NONE, MAKE_CF_CB(set_warmwater_mode)); - register_device_value(TAG_BOILER_DATA_WW, &wWFlowTempOffset_, DeviceValueType::UINT, nullptr, FL_(wWFlowTempOffset), DeviceValueUOM::NONE, MAKE_CF_CB(set_wWFlowTempOffset)); - register_device_value(TAG_BOILER_DATA_WW, &wWMaxPower_, DeviceValueType::UINT, nullptr, FL_(wWMaxPower), DeviceValueUOM::PERCENT, MAKE_CF_CB(set_warmwater_maxpower)); - register_device_value(TAG_BOILER_DATA_WW, &wWCircPump_, DeviceValueType::BOOL, nullptr, FL_(wWCircPump), DeviceValueUOM::NONE, MAKE_CF_CB(set_warmwater_circulation_pump)); - register_device_value(TAG_BOILER_DATA_WW, &wWChargeType_, DeviceValueType::BOOL, FL_(enum_charge), FL_(wWChargeType), DeviceValueUOM::NONE); - register_device_value(TAG_BOILER_DATA_WW, &wWDisinfectionTemp_, DeviceValueType::UINT, nullptr, FL_(wWDisinfectionTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_disinfect_temp)); - register_device_value(TAG_BOILER_DATA_WW, &wWCircMode_, DeviceValueType::ENUM, FL_(enum_freq), FL_(wWCircMode), DeviceValueUOM::NONE, MAKE_CF_CB(set_warmwater_circulation_mode)); - register_device_value(TAG_BOILER_DATA_WW, &wWCirc_, DeviceValueType::BOOL, nullptr, FL_(wWCirc), DeviceValueUOM::NONE, MAKE_CF_CB(set_warmwater_circulation)); - register_device_value(TAG_BOILER_DATA_WW, &wWCurTemp_, DeviceValueType::USHORT, FL_(div10), FL_(wWCurTemp), DeviceValueUOM::DEGREES); - register_device_value(TAG_BOILER_DATA_WW, &wWCurTemp2_, DeviceValueType::USHORT, FL_(div10), FL_(wWCurTemp2), DeviceValueUOM::DEGREES); - register_device_value(TAG_BOILER_DATA_WW, &wWCurFlow_, DeviceValueType::UINT, FL_(div10), FL_(wWCurFlow), DeviceValueUOM::LMIN); - register_device_value(TAG_BOILER_DATA_WW, &wWStorageTemp1_, DeviceValueType::USHORT, FL_(div10), FL_(wWStorageTemp1), DeviceValueUOM::DEGREES); - register_device_value(TAG_BOILER_DATA_WW, &wWStorageTemp2_, DeviceValueType::USHORT, FL_(div10), FL_(wWStorageTemp2), DeviceValueUOM::DEGREES); - register_device_value(TAG_BOILER_DATA_WW, &wWActivated_, DeviceValueType::BOOL, nullptr, FL_(wWActivated), DeviceValueUOM::NONE, MAKE_CF_CB(set_warmwater_activated)); - register_device_value(TAG_BOILER_DATA_WW, &wWOneTime_, DeviceValueType::BOOL, nullptr, FL_(wWOneTime), DeviceValueUOM::NONE, MAKE_CF_CB(set_warmwater_onetime)); - register_device_value(TAG_BOILER_DATA_WW, &wWDisinfecting_, DeviceValueType::BOOL, nullptr, FL_(wWDisinfecting), DeviceValueUOM::NONE); - register_device_value(TAG_BOILER_DATA_WW, &wWCharging_, DeviceValueType::BOOL, nullptr, FL_(wWCharging), DeviceValueUOM::NONE); - register_device_value(TAG_BOILER_DATA_WW, &wWRecharging_, DeviceValueType::BOOL, nullptr, FL_(wWRecharging), DeviceValueUOM::NONE); - register_device_value(TAG_BOILER_DATA_WW, &wWTempOK_, DeviceValueType::BOOL, nullptr, FL_(wWTempOK), DeviceValueUOM::NONE); - register_device_value(TAG_BOILER_DATA_WW, &wWActive_, DeviceValueType::BOOL, nullptr, FL_(wWActive), DeviceValueUOM::NONE); - register_device_value(TAG_BOILER_DATA_WW, &wWHeat_, DeviceValueType::BOOL, nullptr, FL_(wWHeat), DeviceValueUOM::NONE); - register_device_value(TAG_BOILER_DATA_WW, &wWSetPumpPower_, DeviceValueType::UINT, nullptr, FL_(wWSetPumpPower), DeviceValueUOM::PERCENT); - register_device_value(TAG_BOILER_DATA_WW, &mixerTemp_, DeviceValueType::USHORT, FL_(div10), FL_(mixerTemp), DeviceValueUOM::DEGREES); - register_device_value(TAG_BOILER_DATA_WW, &tankMiddleTemp_, DeviceValueType::USHORT, FL_(div10), FL_(tankMiddleTemp), DeviceValueUOM::DEGREES); - register_device_value(TAG_BOILER_DATA_WW, &wWStarts_, DeviceValueType::ULONG, nullptr, FL_(wWStarts), DeviceValueUOM::NONE); - register_device_value(TAG_BOILER_DATA_WW, &wWStarts2_, DeviceValueType::ULONG, nullptr, FL_(wWStarts2), DeviceValueUOM::NONE); - register_device_value(TAG_BOILER_DATA_WW, &wWWorkM_, DeviceValueType::TIME, nullptr, FL_(wWWorkM), DeviceValueUOM::MINUTES); + register_device_value(TAG_DEVICE_DATA_WW, &wWSelTemp_, DeviceValueType::UINT, nullptr, FL_(wWSelTemp), DeviceValueUOM::DEGREES); + register_device_value(TAG_DEVICE_DATA_WW, &wWSetTemp_, DeviceValueType::UINT, nullptr, FL_(wWSetTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_warmwater_temp)); + register_device_value(TAG_DEVICE_DATA_WW, &wWType_, DeviceValueType::ENUM, FL_(enum_flow), FL_(wWType), DeviceValueUOM::NONE); + register_device_value(TAG_DEVICE_DATA_WW, &wWComfort_, DeviceValueType::ENUM, FL_(enum_comfort), FL_(wWComfort), DeviceValueUOM::NONE, MAKE_CF_CB(set_warmwater_mode)); + register_device_value(TAG_DEVICE_DATA_WW, &wWFlowTempOffset_, DeviceValueType::UINT, nullptr, FL_(wWFlowTempOffset), DeviceValueUOM::NONE, MAKE_CF_CB(set_wWFlowTempOffset)); + register_device_value(TAG_DEVICE_DATA_WW, &wWMaxPower_, DeviceValueType::UINT, nullptr, FL_(wWMaxPower), DeviceValueUOM::PERCENT, MAKE_CF_CB(set_warmwater_maxpower)); + register_device_value(TAG_DEVICE_DATA_WW, &wWCircPump_, DeviceValueType::BOOL, nullptr, FL_(wWCircPump), DeviceValueUOM::NONE, MAKE_CF_CB(set_warmwater_circulation_pump)); + register_device_value(TAG_DEVICE_DATA_WW, &wWChargeType_, DeviceValueType::BOOL, FL_(enum_charge), FL_(wWChargeType), DeviceValueUOM::NONE); + register_device_value(TAG_DEVICE_DATA_WW, &wWDisinfectionTemp_, DeviceValueType::UINT, nullptr, FL_(wWDisinfectionTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_disinfect_temp)); + register_device_value(TAG_DEVICE_DATA_WW, &wWCircMode_, DeviceValueType::ENUM, FL_(enum_freq), FL_(wWCircMode), DeviceValueUOM::NONE, MAKE_CF_CB(set_warmwater_circulation_mode)); + register_device_value(TAG_DEVICE_DATA_WW, &wWCirc_, DeviceValueType::BOOL, nullptr, FL_(wWCirc), DeviceValueUOM::NONE, MAKE_CF_CB(set_warmwater_circulation)); + register_device_value(TAG_DEVICE_DATA_WW, &wWCurTemp_, DeviceValueType::USHORT, FL_(div10), FL_(wWCurTemp), DeviceValueUOM::DEGREES); + register_device_value(TAG_DEVICE_DATA_WW, &wWCurTemp2_, DeviceValueType::USHORT, FL_(div10), FL_(wWCurTemp2), DeviceValueUOM::DEGREES); + register_device_value(TAG_DEVICE_DATA_WW, &wWCurFlow_, DeviceValueType::UINT, FL_(div10), FL_(wWCurFlow), DeviceValueUOM::LMIN); + register_device_value(TAG_DEVICE_DATA_WW, &wWStorageTemp1_, DeviceValueType::USHORT, FL_(div10), FL_(wWStorageTemp1), DeviceValueUOM::DEGREES); + register_device_value(TAG_DEVICE_DATA_WW, &wWStorageTemp2_, DeviceValueType::USHORT, FL_(div10), FL_(wWStorageTemp2), DeviceValueUOM::DEGREES); + register_device_value(TAG_DEVICE_DATA_WW, &wWActivated_, DeviceValueType::BOOL, nullptr, FL_(wWActivated), DeviceValueUOM::NONE, MAKE_CF_CB(set_warmwater_activated)); + register_device_value(TAG_DEVICE_DATA_WW, &wWOneTime_, DeviceValueType::BOOL, nullptr, FL_(wWOneTime), DeviceValueUOM::NONE, MAKE_CF_CB(set_warmwater_onetime)); + register_device_value(TAG_DEVICE_DATA_WW, &wWDisinfecting_, DeviceValueType::BOOL, nullptr, FL_(wWDisinfecting), DeviceValueUOM::NONE); + register_device_value(TAG_DEVICE_DATA_WW, &wWCharging_, DeviceValueType::BOOL, nullptr, FL_(wWCharging), DeviceValueUOM::NONE); + register_device_value(TAG_DEVICE_DATA_WW, &wWRecharging_, DeviceValueType::BOOL, nullptr, FL_(wWRecharging), DeviceValueUOM::NONE); + register_device_value(TAG_DEVICE_DATA_WW, &wWTempOK_, DeviceValueType::BOOL, nullptr, FL_(wWTempOK), DeviceValueUOM::NONE); + register_device_value(TAG_DEVICE_DATA_WW, &wWActive_, DeviceValueType::BOOL, nullptr, FL_(wWActive), DeviceValueUOM::NONE); + register_device_value(TAG_DEVICE_DATA_WW, &wWHeat_, DeviceValueType::BOOL, nullptr, FL_(wWHeat), DeviceValueUOM::NONE); + register_device_value(TAG_DEVICE_DATA_WW, &wWSetPumpPower_, DeviceValueType::UINT, nullptr, FL_(wWSetPumpPower), DeviceValueUOM::PERCENT); + register_device_value(TAG_DEVICE_DATA_WW, &mixerTemp_, DeviceValueType::USHORT, FL_(div10), FL_(mixerTemp), DeviceValueUOM::DEGREES); + register_device_value(TAG_DEVICE_DATA_WW, &tankMiddleTemp_, DeviceValueType::USHORT, FL_(div10), FL_(tankMiddleTemp), DeviceValueUOM::DEGREES); + register_device_value(TAG_DEVICE_DATA_WW, &wWStarts_, DeviceValueType::ULONG, nullptr, FL_(wWStarts), DeviceValueUOM::NONE); + register_device_value(TAG_DEVICE_DATA_WW, &wWStarts2_, DeviceValueType::ULONG, nullptr, FL_(wWStarts2), DeviceValueUOM::NONE); + register_device_value(TAG_DEVICE_DATA_WW, &wWWorkM_, DeviceValueType::TIME, nullptr, FL_(wWWorkM), DeviceValueUOM::MINUTES); // fetch some initial data EMSESP::send_read_request(0x10, device_id); // read last errorcode on start (only published on errors) @@ -210,7 +214,7 @@ bool Boiler::publish_ha_config() { ids.add("ems-esp-boiler"); char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; - snprintf_P(topic, sizeof(topic), PSTR("homeassistant/sensor/%s/boiler/config"), Mqtt::base().c_str()); + snprintf_P(topic, sizeof(topic), PSTR("sensor/%s/boiler/config"), Mqtt::base().c_str()); Mqtt::publish_ha(topic, doc.as()); // publish the config payload with retain flag return true; @@ -545,7 +549,7 @@ void Boiler::process_UBAInformation(std::shared_ptr telegram) { has_update(telegram->read_value(auxElecHeatNrgConsTotal_, 40)); has_update(telegram->read_value(auxElecHeatNrgConsHeating_, 48)); - has_update(telegram->read_value(auxElecHeatNrgConsDHW_, 44)); + has_update(telegram->read_value(auxElecHeatNrgConsWW_, 44)); has_update(telegram->read_value(nrgConsCompTotal_, 56)); has_update(telegram->read_value(nrgConsCompHeating_, 68)); @@ -685,6 +689,7 @@ bool Boiler::set_warmwater_temp(const char * value, const int8_t id) { if (get_toggle_fetch(EMS_TYPE_UBAParametersPlus)) { write_command(EMS_TYPE_UBAParameterWWPlus, 6, v, EMS_TYPE_UBAParameterWWPlus); } else { + // some boiler have it in 0x33, some in 0x35 write_command(EMS_TYPE_UBAFlags, 3, v, 0x34); // for i9000, see #397 write_command(EMS_TYPE_UBAParameterWW, 2, v, EMS_TYPE_UBAParameterWW); // read seltemp back } @@ -718,9 +723,7 @@ bool Boiler::set_flow_temp(const char * value, const int8_t id) { } LOG_INFO(F("Setting boiler flow temperature to %d C"), v); - // some boiler have it in 0x1A, some in 0x35, but both telegrams are sometimes writeonly write_command(EMS_TYPE_UBASetPoints, 0, v, EMS_TYPE_UBASetPoints); - // write_command(0x35, 3, v, 0x35); return true; } @@ -1108,20 +1111,20 @@ bool Boiler::set_warmwater_circulation_mode(const char * value, const int8_t id) } // Reset command -// 0 & 1 Reset-Mode (Manuel, others) +// 0 & 1 Reset-Mode (Manual, others) // 8 reset maintenance message Hxx // 12 & 13 Reset that Error-memory bool Boiler::set_reset(const char * value, const int8_t id) { - std::string s(12, '\0'); - if (!Helpers::value2string(value, s)) { + uint8_t num; + if (!Helpers::value2enum(value, num, FL_(enum_reset))) { return false; } - if (s == Helpers::toLower(uuid::read_flash_string(F_(maintenance)))) { + if (num == 0) { LOG_INFO(F("Reset boiler maintenance message")); write_command(0x05, 0x08, 0xFF, 0x1C); return true; - } else if (s == Helpers::toLower(uuid::read_flash_string(F_(error)))) { + } else if (num == 1) { LOG_INFO(F("Reset boiler error message")); write_command(0x05, 0x00, 0x5A); // error reset return true; diff --git a/src/devices/boiler.h b/src/devices/boiler.h index 97aea088b..fc78d971a 100644 --- a/src/devices/boiler.h +++ b/src/devices/boiler.h @@ -32,6 +32,11 @@ class Boiler : public EMSdevice { private: static uuid::log::Logger logger_; + // specific boiler characteristics, stripping the top 4 bits + inline uint8_t model() const { + return (flags() & 0x0F); + } + void check_active(const bool force = false); uint8_t boilerState_ = EMS_VALUE_UINT_NOTSET; // Boiler state flag - FOR INTERNAL USE @@ -84,6 +89,8 @@ class Boiler : public EMSdevice { // main uint8_t id_; // product id + uint8_t dummy8u_; // for commands with no output + uint8_t dummybool_; // for commands with no output uint8_t heatingActive_; // Central heating is on/off uint8_t tapwaterActive_; // Hot tap water is on/off uint8_t selFlowTemp_; // Selected flow temperature @@ -141,7 +148,7 @@ class Boiler : public EMSdevice { uint32_t nrgSuppCooling_; // Energy supplied cooling uint32_t auxElecHeatNrgConsTotal_; // Auxiliary electrical heater energy consumption total uint32_t auxElecHeatNrgConsHeating_; // Auxiliary electrical heater energy consumption heating - uint32_t auxElecHeatNrgConsDHW_; // Auxiliary electrical heater energy consumption DHW + uint32_t auxElecHeatNrgConsWW_; // Auxiliary electrical heater energy consumption DHW char maintenanceMessage_[4]; char maintenanceDate_[12]; uint8_t maintenanceType_; diff --git a/src/devices/heatpump.cpp b/src/devices/heatpump.cpp index d1bc4f7c1..77544287a 100644 --- a/src/devices/heatpump.cpp +++ b/src/devices/heatpump.cpp @@ -33,7 +33,7 @@ Heatpump::Heatpump(uint8_t device_type, uint8_t device_id, uint8_t product_id, c register_telegram_type(0x047B, F("HP2"), true, MAKE_PF_CB(process_HPMonitor2)); // device values - register_device_value(TAG_NONE, &id_, DeviceValueType::UINT, nullptr, F("id"), nullptr, DeviceValueUOM::NONE); // empty full name to prevent being shown in web or console + register_device_value(TAG_NONE, &id_, DeviceValueType::UINT, nullptr, FL_(ID), DeviceValueUOM::NONE); register_device_value(TAG_NONE, &airHumidity_, DeviceValueType::UINT, FL_(div2), FL_(airHumidity), DeviceValueUOM::PERCENT); register_device_value(TAG_NONE, &dewTemperature_, DeviceValueType::UINT, nullptr, FL_(dewTemperature), DeviceValueUOM::DEGREES); @@ -61,7 +61,7 @@ bool Heatpump::publish_ha_config() { ids.add("ems-esp-heatpump"); char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; - snprintf_P(topic, sizeof(topic), PSTR("homeassistant/sensor/%s/heatpump/config"), Mqtt::base().c_str()); + snprintf_P(topic, sizeof(topic), PSTR("sensor/%s/heatpump/config"), Mqtt::base().c_str()); Mqtt::publish_ha(topic, doc.as()); // publish the config payload with retain flag return true; diff --git a/src/devices/mixer.cpp b/src/devices/mixer.cpp index 4f28ca4e9..88f9af118 100644 --- a/src/devices/mixer.cpp +++ b/src/devices/mixer.cpp @@ -57,7 +57,7 @@ Mixer::Mixer(uint8_t device_type, uint8_t device_id, uint8_t product_id, const s type_ = Type::HC; hc_ = device_id - 0x20 + 1; uint8_t tag = TAG_HC1 + hc_ - 1; - register_device_value(tag, &id_, DeviceValueType::UINT, nullptr, F("id"), nullptr, DeviceValueUOM::NONE); // empty full name to prevent being shown in web or console + register_device_value(tag, &id_, DeviceValueType::UINT, nullptr, FL_(ID), DeviceValueUOM::NONE); register_device_value(tag, &flowSetTemp_, DeviceValueType::UINT, nullptr, FL_(flowSetTemp), DeviceValueUOM::DEGREES); register_device_value(tag, &flowTempHc_, DeviceValueType::USHORT, FL_(div10), FL_(flowTempHc), DeviceValueUOM::DEGREES); register_device_value(tag, &pumpStatus_, DeviceValueType::BOOL, nullptr, FL_(pumpStatus), DeviceValueUOM::PUMP); @@ -67,7 +67,7 @@ Mixer::Mixer(uint8_t device_type, uint8_t device_id, uint8_t product_id, const s type_ = Type::WWC; hc_ = device_id - 0x28 + 1; uint8_t tag = TAG_WWC1 + hc_ - 1; - register_device_value(tag, &id_, DeviceValueType::UINT, nullptr, F("id"), nullptr, DeviceValueUOM::NONE); // empty full name to prevent being shown in web or console + register_device_value(tag, &id_, DeviceValueType::UINT, nullptr, FL_(ID), DeviceValueUOM::NONE); register_device_value(tag, &flowTempHc_, DeviceValueType::USHORT, FL_(div10), FL_(wwTemp), DeviceValueUOM::DEGREES); register_device_value(tag, &pumpStatus_, DeviceValueType::BOOL, nullptr, FL_(pumpStatus), DeviceValueUOM::PUMP); register_device_value(tag, &status_, DeviceValueType::INT, nullptr, FL_(tempStatus), DeviceValueUOM::NONE); @@ -109,9 +109,9 @@ bool Mixer::publish_ha_config() { // determine the topic, if its HC and WWC. This is determined by the incoming telegram types. std::string topic(Mqtt::MQTT_TOPIC_MAX_SIZE, '\0'); if (type_ == Type::HC) { - snprintf_P(&topic[0], topic.capacity() + 1, PSTR("homeassistant/sensor/%s/mixer_hc%d/config"), Mqtt::base().c_str(), hc_); + snprintf_P(&topic[0], topic.capacity() + 1, PSTR("sensor/%s/mixer_hc%d/config"), Mqtt::base().c_str(), hc_); } else { - snprintf_P(&topic[0], topic.capacity() + 1, PSTR("homeassistant/sensor/%s/mixer_wwc%d/config"), Mqtt::base().c_str(), hc_); // WWC + snprintf_P(&topic[0], topic.capacity() + 1, PSTR("sensor/%s/mixer_wwc%d/config"), Mqtt::base().c_str(), hc_); // WWC } Mqtt::publish_ha(topic, doc.as()); // publish the config payload with retain flag diff --git a/src/devices/solar.cpp b/src/devices/solar.cpp index b843d1203..a132a4d8a 100644 --- a/src/devices/solar.cpp +++ b/src/devices/solar.cpp @@ -62,11 +62,18 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const s // special case for a device_id with 0x2A where it's not actual a solar module if (device_id == 0x2A) { - register_device_value(TAG_NONE, &type_, DeviceValueType::TEXT, nullptr, F("type"), F("type"), DeviceValueUOM::NONE); - strncpy(type_, "warm water circuit", sizeof(type_)); + register_device_value(TAG_NONE, &type_, DeviceValueType::TEXT, nullptr, FL_(type), DeviceValueUOM::NONE); + strlcpy(type_, "warm water circuit", sizeof(type_)); + register_device_value(TAG_DEVICE_DATA_WW, &wwTemp_1_, DeviceValueType::UINT, nullptr, FL_(wwTemp1), DeviceValueUOM::DEGREES); + register_device_value(TAG_DEVICE_DATA_WW, &wwTemp_3_, DeviceValueType::UINT, nullptr, FL_(wwTemp3), DeviceValueUOM::DEGREES); + register_device_value(TAG_DEVICE_DATA_WW, &wwTemp_4_, DeviceValueType::UINT, nullptr, FL_(wwTemp4), DeviceValueUOM::DEGREES); + register_device_value(TAG_DEVICE_DATA_WW, &wwTemp_5_, DeviceValueType::UINT, nullptr, FL_(wwTemp5), DeviceValueUOM::DEGREES); + register_device_value(TAG_DEVICE_DATA_WW, &wwTemp_7_, DeviceValueType::UINT, nullptr, FL_(wwTemp7), DeviceValueUOM::DEGREES); + register_device_value(TAG_DEVICE_DATA_WW, &wwPump_, DeviceValueType::UINT, nullptr, FL_(wwPump), DeviceValueUOM::DEGREES); + return; } - register_device_value(TAG_NONE, &id_, DeviceValueType::UINT, nullptr, F("id"), nullptr, DeviceValueUOM::NONE); // empty full name to prevent being shown in web or console + register_device_value(TAG_NONE, &id_, DeviceValueType::UINT, nullptr, FL_(ID), DeviceValueUOM::NONE); id_ = product_id; register_device_value(TAG_NONE, &collectorTemp_, DeviceValueType::SHORT, FL_(div10), FL_(collectorTemp), DeviceValueUOM::DEGREES); @@ -88,6 +95,7 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const s register_device_value(TAG_NONE, &energyLastHour_, DeviceValueType::ULONG, FL_(div10), FL_(energyLastHour), DeviceValueUOM::WH); register_device_value(TAG_NONE, &energyTotal_, DeviceValueType::ULONG, FL_(div10), FL_(energyTotal), DeviceValueUOM::KWH); register_device_value(TAG_NONE, &energyToday_, DeviceValueType::ULONG, nullptr, FL_(energyToday), DeviceValueUOM::WH); + } // publish HA config @@ -110,7 +118,7 @@ bool Solar::publish_ha_config() { ids.add("ems-esp-solar"); char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; - snprintf_P(topic, sizeof(topic), PSTR("homeassistant/sensor/%s/solar/config"), Mqtt::base().c_str()); + snprintf_P(topic, sizeof(topic), PSTR("sensor/%s/solar/config"), Mqtt::base().c_str()); Mqtt::publish_ha(topic, doc.as()); // publish the config payload with retain flag return true; @@ -201,6 +209,22 @@ void Solar::process_SM100Monitor(std::shared_ptr telegram) { has_update(telegram->read_value(heatExchangerTemp_, 20)); // is *10 - TS6: Heat exchanger temperature sensor } +// SM100wwTemperatur - 0x07D6 +// Solar Module(0x2A) -> (0x00), (0x7D6), data: 01 C1 00 00 02 5B 01 AF 01 AD 80 00 01 90 +void Solar::process_SM100wwTemperature(std::shared_ptr telegram) { + has_update(telegram->read_value(wwTemp_1_, 0)); + has_update(telegram->read_value(wwTemp_3_, 4)); + has_update(telegram->read_value(wwTemp_4_, 6)); + has_update(telegram->read_value(wwTemp_5_, 8)); + has_update(telegram->read_value(wwTemp_7_, 12)); +} + +// SM100wwStatus - 0x07AA +// Solar Module(0x2A) -> (0x00), (0x7AA), data: 64 00 04 00 03 00 28 01 0F +void Solar::process_SM100wwStatus(std::shared_ptr telegram) { + has_update(telegram->read_value(wwPump_, 0)); +} + #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" @@ -210,22 +234,6 @@ void Solar::process_SM100Monitor2(std::shared_ptr telegram) { // not implemented yet } -// SM100wwTemperatur - 0x07D6 -// Solar Module(0x2A) -> (0x00), (0x7D6), data: 01 C1 00 00 02 5B 01 AF 01 AD 80 00 01 90 -void Solar::process_SM100wwTemperature(std::shared_ptr telegram) { - // has_update(telegram->read_value(wwTemp_1_, 0)); - // has_update(telegram->read_value(wwTemp_3_, 4)); - // has_update(telegram->read_value(wwTemp_4_, 6)); - // has_update(telegram->read_value(wwTemp_5_, 8)); - // has_update(telegram->read_value(wwTemp_7_, 12)); -} - -// SM100wwStatus - 0x07AA -// Solar Module(0x2A) -> (0x00), (0x7AA), data: 64 00 04 00 03 00 28 01 0F -void Solar::process_SM100wwStatus(std::shared_ptr telegram) { - // has_update(telegram->read_value(wwPump_, 0)); -} - // SM100wwCommand - 0x07AB // Thermostat(0x10) -> Solar Module(0x2A), (0x7AB), data: 01 00 01 void Solar::process_SM100wwCommand(std::shared_ptr telegram) { diff --git a/src/devices/solar.h b/src/devices/solar.h index cd18886c1..d7bb38eb0 100644 --- a/src/devices/solar.h +++ b/src/devices/solar.h @@ -75,6 +75,14 @@ class Solar : public EMSdevice { uint8_t climateZone_; // climate zone identifier uint16_t collector1Area_; // Area of collector field 1 uint8_t collector1Type_; // Type of collector field 1, 01=flat, 02=vacuum + // SM100wwTemperature - 0x07D6 + uint8_t wwTemp_1_; + uint8_t wwTemp_3_; + uint8_t wwTemp_4_; + uint8_t wwTemp_5_; + uint8_t wwTemp_7_; + // SM100wwStatus - 0x07AA + uint8_t wwPump_; char type_[20]; // Solar of WWC uint8_t id_; diff --git a/src/devices/switch.cpp b/src/devices/switch.cpp index c0e8b7c4b..248ab10d4 100644 --- a/src/devices/switch.cpp +++ b/src/devices/switch.cpp @@ -34,7 +34,7 @@ Switch::Switch(uint8_t device_type, uint8_t device_id, uint8_t product_id, const register_telegram_type(0x9D, F("WM10SetMessage"), false, MAKE_PF_CB(process_WM10SetMessage)); register_telegram_type(0x1E, F("WM10TempMessage"), false, MAKE_PF_CB(process_WM10TempMessage)); - register_device_value(TAG_NONE, &id_, DeviceValueType::UINT, nullptr, F("id"), nullptr, DeviceValueUOM::NONE); // empty full name to prevent being shown in web or console + register_device_value(TAG_NONE, &id_, DeviceValueType::UINT, nullptr, FL_(ID), DeviceValueUOM::NONE); register_device_value(TAG_NONE, &activated_, DeviceValueType::BOOL, nullptr, FL_(activated), DeviceValueUOM::NONE); register_device_value(TAG_NONE, &flowTempHc_, DeviceValueType::USHORT, FL_(div10), FL_(flowTempHc), DeviceValueUOM::DEGREES); register_device_value(TAG_NONE, &status_, DeviceValueType::INT, nullptr, FL_(status), DeviceValueUOM::NONE); @@ -66,7 +66,7 @@ bool Switch::publish_ha_config() { ids.add("ems-esp-switch"); char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; - snprintf_P(topic, sizeof(topic), PSTR("homeassistant/sensor/%s/switch/config"), Mqtt::base().c_str()); + snprintf_P(topic, sizeof(topic), PSTR("sensor/%s/switch/config"), Mqtt::base().c_str()); Mqtt::publish_ha(topic, doc.as()); // publish the config payload with retain flag return true; diff --git a/src/devices/thermostat.cpp b/src/devices/thermostat.cpp index 718a467ed..44ed9246e 100644 --- a/src/devices/thermostat.cpp +++ b/src/devices/thermostat.cpp @@ -180,7 +180,9 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i EMSESP::send_read_request(set_typeids[i], device_id); } + EMSESP::send_read_request(EMS_TYPE_RCTime, device_id); EMSESP::send_read_request(0x12, device_id); // read last error (only published on errors) + EMSESP::send_read_request(0xA2, device_id); // read errorCode (only published on errors) } // publish HA config @@ -203,7 +205,7 @@ bool Thermostat::publish_ha_config() { ids.add("ems-esp-thermostat"); char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; - snprintf_P(topic, sizeof(topic), PSTR("homeassistant/sensor/%s/thermostat/config"), Mqtt::base().c_str()); + snprintf_P(topic, sizeof(topic), PSTR("sensor/%s/thermostat/config"), Mqtt::base().c_str()); Mqtt::publish_ha(topic, doc.as()); // publish the config payload with retain flag return true; @@ -420,7 +422,7 @@ void Thermostat::register_mqtt_ha_config_hc(uint8_t hc_num) { ids.add("ems-esp-thermostat"); char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; - snprintf_P(topic, sizeof(topic), PSTR("homeassistant/climate/%s/thermostat_hc%d/config"), Mqtt::base().c_str(), hc_num); + snprintf_P(topic, sizeof(topic), PSTR("climate/%s/thermostat_hc%d/config"), Mqtt::base().c_str(), hc_num); Mqtt::publish_ha(topic, doc.as()); // publish the config payload with retain flag // enable the a special "thermostat_hc" topic to take both mode strings and floats for each of the heating circuits @@ -957,7 +959,7 @@ void Thermostat::process_RC35Set(std::shared_ptr telegram) { has_update(telegram->read_value(hc->reducemode, 25)); // 0-nofrost, 1-reduce, 2-roomhold, 3-outdoorhold has_update(telegram->read_value(hc->control, 26)); // 0-off, 1-RC20 (remote), 2-RC35 has_update(telegram->read_value(hc->controlmode, 33)); // 0-outdoortemp, 1-roomtemp - has_update(telegram->read_value(hc->tempautotemp, 37)); // 0-outdoortemp, 1-roomtemp + has_update(telegram->read_value(hc->tempautotemp, 37)); has_update(telegram->read_value(hc->noreducetemp, 38)); // outdoor temperature for no reduce has_update(telegram->read_value(hc->minflowtemp, 16)); if (hc->heatingtype == 3) { @@ -2070,13 +2072,8 @@ bool Thermostat::set_roominfluence(const char * value, const int8_t id) { // register main device values, top level for all thermostats (excluding heating circuits) // as these are done in void Thermostat::register_device_values_hc() void Thermostat::register_device_values() { - // extra commands - if (!has_flags(EMS_DEVICE_FLAG_NO_WRITE)) { - register_cmd(MQTT_TOPIC(temp), MAKE_CF_CB(set_temp), FLAG_HC); // for backwards compatibility - } - // Common for all thermostats - register_device_value(TAG_THERMOSTAT_DATA, &id_, DeviceValueType::UINT, nullptr, F("id"), nullptr, DeviceValueUOM::NONE); // empty full name to prevent being shown in web or console + register_device_value(TAG_THERMOSTAT_DATA, &id_, DeviceValueType::UINT, nullptr, FL_(ID), DeviceValueUOM::NONE); register_device_value(TAG_THERMOSTAT_DATA, &errorCode_, DeviceValueType::TEXT, nullptr, FL_(errorCode), DeviceValueUOM::NONE); register_device_value(TAG_THERMOSTAT_DATA, &lastCode_, DeviceValueType::TEXT, nullptr, FL_(lastCode), DeviceValueUOM::NONE); @@ -2088,12 +2085,12 @@ void Thermostat::register_device_values() { register_device_value(TAG_THERMOSTAT_DATA, &dampedoutdoortemp2_, DeviceValueType::SHORT, FL_(div10), FL_(dampedoutdoortemp), DeviceValueUOM::DEGREES); register_device_value(TAG_THERMOSTAT_DATA, &floordrytemp_, DeviceValueType::UINT, nullptr, FL_(floordrytemp), DeviceValueUOM::DEGREES); register_device_value(TAG_THERMOSTAT_DATA, &ibaBuildingType_, DeviceValueType::ENUM, FL_(enum_ibaBuildingType), FL_(ibaBuildingType), DeviceValueUOM::NONE, MAKE_CF_CB(set_building)); - register_device_value(TAG_THERMOSTAT_DATA, &wwSetTemp_, DeviceValueType::UINT, nullptr, FL_(wwSetTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_wwtemp)); - register_device_value(TAG_THERMOSTAT_DATA, &wwMode_, DeviceValueType::ENUM, FL_(enum_wwMode), FL_(wwMode), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwmode)); - register_device_value(TAG_THERMOSTAT_DATA, &wwSetTempLow_, DeviceValueType::UINT, nullptr, FL_(wwSetTempLow), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_wwtemplow)); - register_device_value(TAG_THERMOSTAT_DATA, &wwCircMode_, DeviceValueType::ENUM, FL_(enum_wwCircMode), FL_(wWCircMode), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwcircmode)); - register_device_value(TAG_THERMOSTAT_DATA, &wwExtra1_, DeviceValueType::UINT, nullptr, FL_(wwExtra1), DeviceValueUOM::DEGREES); - register_device_value(TAG_THERMOSTAT_DATA, &wwExtra2_, DeviceValueType::UINT, nullptr, FL_(wwExtra2), DeviceValueUOM::DEGREES); + register_device_value(TAG_DEVICE_DATA_WW, &wwSetTemp_, DeviceValueType::UINT, nullptr, FL_(wwSetTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_wwtemp)); + register_device_value(TAG_DEVICE_DATA_WW, &wwMode_, DeviceValueType::ENUM, FL_(enum_wwMode), FL_(wwMode), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwmode)); + register_device_value(TAG_DEVICE_DATA_WW, &wwSetTempLow_, DeviceValueType::UINT, nullptr, FL_(wwSetTempLow), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_wwtemplow)); + register_device_value(TAG_DEVICE_DATA_WW, &wwCircMode_, DeviceValueType::ENUM, FL_(enum_wwCircMode), FL_(wWCircMode), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwcircmode)); + register_device_value(TAG_DEVICE_DATA_WW, &wwExtra1_, DeviceValueType::UINT, nullptr, FL_(wwExtra1), DeviceValueUOM::DEGREES); + register_device_value(TAG_DEVICE_DATA_WW, &wwExtra2_, DeviceValueType::UINT, nullptr, FL_(wwExtra2), DeviceValueUOM::DEGREES); break; case EMS_DEVICE_FLAG_RC20_N: case EMS_DEVICE_FLAG_RC20: @@ -2108,8 +2105,8 @@ void Thermostat::register_device_values() { register_device_value(TAG_THERMOSTAT_DATA, &ibaMinExtTemperature_, DeviceValueType::INT, nullptr, FL_(ibaMinExtTemperature), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_minexttemp)); register_device_value(TAG_THERMOSTAT_DATA, &dampedoutdoortemp_, DeviceValueType::INT, nullptr, FL_(dampedoutdoortemp), DeviceValueUOM::DEGREES); register_device_value(TAG_THERMOSTAT_DATA, &ibaBuildingType_, DeviceValueType::ENUM, FL_(enum_ibaBuildingType2), FL_(ibaBuildingType), DeviceValueUOM::NONE, MAKE_CF_CB(set_building)); - register_device_value(TAG_THERMOSTAT_DATA, &wwMode_, DeviceValueType::ENUM, FL_(enum_wwMode2), FL_(wwMode), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwmode)); - register_device_value(TAG_THERMOSTAT_DATA, &wwCircMode_, DeviceValueType::ENUM, FL_(enum_wwCircMode2), FL_(wWCircMode), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwcircmode)); + register_device_value(TAG_DEVICE_DATA_WW, &wwMode_, DeviceValueType::ENUM, FL_(enum_wwMode2), FL_(wwMode), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwmode)); + register_device_value(TAG_DEVICE_DATA_WW, &wwCircMode_, DeviceValueType::ENUM, FL_(enum_wwCircMode2), FL_(wWCircMode), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwcircmode)); break; case EMS_DEVICE_FLAG_RC35: register_device_value(TAG_THERMOSTAT_DATA, &dateTime_, DeviceValueType::TEXT, nullptr, FL_(dateTime), DeviceValueUOM::NONE, MAKE_CF_CB(set_datetime)); @@ -2119,8 +2116,8 @@ void Thermostat::register_device_values() { register_device_value(TAG_THERMOSTAT_DATA, &tempsensor2_, DeviceValueType::USHORT, FL_(div10), FL_(tempsensor2), DeviceValueUOM::DEGREES); register_device_value(TAG_THERMOSTAT_DATA, &dampedoutdoortemp_, DeviceValueType::INT, nullptr, FL_(dampedoutdoortemp), DeviceValueUOM::DEGREES); register_device_value(TAG_THERMOSTAT_DATA, &ibaBuildingType_, DeviceValueType::ENUM, FL_(enum_ibaBuildingType2), FL_(ibaBuildingType), DeviceValueUOM::NONE, MAKE_CF_CB(set_building)); - register_device_value(TAG_THERMOSTAT_DATA, &wwMode_, DeviceValueType::ENUM, FL_(enum_wwMode2), FL_(wwMode), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwmode)); - register_device_value(TAG_THERMOSTAT_DATA, &wwCircMode_, DeviceValueType::ENUM, FL_(enum_wwCircMode2), FL_(wWCircMode), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwcircmode)); + register_device_value(TAG_DEVICE_DATA_WW, &wwMode_, DeviceValueType::ENUM, FL_(enum_wwMode2), FL_(wwMode), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwmode)); + register_device_value(TAG_DEVICE_DATA_WW, &wwCircMode_, DeviceValueType::ENUM, FL_(enum_wwCircMode2), FL_(wWCircMode), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwcircmode)); break; case EMS_DEVICE_FLAG_JUNKERS: register_device_value(TAG_THERMOSTAT_DATA, &dateTime_, DeviceValueType::TEXT, nullptr, FL_(dateTime), DeviceValueUOM::NONE, MAKE_CF_CB(set_datetime)); @@ -2154,7 +2151,8 @@ void Thermostat::register_device_values_hc(std::shared_ptrsetpoint_roomTemp, DeviceValueType::SHORT, setpoint_temp_divider, FL_(setpoint_roomTemp), DeviceValueUOM::DEGREES); } else { - register_device_value(tag, &hc->setpoint_roomTemp, DeviceValueType::SHORT, setpoint_temp_divider, FL_(setpoint_roomTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_temp)); + register_device_value(tag, &hc->setpoint_roomTemp, DeviceValueType::SHORT, setpoint_temp_divider, FL_(setpoint_roomTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_temp), 5, 29); + register_device_value(tag, &hc->setpoint_roomTemp, DeviceValueType::SHORT, setpoint_temp_divider, FL_(temp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_temp), 5, 29); } register_device_value(tag, &hc->curr_roomTemp, DeviceValueType::SHORT, curr_temp_divider, FL_(curr_roomTemp), DeviceValueUOM::DEGREES); @@ -2167,18 +2165,18 @@ void Thermostat::register_device_values_hc(std::shared_ptrcurr_roomTemp, DeviceValueType::SHORT, curr_temp_divider, F("hatemp"), nullptr, DeviceValueUOM::NONE); + register_device_value(tag, &hc->curr_roomTemp, DeviceValueType::SHORT, curr_temp_divider, FL_(hatemp), DeviceValueUOM::NONE); } else if (option == Mqtt::HA_Climate_Format::SETPOINT) { - register_device_value(tag, &hc->setpoint_roomTemp, DeviceValueType::SHORT, setpoint_temp_divider, F("hatemp"), nullptr, DeviceValueUOM::NONE); + register_device_value(tag, &hc->setpoint_roomTemp, DeviceValueType::SHORT, setpoint_temp_divider, FL_(hatemp), DeviceValueUOM::NONE); } else if (option == Mqtt::HA_Climate_Format::ZERO) { - register_device_value(tag, &zero_value_, DeviceValueType::UINT, nullptr, F("hatemp"), nullptr, DeviceValueUOM::NONE); + register_device_value(tag, &zero_value_, DeviceValueType::UINT, nullptr, FL_(hatemp), DeviceValueUOM::NONE); } // if we're sending to HA the only valid mode types are heat, auto and off // manual & day = heat // night & off = off // everything else auto - register_device_value(tag, &hc->mode, DeviceValueType::ENUM, FL_(enum_hamode), F("hamode"), nullptr, DeviceValueUOM::NONE); + register_device_value(tag, &hc->mode, DeviceValueType::ENUM, FL_(enum_hamode), FL_(hamode), DeviceValueUOM::NONE); } switch (model) { case EMS_DEVICE_FLAG_RC100: @@ -2241,6 +2239,7 @@ void Thermostat::register_device_values_hc(std::shared_ptrtempautotemp, DeviceValueType::UINT, FL_(div2), FL_(tempautotemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_tempautotemp)); register_device_value(tag, &hc->noreducetemp, DeviceValueType::INT, nullptr, FL_(noreducetemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_noreducetemp)); register_device_value(tag, &hc->remotetemp, DeviceValueType::SHORT, FL_(div10), FL_(remotetemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_remotetemp)); + register_device_value(tag, &dummychar_, DeviceValueType::TEXT, nullptr, FL_(switchtime), DeviceValueUOM::NONE, MAKE_CF_CB(set_switchtime)); break; case EMS_DEVICE_FLAG_JUNKERS: register_device_value(tag, &hc->mode, DeviceValueType::ENUM, FL_(enum_mode4), FL_(mode), DeviceValueUOM::NONE, MAKE_CF_CB(set_mode)); diff --git a/src/devices/thermostat.h b/src/devices/thermostat.h index b3edfb62f..c8ef0bd0b 100644 --- a/src/devices/thermostat.h +++ b/src/devices/thermostat.h @@ -37,7 +37,7 @@ class Thermostat : public EMSdevice { int16_t setpoint_roomTemp; int16_t curr_roomTemp; int16_t remotetemp; // for readback - uint8_t tempautotemp; + uint8_t tempautotemp; uint8_t mode; uint8_t modetype; uint8_t summermode; @@ -143,7 +143,8 @@ class Thermostat : public EMSdevice { char dateTime_[25]; // date and time stamp char errorCode_[15]; // code from 0xA2 as string i.e. "A22(816)" uint16_t errorNumber_; // used internally to build error code - char lastCode_[30]; + char lastCode_[30]; // error log + char dummychar_[5]; // for commands with no output // Installation parameters uint8_t ibaMainDisplay_; // display on Thermostat: 0 int temp, 1 int setpoint, 2 ext temp, 3 burner temp, 4 ww temp, 5 functioning mode, 6 time, 7 data, 9 smoke temp diff --git a/src/emsdevice.cpp b/src/emsdevice.cpp index 5cf200c57..7eece5f4d 100644 --- a/src/emsdevice.cpp +++ b/src/emsdevice.cpp @@ -44,7 +44,7 @@ static const __FlashStringHelper * const DeviceValueTAG_s[] PROGMEM = { F_(tag_none), // "" F_(tag_heartbeat), // "" F_(tag_boiler_data), // "" - F_(tag_boiler_data_ww), // "warm water" + F_(tag_device_data_ww), // "warm water" F_(tag_thermostat_data), // "" F_(tag_hc1), // "hc1" F_(tag_hc2), // "hc2" @@ -77,9 +77,9 @@ static const __FlashStringHelper * const DeviceValueTAG_s[] PROGMEM = { static const __FlashStringHelper * const DeviceValueTAG_mqtt[] PROGMEM = { F_(tag_none), // "" - F_(tag_heartbeat_mqtt), // "heartbeat" + F_(heartbeat), // "heartbeat" F_(tag_boiler_data_mqtt), // "" - F_(tag_boiler_data_ww_mqtt), // "ww" + F_(tag_device_data_ww_mqtt), // "ww" F_(tag_thermostat_data), // "" F_(tag_hc1), // "hc1" F_(tag_hc2), // "hc2" @@ -412,9 +412,9 @@ void EMSdevice::register_mqtt_topic(const std::string & topic, mqtt_subfunction_ } // add command to library -void EMSdevice::register_cmd(const __FlashStringHelper * cmd, cmdfunction_p f, uint8_t flag) { - Command::add(device_type_, cmd, f, flag); -} +// void EMSdevice::register_cmd(const __FlashStringHelper * cmd, cmdfunction_p f, uint8_t flag) { +// Command::add(device_type_, cmd, f, flag); +// } // register a callback function for a specific telegram type void EMSdevice::register_telegram_type(const uint16_t telegram_type_id, const __FlashStringHelper * telegram_type_name, bool fetch, process_function_p f) { @@ -437,7 +437,9 @@ void EMSdevice::register_device_value(uint8_t tag, const __FlashStringHelper * short_name, const __FlashStringHelper * full_name, uint8_t uom, - bool has_cmd) { + bool has_cmd, + int32_t min, + uint32_t max) { // init the value depending on it's type if (type == DeviceValueType::TEXT) { *(char *)(value_p) = {'\0'}; @@ -449,8 +451,10 @@ void EMSdevice::register_device_value(uint8_t tag, *(uint16_t *)(value_p) = EMS_VALUE_USHORT_NOTSET; } else if ((type == DeviceValueType::ULONG) || (type == DeviceValueType::TIME)) { *(uint32_t *)(value_p) = EMS_VALUE_ULONG_NOTSET; + } else if (type == DeviceValueType::BOOL) { + *(int8_t *)(value_p) = EMS_VALUE_BOOL_NOTSET; // bool is uint8_t, but other initial value } else { - *(uint8_t *)(value_p) = EMS_VALUE_UINT_NOTSET; // enums, uint8_t, bool behave as uint8_t + *(uint8_t *)(value_p) = EMS_VALUE_UINT_NOTSET; // enums behave as uint8_t } // count #options @@ -462,11 +466,11 @@ void EMSdevice::register_device_value(uint8_t tag, }; } - devicevalues_.emplace_back(device_type_, tag, value_p, type, options, options_size, short_name, full_name, uom, 0, has_cmd); + devicevalues_.emplace_back(device_type_, tag, value_p, type, options, options_size, short_name, full_name, uom, 0, has_cmd, min, max); } -void EMSdevice::register_device_value(uint8_t tag, void * value_p, uint8_t type, const __FlashStringHelper * const * options, const __FlashStringHelper * const * name, uint8_t uom, cmdfunction_p f) { - register_device_value(tag, value_p, type, options, name[0], name[1], uom, (f != nullptr)); +void EMSdevice::register_device_value(uint8_t tag, void * value_p, uint8_t type, const __FlashStringHelper * const * options, const __FlashStringHelper * const * name, uint8_t uom, cmdfunction_p f, int32_t min, uint32_t max) { + register_device_value(tag, value_p, type, options, name[0], name[1], uom, (f != nullptr), min, max); if (f != nullptr) { if (tag >= TAG_HC1 && tag <= TAG_HC4) { Command::add(device_type_, name[0], f, FLAG_HC); @@ -476,11 +480,23 @@ void EMSdevice::register_device_value(uint8_t tag, void * value_p, uint8_t type, } } +void EMSdevice::register_device_value(uint8_t tag, void * value_p, uint8_t type, const __FlashStringHelper * const * options, const __FlashStringHelper * const * name, uint8_t uom, cmdfunction_p f) { + register_device_value(tag, value_p, type, options, name, uom, f, 0, 0); +} + +// void EMSdevice::register_device_value(uint8_t tag, void * value_p, uint8_t type, const __FlashStringHelper * const * options, const __FlashStringHelper * const * name, uint8_t uom, int32_t min, uint32_t max) { +// register_device_value(tag, value_p, type, options, name, uom, nullptr, min, max); +// } + +void EMSdevice::register_device_value(uint8_t tag, void * value_p, uint8_t type, const __FlashStringHelper * const * options, const __FlashStringHelper * const * name, uint8_t uom) { + register_device_value(tag, value_p, type, options, name, uom, nullptr, 0, 0); +} + // looks up the uom (suffix) for a given key from the device value table std::string EMSdevice::get_value_uom(const char * key) { // the key may have a suffix at the start which is between brackets. remove it. char new_key[80]; - strncpy(new_key, key, sizeof(new_key)); + strlcpy(new_key, key, sizeof(new_key)); char * p = new_key; if (key[0] == '(') { while ((*p++ != ')') && (*p != '\0')) @@ -732,7 +748,11 @@ bool EMSdevice::get_value_info(JsonObject & root, const char * cmd, const int8_t json["unit"] = EMSdevice::uom_to_string(dv.uom); } json["writeable"] = dv.has_cmd; - return true; + if (dv.min != 0 || dv.max != 0) { + json["min"] = dv.min; + json["max"] = dv.max; + } + return true; } } return false; @@ -879,7 +899,7 @@ bool EMSdevice::generate_values_json(JsonObject & root, const uint8_t tag_filter } } } - dv.ha |= has_value ? DeviceValueHA::HA_VALUE : DeviceValueHA::HA_NONE; + dv.ha |= has_value ? DeviceValueHA::HA_VALUE : DeviceValueHA::HA_NONE; has_values |= has_value; } diff --git a/src/emsdevice.h b/src/emsdevice.h index c00c792bf..1f0c1560c 100644 --- a/src/emsdevice.h +++ b/src/emsdevice.h @@ -55,61 +55,16 @@ enum DeviceValueType : uint8_t { }; // Unit Of Measurement mapping - maps to DeviceValueUOM_s in emsdevice.cpp -// sequence is important! // uom - also used with HA -MAKE_PSTR(percent, "%") -MAKE_PSTR(degrees, "°C") -MAKE_PSTR(kwh, "kWh") -MAKE_PSTR(wh, "Wh") -MAKE_PSTR(bar, "bar") -MAKE_PSTR(minutes, "minutes") -MAKE_PSTR(hours, "hours") -MAKE_PSTR(ua, "uA") -MAKE_PSTR(lmin, "l/min") +// sequence is important! enum DeviceValueUOM : uint8_t { NONE = 0, DEGREES, PERCENT, LMIN, KWH, WH, HOURS, MINUTES, UA, BAR, PUMP }; // TAG mapping - maps to DeviceValueTAG_s in emsdevice.cpp -// use empty string if want to suppress showing tags -MAKE_PSTR(tag_none, "") -MAKE_PSTR(tag_heartbeat, "") -MAKE_PSTR(tag_boiler_data, "") -MAKE_PSTR(tag_boiler_data_ww, "warm water") -MAKE_PSTR(tag_thermostat_data, "") -MAKE_PSTR(tag_hc1, "hc1") -MAKE_PSTR(tag_hc2, "hc2") -MAKE_PSTR(tag_hc3, "hc3") -MAKE_PSTR(tag_hc4, "hc4") -MAKE_PSTR(tag_wwc1, "wwc1") -MAKE_PSTR(tag_wwc2, "wwc2") -MAKE_PSTR(tag_wwc3, "wwc3") -MAKE_PSTR(tag_wwc4, "wwc4") -MAKE_PSTR(tag_hs1, "hs1") -MAKE_PSTR(tag_hs2, "hs2") -MAKE_PSTR(tag_hs3, "hs3") -MAKE_PSTR(tag_hs4, "hs4") -MAKE_PSTR(tag_hs5, "hs5") -MAKE_PSTR(tag_hs6, "hs6") -MAKE_PSTR(tag_hs7, "hs7") -MAKE_PSTR(tag_hs8, "hs8") -MAKE_PSTR(tag_hs9, "hs9") -MAKE_PSTR(tag_hs10, "hs10") -MAKE_PSTR(tag_hs11, "hs11") -MAKE_PSTR(tag_hs12, "hs12") -MAKE_PSTR(tag_hs13, "hs13") -MAKE_PSTR(tag_hs14, "hs14") -MAKE_PSTR(tag_hs15, "hs15") -MAKE_PSTR(tag_hs16, "hs16") - -// MQTT topic names -MAKE_PSTR(tag_heartbeat_mqtt, "heartbeat") -MAKE_PSTR(tag_boiler_data_mqtt, "") -MAKE_PSTR(tag_boiler_data_ww_mqtt, "ww") - enum DeviceValueTAG : uint8_t { TAG_NONE = 0, // wild card TAG_HEARTBEAT, TAG_BOILER_DATA, - TAG_BOILER_DATA_WW, + TAG_DEVICE_DATA_WW, TAG_THERMOSTAT_DATA, TAG_HC1, TAG_HC2, @@ -274,8 +229,13 @@ class EMSdevice { const __FlashStringHelper * short_name, const __FlashStringHelper * full_name, uint8_t uom, - bool has_cmd = false); - void register_device_value(uint8_t tag, void * value_p, uint8_t type, const __FlashStringHelper * const * options, const __FlashStringHelper * const * name, uint8_t uom, cmdfunction_p f = nullptr); + bool has_cmd, + int32_t min, + uint32_t max); + void register_device_value(uint8_t tag, void * value_p, uint8_t type, const __FlashStringHelper * const * options, const __FlashStringHelper * const * name, uint8_t uom, cmdfunction_p f, int32_t min, uint32_t max); + void register_device_value(uint8_t tag, void * value_p, uint8_t type, const __FlashStringHelper * const * options, const __FlashStringHelper * const * name, uint8_t uom, cmdfunction_p f); + void register_device_value(uint8_t tag, void * value_p, uint8_t type, const __FlashStringHelper * const * options, const __FlashStringHelper * const * name, uint8_t uom); + // void register_device_value(uint8_t tag, void * value_p, uint8_t type, const __FlashStringHelper * const * options, const __FlashStringHelper * const * name, uint8_t uom, int32_t min, uint32_t max); void write_command(const uint16_t type_id, const uint8_t offset, uint8_t * message_data, const uint8_t message_length, const uint16_t validate_typeid); void write_command(const uint16_t type_id, const uint8_t offset, const uint8_t value, const uint16_t validate_typeid); @@ -283,7 +243,7 @@ class EMSdevice { void read_command(const uint16_t type_id, uint8_t offset = 0, uint8_t length = 0); void register_mqtt_topic(const std::string & topic, mqtt_subfunction_p f); - void register_cmd(const __FlashStringHelper * cmd, cmdfunction_p f, uint8_t flag = 0); + // void register_cmd(const __FlashStringHelper * cmd, cmdfunction_p f, uint8_t flag = 0); void publish_mqtt_ha_sensor(); @@ -342,7 +302,10 @@ class EMSdevice { static constexpr uint8_t EMS_DEVICE_FLAG_NONE = 0; // Boiler - static constexpr uint8_t EMS_DEVICE_FLAG_EMS = 1; + static constexpr uint8_t EMS_DEVICE_FLAG_EMS = 1; + static constexpr uint8_t EMS_DEVICE_FLAG_EMSPLUS = 2; + static constexpr uint8_t EMS_DEVICE_FLAG_HT3 = 3; + static constexpr uint8_t EMS_DEVICE_FLAG_HEATPUMP = 4; // Solar Module static constexpr uint8_t EMS_DEVICE_FLAG_SM10 = 1; @@ -415,6 +378,8 @@ class EMSdevice { uint8_t uom; // DeviceValueUOM::* uint8_t ha; // DevcieValueHA:: bool has_cmd; // true if there is a Console/MQTT command which matches the short_name + int32_t min; + uint32_t max; DeviceValue(uint8_t device_type, uint8_t tag, @@ -426,7 +391,9 @@ class EMSdevice { const __FlashStringHelper * full_name, uint8_t uom, uint8_t ha, - bool has_cmd) + bool has_cmd, + int32_t min, + uint32_t max) : device_type(device_type) , tag(tag) , value_p(value_p) @@ -437,7 +404,9 @@ class EMSdevice { , full_name(full_name) , uom(uom) , ha(ha) - , has_cmd(has_cmd) { + , has_cmd(has_cmd) + , min(min) + , max(max) { } }; const std::vector devicevalues() const; diff --git a/src/emsesp.cpp b/src/emsesp.cpp index 97b62cf4c..9972933e1 100644 --- a/src/emsesp.cpp +++ b/src/emsesp.cpp @@ -450,8 +450,8 @@ void EMSESP::publish_device_values(uint8_t device_type) { emsdevice->generate_values_json(json, DeviceValueTAG::TAG_BOILER_DATA, false); Mqtt::publish(Mqtt::tag_to_topic(device_type, DeviceValueTAG::TAG_BOILER_DATA), json); json.clear(); - emsdevice->generate_values_json(json, DeviceValueTAG::TAG_BOILER_DATA_WW, false); - Mqtt::publish(Mqtt::tag_to_topic(device_type, DeviceValueTAG::TAG_BOILER_DATA_WW), json); + emsdevice->generate_values_json(json, DeviceValueTAG::TAG_DEVICE_DATA_WW, false); + Mqtt::publish(Mqtt::tag_to_topic(device_type, DeviceValueTAG::TAG_DEVICE_DATA_WW), json); need_publish = false; } @@ -544,7 +544,7 @@ void EMSESP::publish_response(std::shared_ptr telegram) { doc["value"] = value; } - Mqtt::publish(F("response"), doc.as()); + Mqtt::publish(F_(response), doc.as()); } bool EMSESP::get_device_value_info(JsonObject & root, const char * cmd, const int8_t id, const uint8_t devicetype) { diff --git a/src/locale_EN.h b/src/locale_EN.h index df1edd2aa..a44fff268 100644 --- a/src/locale_EN.h +++ b/src/locale_EN.h @@ -149,6 +149,54 @@ MAKE_PSTR_LIST(div10, F_(10)) MAKE_PSTR_LIST(div100, F_(100)) MAKE_PSTR_LIST(div60, F_(60)) +// Unit Of Measurement mapping - maps to DeviceValueUOM_s in emsdevice.cpp +// uom - also used with HA +MAKE_PSTR(percent, "%") +MAKE_PSTR(degrees, "°C") +MAKE_PSTR(kwh, "kWh") +MAKE_PSTR(wh, "Wh") +MAKE_PSTR(bar, "bar") +MAKE_PSTR(minutes, "minutes") +MAKE_PSTR(hours, "hours") +MAKE_PSTR(ua, "uA") +MAKE_PSTR(lmin, "l/min") + +// TAG mapping - maps to DeviceValueTAG_s in emsdevice.cpp +// use empty string if want to suppress showing tags +MAKE_PSTR(tag_none, "") +MAKE_PSTR(tag_heartbeat, "") +MAKE_PSTR(tag_boiler_data, "") +MAKE_PSTR(tag_device_data_ww, "warm water") +MAKE_PSTR(tag_thermostat_data, "") +MAKE_PSTR(tag_hc1, "hc1") +MAKE_PSTR(tag_hc2, "hc2") +MAKE_PSTR(tag_hc3, "hc3") +MAKE_PSTR(tag_hc4, "hc4") +MAKE_PSTR(tag_wwc1, "wwc1") +MAKE_PSTR(tag_wwc2, "wwc2") +MAKE_PSTR(tag_wwc3, "wwc3") +MAKE_PSTR(tag_wwc4, "wwc4") +MAKE_PSTR(tag_hs1, "hs1") +MAKE_PSTR(tag_hs2, "hs2") +MAKE_PSTR(tag_hs3, "hs3") +MAKE_PSTR(tag_hs4, "hs4") +MAKE_PSTR(tag_hs5, "hs5") +MAKE_PSTR(tag_hs6, "hs6") +MAKE_PSTR(tag_hs7, "hs7") +MAKE_PSTR(tag_hs8, "hs8") +MAKE_PSTR(tag_hs9, "hs9") +MAKE_PSTR(tag_hs10, "hs10") +MAKE_PSTR(tag_hs11, "hs11") +MAKE_PSTR(tag_hs12, "hs12") +MAKE_PSTR(tag_hs13, "hs13") +MAKE_PSTR(tag_hs14, "hs14") +MAKE_PSTR(tag_hs15, "hs15") +MAKE_PSTR(tag_hs16, "hs16") + +// MQTT topic names +// MAKE_PSTR(tag_heartbeat_mqtt, "heartbeat") +MAKE_PSTR(tag_boiler_data_mqtt, "") +MAKE_PSTR(tag_device_data_ww_mqtt, "ww") // boiler MAKE_PSTR_WORD(time) @@ -169,6 +217,8 @@ MAKE_PSTR_WORD(flow) MAKE_PSTR_WORD(buffer) MAKE_PSTR(bufferedflow, "buffered flow") MAKE_PSTR(layeredbuffer, "layered buffer") +MAKE_PSTR_WORD(maintenance) +MAKE_PSTR_WORD(error) // boiler lists MAKE_PSTR_LIST(enum_off_time_date, F_(off), F_(time), F_(date)) @@ -176,6 +226,7 @@ MAKE_PSTR_LIST(enum_freq, F_(off), F_(1x3min), F_(2x3min), F_(3x3min), F_(4x3min MAKE_PSTR_LIST(enum_charge, F_(3wayvalve), F_(chargepump)) MAKE_PSTR_LIST(enum_comfort, F_(hot), F_(eco), F_(intelligent)) MAKE_PSTR_LIST(enum_flow, F_(off), F_(flow), F_(bufferedflow), F_(buffer), F_(layeredbuffer)) +MAKE_PSTR_LIST(enum_reset, F_(maintenance), F_(error)) // thermostat MAKE_PSTR_WORD(light) @@ -205,6 +256,7 @@ MAKE_PSTR_WORD(room) MAKE_PSTR_WORD(power) MAKE_PSTR_WORD(constant) MAKE_PSTR_WORD(simple) +MAKE_PSTR_WORD(optimized) MAKE_PSTR_WORD(nofrost) MAKE_PSTR_WORD(comfort) MAKE_PSTR_WORD(manual) @@ -221,7 +273,6 @@ MAKE_PSTR_WORD(maxflow) MAKE_PSTR_WORD(rc3x) MAKE_PSTR_WORD(rc20) -MAKE_PSTR_WORD(error) MAKE_PSTR(internal_temperature, "internal temperature") MAKE_PSTR(internal_setpoint, "internal setpoint") MAKE_PSTR(external_temperature, "external temperature") @@ -255,8 +306,9 @@ MAKE_PSTR_LIST(enum_modetype4, F_(blank), F_(nofrost), F_(eco), F_(heat)) MAKE_PSTR_LIST(enum_reducemode, F_(nofrost), F_(reduce), F_(room), F_(outdoor)) -MAKE_PSTR_LIST(enum_controlmode, F_(off), F_(outdoor), F_(simple), F_(mpc), F_(room), F_(power), F_(constant)) +MAKE_PSTR_LIST(enum_controlmode, F_(off), F_(optimized), F_(simple), F_(mpc), F_(room), F_(power), F_(constant)) MAKE_PSTR_LIST(enum_controlmode2, F_(outdoor), F_(room)) +MAKE_PSTR_LIST(enum_controlmode3, F_(off), F_(room), F_(outdoor), F("room+outdoor")) MAKE_PSTR_LIST(enum_control, F_(off), F_(rc20), F_(rc3x)) MAKE_PSTR_LIST(enum_hamode, F_(off), F_(heat), F_(auto), F_(heat), F_(off), F_(heat), F_(auto), F_(auto), F_(auto), F_(auto)) @@ -264,15 +316,21 @@ MAKE_PSTR_LIST(enum_hamode, F_(off), F_(heat), F_(auto), F_(heat), F_(off), F_(h /* * MQTT topics and full text for values and commands */ +MAKE_PSTR(homeassistant, "homeassistant/") + +// if for all devices +// empty full name to prevent being shown in web or console +MAKE_PSTR_LIST(ID, F_(id)) // Boiler -// extra commands +// extra commands, no output MAKE_PSTR_LIST(wwtapactivated, F("wwtapactivated")) MAKE_PSTR_LIST(reset, F("reset")) // single mqtt topics -MAKE_PSTR(heating_active, "heating_active") -MAKE_PSTR(tapwater_active, "tapwater_active") +MAKE_PSTR_WORD(heating_active) +MAKE_PSTR_WORD(tapwater_active) +MAKE_PSTR_WORD(response) // mqtt, commands and text MAKE_PSTR_LIST(heatingActive, F("heatingactive"), F("heating active")) @@ -313,6 +371,10 @@ MAKE_PSTR_LIST(UBAuptime, F("ubauptime"), F("total UBA operating time")) MAKE_PSTR_LIST(lastCode, F("lastcode"), F("last error code")) MAKE_PSTR_LIST(serviceCode, F("servicecode"), F("service code")) MAKE_PSTR_LIST(serviceCodeNumber, F("servicecodenumber"), F("service code number")) +MAKE_PSTR_LIST(maintenanceMessage, F("maintenancemessage"), F("maintenance message")) +MAKE_PSTR_LIST(maintenanceDate, F("maintenancedate"), F("maintenance set date")) +MAKE_PSTR_LIST(maintenanceType, F_(maintenance), F("maintenance scheduled")) +MAKE_PSTR_LIST(maintenanceTime, F("maintenancetime"), F("maintenance set time")) MAKE_PSTR_LIST(upTimeControl, F("uptimecontrol"), F("operating time total heat")) MAKE_PSTR_LIST(upTimeCompHeating, F("uptimecompheating"), F("operating time compressor heating")) @@ -331,11 +393,7 @@ MAKE_PSTR_LIST(nrgSuppWw, F("nrgsuppww"), F("total energy warm supplied warm wat MAKE_PSTR_LIST(nrgSuppCooling, F("nrgsuppcooling"), F("total energy supplied cooling")) MAKE_PSTR_LIST(auxElecHeatNrgConsTotal, F("auxelecheatnrgconstotal"), F("auxiliary electrical heater energy consumption total")) MAKE_PSTR_LIST(auxElecHeatNrgConsHeating, F("auxelecheatnrgconsheating"), F("auxiliary electrical heater energy consumption heating")) -MAKE_PSTR_LIST(auxElecHeatNrgConsDHW, F("auxelecheatnrgconsww"), F("auxiliary electrical heater energy consumption DHW")) -MAKE_PSTR_LIST(maintenanceMessage, F("maintenancemessage"), F("maintenance message")) -MAKE_PSTR_LIST(maintenanceDate, F("maintenancedate"), F("maintenance set date")) -MAKE_PSTR_LIST(maintenance, F("maintenance"), F("maintenance scheduled")) -MAKE_PSTR_LIST(maintenanceTime, F("maintenancetime"), F("maintenance set time")) +MAKE_PSTR_LIST(auxElecHeatNrgConsWW, F("auxelecheatnrgconsww"), F("auxiliary electrical heater energy consumption")) MAKE_PSTR_LIST(wWSelTemp, F("wwseltemp"), F("selected temperature")) MAKE_PSTR_LIST(wWSetTemp, F("wwsettemp"), F("set temperature")) @@ -370,9 +428,10 @@ MAKE_PSTR_LIST(wWWorkM, F("wwworkm"), F("active time")) // thermostat // extra commands, not published yet -MAKE_PSTR_LIST(remoteTemp, F("remotetemp"), F("remotetemp")) MAKE_PSTR_LIST(switchtime, F("switchtime"), F("switchtime")) MAKE_PSTR_LIST(temp, F("temp"), F("temporary set temperature")) +MAKE_PSTR_LIST(hatemp, F("hatemp"), F("homeassistant temperature")) +MAKE_PSTR_LIST(hamode, F("hamode"), F("homeassistent mode")) // mqtt values / commands MAKE_PSTR_LIST(dateTime, F("datetime"), F("date/time")) @@ -392,11 +451,12 @@ MAKE_PSTR_LIST(dampedoutdoortemp, F("dampedoutdoortemp"), F("damped outdoor temp MAKE_PSTR_LIST(floordrystatus, F("floordry"), F("floor drying")) MAKE_PSTR_LIST(dampedoutdoortemp2, F("dampedoutdoortemp"), F("damped outdoor temperature")) MAKE_PSTR_LIST(floordrytemp, F("floordrytemp"), F("floor drying temperature")) -MAKE_PSTR_LIST(wwMode, F("wwmode"), F("warm water mode")) -MAKE_PSTR_LIST(wwSetTemp, F("wwsettemp"), F("warm water set temperature")) -MAKE_PSTR_LIST(wwSetTempLow, F("wwsettemplow"), F("warm water set temperature low")) -MAKE_PSTR_LIST(wwExtra1, F("wwextra1"), F("warm water circuit 1 extra")) -MAKE_PSTR_LIST(wwExtra2, F("wwextra2"), F("warm water circuit 2 extra")) + +MAKE_PSTR_LIST(wwMode, F("wwmode"), F("mode")) +MAKE_PSTR_LIST(wwSetTemp, F("wwsettemp"), F("set temperature")) +MAKE_PSTR_LIST(wwSetTempLow, F("wwsettemplow"), F("set temperature low")) +MAKE_PSTR_LIST(wwExtra1, F("wwextra1"), F("circuit 1 extra")) +MAKE_PSTR_LIST(wwExtra2, F("wwextra2"), F("circuit 2 extra")) MAKE_PSTR_LIST(setpoint_roomTemp, F("seltemp"), F("selected room temperature")) MAKE_PSTR_LIST(curr_roomTemp, F("currtemp"), F("current room temperature")) @@ -450,6 +510,7 @@ MAKE_PSTR_LIST(tempStatus, F("tempstatus"), F("temperature switch in assigned hc MAKE_PSTR_LIST(wwTemp, F("wwtemp"), F("current warm water temperature")) // solar +MAKE_PSTR_LIST(type, F("type"), F("type")) MAKE_PSTR_LIST(collectorTemp, F("collectortemp"), F("collector temperature (TS1)")) MAKE_PSTR_LIST(tankBottomTemp, F("tankbottomtemp"), F("tank bottom temperature (TS2)")) MAKE_PSTR_LIST(tank2BottomTemp, F("tank2bottomtemp"), F("second tank bottom temperature (TS5)")) @@ -470,6 +531,13 @@ MAKE_PSTR_LIST(energyLastHour, F("energylasthour"), F("energy last hour")) MAKE_PSTR_LIST(energyTotal, F("energytotal"), F("energy total")) MAKE_PSTR_LIST(energyToday, F("energytoday"), F("energy today")) +MAKE_PSTR_LIST(wwTemp1, F("wwtemp1"), F("temperature 1")) +MAKE_PSTR_LIST(wwTemp3, F("wwtemp3"), F("temperature 3")) +MAKE_PSTR_LIST(wwTemp4, F("wwtemp4"), F("temperature 4")) +MAKE_PSTR_LIST(wwTemp5, F("wwtemp5"), F("temperature 5")) +MAKE_PSTR_LIST(wwTemp7, F("wwtemp7"), F("temperature 7")) +MAKE_PSTR_LIST(wwPump, F("wwpump"), F("pump")) + // switch MAKE_PSTR_LIST(activated, F("activated"), F("activated")) MAKE_PSTR_LIST(status, F("status"), F("status")) diff --git a/src/mqtt.cpp b/src/mqtt.cpp index 470a8d04c..b701929b1 100644 --- a/src/mqtt.cpp +++ b/src/mqtt.cpp @@ -313,7 +313,7 @@ void Mqtt::on_message(const char * fulltopic, const char * payload, size_t len) if (mf.mqtt_subfunction_) { if (!(mf.mqtt_subfunction_)(message)) { LOG_ERROR(F("MQTT error: invalid payload %s for this topic %s"), message, topic); - Mqtt::publish(F("response"), "invalid"); + Mqtt::publish(F_(response), "invalid"); } return; } @@ -336,7 +336,7 @@ void Mqtt::on_message(const char * fulltopic, const char * payload, size_t len) // LOG_INFO(F("devicetype= %d, topic = %s, cmd = %s, message = %s, id = %d"), mf.device_type_, topic, cmd_only, message, id); if (!Command::call(mf.device_type_, cmd_only, message, id)) { LOG_ERROR(F("No matching cmd (%s) in topic %s, id %d, or invalid data"), cmd_only, topic, id); - Mqtt::publish(F("response"), "unknown"); + Mqtt::publish(F_(response), "unknown"); } return; } @@ -380,14 +380,14 @@ void Mqtt::on_message(const char * fulltopic, const char * payload, size_t len) JsonObject json = resp.to(); cmd_known = Command::call(mf.device_type_, command, "", n, json); if (cmd_known && json.size()) { - Mqtt::publish(F("response"), resp.as()); + Mqtt::publish(F_(response), resp.as()); return; } } if (!cmd_known) { LOG_ERROR(F("No matching cmd (%s) or invalid data"), command); - Mqtt::publish(F("response"), "unknown"); + Mqtt::publish(F_(response), "unknown"); } return; @@ -681,7 +681,7 @@ void Mqtt::ha_status() { ids.add("ems-esp"); char topic[MQTT_TOPIC_MAX_SIZE]; - snprintf_P(topic, sizeof(topic), PSTR("homeassistant/sensor/%s/system/config"), mqtt_base_.c_str()); + snprintf_P(topic, sizeof(topic), PSTR("sensor/%s/system/config"), mqtt_base_.c_str()); Mqtt::publish_ha(topic, doc.as()); // publish the config payload with retain flag // create the sensors @@ -798,14 +798,15 @@ void Mqtt::publish_ha(const std::string & topic, const JsonObject & payload) { payload_text.reserve(measureJson(payload) + 1); serializeJson(payload, payload_text); // convert json to string + std::string fulltopic = uuid::read_flash_string(F_(homeassistant)) + topic; #if defined(EMSESP_STANDALONE) - LOG_DEBUG(F("Publishing HA topic=%s, payload=%s"), topic.c_str(), payload_text.c_str()); + LOG_DEBUG(F("Publishing HA topic=%s, payload=%s"), fulltopic.c_str(), payload_text.c_str()); #elif defined(EMSESP_DEBUG) - LOG_DEBUG(F("[debug] Publishing HA topic=%s, payload=%s"), topic.c_str(), payload_text.c_str()); + LOG_DEBUG(F("[debug] Publishing HA topic=%s, payload=%s"), fulltopic.c_str(), payload_text.c_str()); #endif // queue messages if the MQTT connection is not yet established. to ensure we don't miss messages - queue_publish_message(topic, payload_text, true); // with retain true + queue_publish_message(fulltopic, payload_text, true); // with retain true } // take top from queue and perform the publish or subscribe action @@ -819,7 +820,7 @@ void Mqtt::process_queue() { auto mqtt_message = mqtt_messages_.front(); auto message = mqtt_message.content_; char topic[MQTT_TOPIC_MAX_SIZE]; - if ((strncmp(message->topic.c_str(), "homeassistant/", 13) == 0)) { + if (message->topic.find(uuid::read_flash_string(F_(homeassistant))) == 0) { // leave topic as it is strcpy(topic, message->topic.c_str()); } else { @@ -914,7 +915,7 @@ void Mqtt::publish_mqtt_ha_sensor(uint8_t type, // EMSdevice // device name char device_name[50]; - strncpy(device_name, EMSdevice::device_type_2_device_name(device_type).c_str(), sizeof(device_name)); + strlcpy(device_name, EMSdevice::device_type_2_device_name(device_type).c_str(), sizeof(device_name)); // build unique identifier which will be used in the topic // and replacing all . with _ as not to break HA @@ -954,7 +955,7 @@ void Mqtt::publish_mqtt_ha_sensor(uint8_t type, // EMSdevice // look at the device value type if (type == DeviceValueType::BOOL) { // binary sensor - snprintf_P(topic, sizeof(topic), PSTR("homeassistant/binary_sensor/%s/%s/config"), mqtt_base_.c_str(), uniq.c_str()); // topic + snprintf_P(topic, sizeof(topic), PSTR("binary_sensor/%s/%s/config"), mqtt_base_.c_str(), uniq.c_str()); // topic // how to render boolean. HA only accepts String values char result[10]; @@ -962,7 +963,7 @@ void Mqtt::publish_mqtt_ha_sensor(uint8_t type, // EMSdevice doc[F("payload_off")] = Helpers::render_boolean(result, false); } else { // normal HA sensor, not a boolean one - snprintf_P(topic, sizeof(topic), PSTR("homeassistant/sensor/%s/%s/config"), mqtt_base_.c_str(), uniq.c_str()); // topic + snprintf_P(topic, sizeof(topic), PSTR("sensor/%s/%s/config"), mqtt_base_.c_str(), uniq.c_str()); // topic // unit of measure and map the HA icon if (uom != DeviceValueUOM::NONE && uom != DeviceValueUOM::PUMP) { @@ -996,6 +997,7 @@ void Mqtt::publish_mqtt_ha_sensor(uint8_t type, // EMSdevice ids.add(ha_device); } + doc.shrinkToFit(); publish_ha(topic, doc.as()); } diff --git a/src/shower.cpp b/src/shower.cpp index c4e138073..6e0871e95 100644 --- a/src/shower.cpp +++ b/src/shower.cpp @@ -123,7 +123,7 @@ void Shower::send_mqtt_stat(bool state, bool force) { ids.add("ems-esp"); char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; - snprintf_P(topic, sizeof(topic), PSTR("homeassistant/binary_sensor/%s/shower_active/config"), Mqtt::base().c_str()); + snprintf_P(topic, sizeof(topic), PSTR("binary_sensor/%s/shower_active/config"), Mqtt::base().c_str()); Mqtt::publish_ha(topic, doc.as()); // publish the config payload with retain flag } } From 903696726cfa3ebc2152d99738c18fe45faf4ddb Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Sat, 24 Apr 2021 21:05:10 +0200 Subject: [PATCH 2/3] do not show hatemp, etc. --- src/locale_EN.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/locale_EN.h b/src/locale_EN.h index a44fff268..f4d4ad6c3 100644 --- a/src/locale_EN.h +++ b/src/locale_EN.h @@ -427,11 +427,11 @@ MAKE_PSTR_LIST(wWStarts2, F("wwstarts2"), F("# control starts")) MAKE_PSTR_LIST(wWWorkM, F("wwworkm"), F("active time")) // thermostat -// extra commands, not published yet -MAKE_PSTR_LIST(switchtime, F("switchtime"), F("switchtime")) -MAKE_PSTR_LIST(temp, F("temp"), F("temporary set temperature")) -MAKE_PSTR_LIST(hatemp, F("hatemp"), F("homeassistant temperature")) -MAKE_PSTR_LIST(hamode, F("hamode"), F("homeassistent mode")) +// extra commands, no long name, does not show on web +MAKE_PSTR_LIST(switchtime, F("switchtime")) +MAKE_PSTR_LIST(temp, F("temp")) +MAKE_PSTR_LIST(hatemp, F("hatemp")) +MAKE_PSTR_LIST(hamode, F("hamode")) // mqtt values / commands MAKE_PSTR_LIST(dateTime, F("datetime"), F("date/time")) From 018b4af8d33957f257b73632a2be5381d9aba5ab Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Sat, 24 Apr 2021 21:05:34 +0200 Subject: [PATCH 3/3] value_info bool format --- src/emsdevice.cpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/emsdevice.cpp b/src/emsdevice.cpp index 7eece5f4d..000e97eb8 100644 --- a/src/emsdevice.cpp +++ b/src/emsdevice.cpp @@ -720,12 +720,29 @@ bool EMSdevice::get_value_info(JsonObject & root, const char * cmd, const int8_t json["min"] = 0; json["max"] = divider ? EMS_VALUE_ULONG_NOTSET / divider : EMS_VALUE_ULONG_NOTSET; break; - case DeviceValueType::BOOL: + case DeviceValueType::BOOL: { if (Helpers::hasValue(*(uint8_t *)(dv.value_p), EMS_VALUE_BOOL)) { json["value"] = (bool)(*(uint8_t *)(dv.value_p)) ? true : false; } json["type"] = F("boolean"); + json["min"] = 0; + json["max"] = 1; + JsonArray enum_ = json.createNestedArray(F("enum")); + if (dv.options_size == 2) { + enum_.add(dv.options[1]); + enum_.add(dv.options[0]); + } else if (Mqtt::bool_format() == BOOL_FORMAT_ONOFF) { + enum_.add("off"); + enum_.add("on"); + } else if (Mqtt::bool_format() == BOOL_FORMAT_ONOFF_CAP) { + enum_.add("OFF"); + enum_.add("ON"); + } else { + enum_.add(false); + enum_.add(true); + } break; + } case DeviceValueType::TIME: if (Helpers::hasValue(*(uint32_t *)(dv.value_p))) { json["value"] = (divider) ? *(uint32_t *)(dv.value_p) / divider : *(uint32_t *)(dv.value_p);