test SRC Plus implementation, #2636

This commit is contained in:
MichaelDvP
2025-09-29 12:47:08 +02:00
parent 419fe8ef5d
commit 59d07e81d6
4 changed files with 170 additions and 1 deletions

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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<const Telegram> telegram) {
(0x0880), data: 01 04
(0x0889), data: 00 80 80 01
*/
void Connect::register_device_values_room(std::shared_ptr<Connect::RoomCircuit> 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::RoomCircuit> 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<Connect::RoomCircuit>(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<const Telegram> 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<const Telegram> 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<const Telegram> 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

View File

@@ -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<Connect::RoomCircuit> room_circuit(const uint8_t num, const bool create = false);
void register_device_values_room(std::shared_ptr<Connect::RoomCircuit> room);
void process_roomThermostat(std::shared_ptr<const Telegram> telegram);
void process_roomThermostatName(std::shared_ptr<const Telegram> telegram);
void process_roomThermostatMode(std::shared_ptr<const Telegram> 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<std::shared_ptr<Connect::RoomCircuit>> room_circuits_;
void process_OutdoorTemp(std::shared_ptr<const Telegram> telegram);
int16_t outdoorTemp_;
};