From 59d07e81d652ca6e19264c710dfcd34ea58426ca Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Mon, 29 Sep 2025 12:47:08 +0200 Subject: [PATCH] test SRC Plus implementation, #2636 --- src/core/emsesp.cpp | 6 +- src/core/locale_translations.h | 3 + src/devices/connect.cpp | 130 +++++++++++++++++++++++++++++++++ src/devices/connect.h | 32 ++++++++ 4 files changed, 170 insertions(+), 1 deletion(-) diff --git a/src/core/emsesp.cpp b/src/core/emsesp.cpp index 42806141b..829ffc631 100644 --- a/src/core/emsesp.cpp +++ b/src/core/emsesp.cpp @@ -1307,7 +1307,11 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, const default_name = "Wireless sensor base"; } } - + // map MX400 also to RF Base + if (device_id == EMSdevice::EMS_DEVICE_ID_RFBASE) { + device_type = DeviceType::CONNECT; + default_name = "Wireless base"; + } if ((device_id >= EMSdevice::EMS_DEVICE_ID_DHW1 && device_id <= EMSdevice::EMS_DEVICE_ID_DHW8) || device_id == EMSdevice::EMS_DEVICE_ID_IPM_DHW) { device_type = DeviceType::WATER; } diff --git a/src/core/locale_translations.h b/src/core/locale_translations.h index fe3f131e6..46747b3e1 100644 --- a/src/core/locale_translations.h +++ b/src/core/locale_translations.h @@ -915,6 +915,9 @@ MAKE_TRANSLATION(status, "status", "status", "Status", "Status", "Status", "stat // RF sensor, id 0x40, telegram 0x435 MAKE_TRANSLATION(RFTemp, "rftemp", "RF room temperature sensor", "RF Raumtemperatursensor", "RF ruimtetemperatuur sensor", "RF Rumsgivare Temperatur", "bezprzewodowy czujnik temperatury pomieszczenia", "RF romsgiver temp", "capteur de température de pièce RF", "RF oda sıcaklık sensörü", "Sensore di temperatura ambiente RF", "RF snímač izbovej teploty", "RF senzor teploty místnosti") +// gateway thermostat +MAKE_TRANSLATION(name, "name", "name", "Name") + // ventilation MAKE_TRANSLATION(outFresh, "outfresh", "outdoor fresh air", "Außenlufttemp.", "temperatuur buitenlucht", "Utelufttemperatur", "świeże powietrze z zewnątrz", "", "", "dış ortam taze hava", "aria fresca esterna", "čerstvý vzduch vonku", "venkovní čerstvý vzduch") // TODO translate MAKE_TRANSLATION(inFresh, "infresh", "indoor fresh air", "Zulufttemp.", "temperatuur aanvoer", "Tillufttemperatur", "nawiew", "", "", "iç ortam taze hava", "aria fresca interna", "čerstvý vzduch v interiéri", "vnitřní čerstvý vzduch") // TODO translate diff --git a/src/devices/connect.cpp b/src/devices/connect.cpp index 03303b257..123b0b88a 100644 --- a/src/devices/connect.cpp +++ b/src/devices/connect.cpp @@ -32,6 +32,20 @@ Connect::Connect(uint8_t device_type, uint8_t device_id, uint8_t product_id, con DeviceValueNumOp::DV_NUMOP_DIV10, FL_(outdoorTemp), DeviceValueUOM::DEGREES); + // Roomthermostats + for (uint8_t i = 0; i < 16; i++) { + register_telegram_type(0x0BDD + i, "Room", false, MAKE_PF_CB(process_roomThermostat)); + register_telegram_type(0x0B3D + i, "Roomname", true, MAKE_PF_CB(process_roomThermostatName)); + register_telegram_type(0x0BB5 + i, "Roomsettings", true, MAKE_PF_CB(process_roomThermostatMode)); + + // 1230..123F read, unknown, 16 bytes long? + // register_telegram_type(0x1230 + i, "unknown", true, MAKE_PF_CB(process_unknown)); + // 1244..1253 broadcast, unknown, 14 bytes long + } + // register_telegram_type(0xDB65, "Roomschedule", true, MAKE_PF_CB(process_roomSchedule)); + // 0x2040, broadcast 36 bytes: + // data: 0E 60 00 DF 0D AF 0A 46 0A 46 02 9A 1C 53 1C 53 12 AD 12 AD 00 00 13 C2 + // data: 1F 37 1F 37 00 00 00 00 18 97 11 27 (offset 24) } } /* @@ -46,6 +60,122 @@ void Connect::process_OutdoorTemp(std::shared_ptr telegram) { (0x0880), data: 01 04 (0x0889), data: 00 80 80 01 */ +void Connect::register_device_values_room(std::shared_ptr room) { + auto tag = DeviceValueTAG::TAG_HS1 + room->room(); + register_device_value(tag, &room->temp_, DeviceValueType::INT16, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(roomTemp), DeviceValueUOM::DEGREES); + register_device_value(tag, &room->humidity_, DeviceValueType::UINT8, FL_(airHumidity), DeviceValueUOM::PERCENT); + register_device_value(tag, &room->seltemp_, DeviceValueType::UINT8, DeviceValueNumOp::DV_NUMOP_DIV2, FL_(seltemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_seltemp)); + register_device_value(tag, &room->mode_, DeviceValueType::ENUM, FL_(enum_mode2), FL_(mode), DeviceValueUOM::NONE, MAKE_CF_CB(set_mode)); + register_device_value(tag, &room->name_, DeviceValueType::STRING, FL_(name), DeviceValueUOM::NONE, MAKE_CF_CB(set_name)); +} + +std::shared_ptr Connect::room_circuit(const uint8_t num, const bool create) { + // check for existing circuit + for (const auto & room_circuit : room_circuits_) { + if (room_circuit->room() == num) { + return room_circuit; + } + } + if (!create) { + return nullptr; + } + // create a new circuit object and add to the list + auto new_room = std::make_shared(num); + room_circuits_.push_back(new_room); + // register the device values + register_device_values_room(new_room); + + return new_room; // return back point to new HC object +} + +// gateway(0x50) B all(0x00), ?(0x0BDD), data: 00 E6 36 2A +void Connect::process_roomThermostat(std::shared_ptr telegram) { + auto rc = room_circuit(telegram->type_id - 0xBDD, true); + uint8_t humidity = EMS_VALUE_UINT8_NOTSET; + uint8_t seltemp = EMS_VALUE_UINT8_NOTSET; + has_update(telegram, rc->temp_, 0); + if (Helpers::hasValue(rc->temp_)) { + telegram->read_value(humidity, 2); + telegram->read_value(seltemp, 3); + } + has_update(rc->humidity_, humidity); + has_update(rc->seltemp_, seltemp); +} + +// gateway(0x48) W gateway(0x50), ?(0x0B42), data: 01 +// gateway(0x48) W gateway(0x50), ?(0x0B42), data: 00 4B 00 FC 00 63 00 68 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 (offset 1) +void Connect::process_roomThermostatName(std::shared_ptr telegram) { + auto rc = room_circuit(telegram->type_id - 0xB3D); + if (rc == nullptr) { + return; + } + if (telegram->offset > 1 || telegram->message_length < 3) { + return; + } + std::string s; + char c; + uint8_t i = 3 - telegram->offset; + while ((i < telegram->message_length) && ((c = telegram->message_data[i]) != 0)) { + s += c; + i += 2; + } + if (s.length()) { + has_update(rc->name_, s.c_str(), s.length()); + } +} + +// settings 0-mode, 1-tempautotemp, 3 - manualtemp, 6,7 - ? +void Connect::process_roomThermostatMode(std::shared_ptr telegram) { + auto rc = room_circuit(telegram->type_id - 0xBB5); + if (rc == nullptr) { + return; + } + has_enumupdate(telegram, rc->mode_, 0, {3, 1, 0}); +} + +// Settings: + +bool Connect::set_mode(const char * value, const int8_t id) { + auto rc = room_circuit(id - DeviceValueTAG::TAG_HS1); + if (rc == nullptr) { + return false; + } + uint8_t v; + if (Helpers::value2enum(value, v, FL_(enum_mode2), {3, 1, 0})) { + write_command(0xBB5 + rc->room(), 0, v); // no validate, mode change is broadcasted + return true; + } + return false; +} + +bool Connect::set_seltemp(const char * value, const int8_t id) { + auto rc = room_circuit(id - DeviceValueTAG::TAG_HS1); + if (rc == nullptr) { + return false; + } + float v; + if (Helpers::value2float(value, v)) { + write_command(0xBB5 + rc->room(), rc->mode_ == 2 ? 1 : 3, v * 2); + return true; + } + return false; +} + +bool Connect::set_name(const char * value, const int8_t id) { + auto rc = room_circuit(id - DeviceValueTAG::TAG_HS1); + if (rc == nullptr || value == nullptr || strlen(value) > 12) { + return false; + } + uint8_t data[strlen(value) * 2]; + uint8_t * d = data; + const char * c = value; + while (*c != 0) { + *d++ = 0; + *d++ = *c++; + } + write_command(0x0B3D + rc->room(), 1, data, sizeof(data), 0x0B3D + rc->room()); + return true; +} } // namespace emsesp diff --git a/src/devices/connect.h b/src/devices/connect.h index 5db2e11d3..e20e74315 100644 --- a/src/devices/connect.h +++ b/src/devices/connect.h @@ -27,7 +27,39 @@ class Connect : public EMSdevice { public: Connect(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const char * name, uint8_t flags, uint8_t brand); + class RoomCircuit { + public: + RoomCircuit(const uint8_t num) + : room_(num) { + } + ~RoomCircuit() = default; + int16_t temp_; + uint8_t humidity_; + uint8_t seltemp_; + uint8_t mode_; + char name_[25]; + + uint8_t room() { + return room_; + } + + private: + uint8_t room_; // dhw circuit number 0..10 + }; + private: + std::shared_ptr room_circuit(const uint8_t num, const bool create = false); + + void register_device_values_room(std::shared_ptr room); + void process_roomThermostat(std::shared_ptr telegram); + void process_roomThermostatName(std::shared_ptr telegram); + void process_roomThermostatMode(std::shared_ptr telegram); + bool set_mode(const char * value, const int8_t id); + bool set_seltemp(const char * value, const int8_t id); + bool set_name(const char * value, const int8_t id); + + std::vector> room_circuits_; + void process_OutdoorTemp(std::shared_ptr telegram); int16_t outdoorTemp_; };