diff --git a/docs/Modbus-Entity-Registers.md b/docs/Modbus-Entity-Registers.md index 1d7525a98..4c1b1f57d 100644 --- a/docs/Modbus-Entity-Registers.md +++ b/docs/Modbus-Entity-Registers.md @@ -5577,7 +5577,7 @@ | hc1.currtemp | current room temperature | int16 (>=-3199<=3199) | C | false | HC | 1 | 1 | 1/10 | | hc1.haclimate | mqtt discovery current room temperature | enum [selTemp\|roomTemp] (>=5<=30) | | false | HC | 2 | 1 | 1 | -### TR120RF, CR20RF +### RC120RF, TR120RF, CR20RF | shortname | fullname | type | uom | writeable | tag type | register offset | register count | scale factor | |-|-|-|-|-|-|-|-|-| | errorcode | error code | string | | false | DEVICE_DATA | 0 | 8 | 1 | diff --git a/docs/dump_entities.csv b/docs/dump_entities.csv index 323997f18..fbe200347 100644 --- a/docs/dump_entities.csv +++ b/docs/dump_entities.csv @@ -5287,12 +5287,12 @@ device name,device type,product id,shortname,fullname,type [options...] \| (min/ "RC100H, CR10H",thermostat,200,hc1.seltemp,selected room temperature,int16 (>=0<=30),C,true,number.thermostat_hc1_selected_room_temperature,number.thermostat_hc1_seltemp,6,1,1/2,0,1 "RC100H, CR10H",thermostat,200,hc1.currtemp,current room temperature,int16 (>=-3199<=3199),C,false,sensor.thermostat_hc1_current_room_temperature,sensor.thermostat_hc1_currtemp,6,1,1/10,1,1 "RC100H, CR10H",thermostat,200,hc1.haclimate,mqtt discovery current room temperature,enum [selTemp\|roomTemp] (>=5<=30), ,false,sensor.thermostat_hc1_mqtt_discovery_current_room_temperature,sensor.thermostat_hc1_haclimate,6,1,1,2,1 -"TR120RF, CR20RF",thermostat,249,errorcode,error code,string, ,false,sensor.thermostat_error_code,sensor.thermostat_errorcode,6,0,1,0,8 -"TR120RF, CR20RF",thermostat,249,lastcode,last error code,string, ,false,sensor.thermostat_last_error_code,sensor.thermostat_lastcode,6,0,1,8,25 -"TR120RF, CR20RF",thermostat,249,datetime,date/time,string, ,false,sensor.thermostat_date/time,sensor.thermostat_datetime,6,0,1,33,13 -"TR120RF, CR20RF",thermostat,249,hc1.seltemp,selected room temperature,int16 (>=0<=30),C,true,number.thermostat_hc1_selected_room_temperature,number.thermostat_hc1_seltemp,6,1,1/2,0,1 -"TR120RF, CR20RF",thermostat,249,hc1.currtemp,current room temperature,int16 (>=-3199<=3199),C,false,sensor.thermostat_hc1_current_room_temperature,sensor.thermostat_hc1_currtemp,6,1,1/10,1,1 -"TR120RF, CR20RF",thermostat,249,hc1.haclimate,mqtt discovery current room temperature,enum [selTemp\|roomTemp] (>=5<=30), ,false,sensor.thermostat_hc1_mqtt_discovery_current_room_temperature,sensor.thermostat_hc1_haclimate,6,1,1,2,1 +"RC120RF, TR120RF, CR20RF",thermostat,249,errorcode,error code,string, ,false,sensor.thermostat_error_code,sensor.thermostat_errorcode,6,0,1,0,8 +"RC120RF, TR120RF, CR20RF",thermostat,249,lastcode,last error code,string, ,false,sensor.thermostat_last_error_code,sensor.thermostat_lastcode,6,0,1,8,25 +"RC120RF, TR120RF, CR20RF",thermostat,249,datetime,date/time,string, ,false,sensor.thermostat_date/time,sensor.thermostat_datetime,6,0,1,33,13 +"RC120RF, TR120RF, CR20RF",thermostat,249,hc1.seltemp,selected room temperature,int16 (>=0<=30),C,true,number.thermostat_hc1_selected_room_temperature,number.thermostat_hc1_seltemp,6,1,1/2,0,1 +"RC120RF, TR120RF, CR20RF",thermostat,249,hc1.currtemp,current room temperature,int16 (>=-3199<=3199),C,false,sensor.thermostat_hc1_current_room_temperature,sensor.thermostat_hc1_currtemp,6,1,1/10,1,1 +"RC120RF, TR120RF, CR20RF",thermostat,249,hc1.haclimate,mqtt discovery current room temperature,enum [selTemp\|roomTemp] (>=5<=30), ,false,sensor.thermostat_hc1_mqtt_discovery_current_room_temperature,sensor.thermostat_hc1_haclimate,6,1,1,2,1 "XCUMixer",mixer,8,hc1.flowtemphc,flow temperature (TC1),uint16 (>=0<=3199),C,false,sensor.mixer_hc1_flow_temperature_(TC1),sensor.mixer_hc1_flowtemphc,7,1,1/10,0,1 "XCUMixer",mixer,8,hc1.valvestatus,mixing valve actuator (VC1),uint8 (>=0<=100),%,false,sensor.mixer_hc1_mixing_valve_actuator_(VC1),sensor.mixer_hc1_valvestatus,7,1,1,1,1 "XCUMixer",mixer,8,hc1.flowsettemp,setpoint flow temperature,uint8 (>=0<=254),C,true,number.mixer_hc1_setpoint_flow_temperature,number.mixer_hc1_flowsettemp,7,1,1,2,1 diff --git a/src/core/analogsensor.cpp b/src/core/analogsensor.cpp index 0723f1419..7306f2f7d 100644 --- a/src/core/analogsensor.cpp +++ b/src/core/analogsensor.cpp @@ -664,13 +664,18 @@ void AnalogSensor::remove_ha_topic(const int8_t type, const uint8_t gpio) const void AnalogSensor::publish_values(const bool force) { uint8_t num_sensors = sensors_.size(); - if (num_sensors == 0) { + if (!Mqtt::enabled() || num_sensors == 0) { return; } - if (force && Mqtt::publish_single()) { - for (const auto & sensor : sensors_) { - publish_sensor(sensor); + if (force) { + if (Mqtt::publish_single()) { + for (const auto & sensor : sensors_) { + publish_sensor(sensor); + } + return; + } else if (!EMSESP::mqtt_.get_publish_onchange(0)) { + return; // wait for first time periode } } @@ -748,7 +753,8 @@ void AnalogSensor::publish_values(const bool force) { char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; // Set commands for some analog types - char command_topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; + char command_topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; + uint8_t valueType = DeviceValueType::INT16; #if CONFIG_IDF_TARGET_ESP32 if (sensor.type() == AnalogType::PULSE || (sensor.type() == AnalogType::DIGITAL_OUT && sensor.gpio() != 25 && sensor.gpio() != 26)) { #elif CONFIG_IDF_TARGET_ESP32S2 @@ -760,6 +766,7 @@ void AnalogSensor::publish_values(const bool force) { snprintf(command_topic, sizeof(command_topic), "%s/%s/%s", Mqtt::base().c_str(), F_(analogsensor), sensor.name()); config["cmd_t"] = command_topic; Mqtt::add_ha_bool(config.as()); + valueType = DeviceValueType::BOOL; } else if (sensor.type() == AnalogType::DIGITAL_OUT) { // DAC snprintf(topic, sizeof(topic), "number/%s/%s_%02d/config", Mqtt::basename().c_str(), F_(analogsensor), sensor.gpio()); snprintf(command_topic, sizeof(command_topic), "%s/%s/%s", Mqtt::base().c_str(), F_(analogsensor), sensor.name()); @@ -787,22 +794,22 @@ void AnalogSensor::publish_values(const bool force) { } else if (sensor.type() == AnalogType::COUNTER || (sensor.type() >= AnalogType::CNT_0 && sensor.type() <= AnalogType::CNT_2)) { snprintf(topic, sizeof(topic), "sensor/%s/%s_%02d/config", Mqtt::basename().c_str(), F_(analogsensor), sensor.gpio()); snprintf(command_topic, sizeof(command_topic), "%s/%s/%s", Mqtt::base().c_str(), F_(analogsensor), sensor.name()); - config["cmd_t"] = command_topic; - config["stat_cla"] = "total_increasing"; + config["cmd_t"] = command_topic; // config["mode"] = "box"; // auto, slider or box // config["step"] = sensor.factor(); } else if (sensor.type() == AnalogType::DIGITAL_IN) { snprintf(topic, sizeof(topic), "binary_sensor/%s/%s_%02d/config", Mqtt::basename().c_str(), F_(analogsensor), sensor.gpio()); Mqtt::add_ha_bool(config.as()); + valueType = DeviceValueType::BOOL; } else { snprintf(topic, sizeof(topic), "sensor/%s/%s_%02d/config", Mqtt::basename().c_str(), F_(analogsensor), sensor.gpio()); - config["stat_cla"] = "measurement"; } // add default_entity_id std::string topic_str(topic); config["def_ent_id"] = topic_str.substr(0, topic_str.find("/")) + "." + uniq_s; + Mqtt::add_ha_classes(config.as(), EMSdevice::DeviceType::ANALOGSENSOR, valueType, sensor.uom()); // dev section with model is only created on the 1st sensor Mqtt::add_ha_dev_section(config.as(), "Analog Sensors", !ha_dev_created); Mqtt::add_ha_avty_section(config.as(), stat_t, val_cond); diff --git a/src/core/device_library.h b/src/core/device_library.h index d452b569e..343050585 100644 --- a/src/core/device_library.h +++ b/src/core/device_library.h @@ -129,7 +129,7 @@ // Thermostat remote - 0x38 { 3, DeviceType::THERMOSTAT, "RT800, RC220", DeviceFlags::EMS_DEVICE_FLAG_RC100H}, {200, DeviceType::THERMOSTAT, "RC100H, CR10H", DeviceFlags::EMS_DEVICE_FLAG_RC100H}, -{249, DeviceType::THERMOSTAT, "TR120RF, CR20RF", DeviceFlags::EMS_DEVICE_FLAG_RC100H}, +{249, DeviceType::THERMOSTAT, "RC120RF, TR120RF, CR20RF", DeviceFlags::EMS_DEVICE_FLAG_RC100H}, // Solar Modules - 0x30 (for solar), 0x2A, 0x41 (for ww) { 73, DeviceType::SOLAR, "SM10", DeviceFlags::EMS_DEVICE_FLAG_SM10}, diff --git a/src/core/mqtt.cpp b/src/core/mqtt.cpp index f5400cc3e..5fc577b72 100644 --- a/src/core/mqtt.cpp +++ b/src/core/mqtt.cpp @@ -511,6 +511,11 @@ void Mqtt::on_connect() { // send initial MQTT messages for some of our services EMSESP::system_.send_heartbeat(); // send heartbeat + // for publish on change publish the initial complete list + EMSESP::webCustomEntityService.publish(true); + EMSESP::webSchedulerService.publish(true); + EMSESP::analogsensor_.publish_values(true); + EMSESP::temperaturesensor_.publish_values(true); } // Home Assistant Discovery - the main master Device called EMS-ESP @@ -590,10 +595,6 @@ void Mqtt::ha_status() { // add sub or pub task to the queue. // the base is not included in the topic bool Mqtt::queue_message(const uint8_t operation, const std::string & topic, const std::string & payload, const bool retain) { - if (!mqtt_enabled_ || topic.empty() || !connected()) { - return false; // quit, not using MQTT - } - if (topic == "response" && operation == Operation::PUBLISH) { lastresponse_ = payload; if (!send_response_) { @@ -601,6 +602,10 @@ bool Mqtt::queue_message(const uint8_t operation, const std::string & topic, con } } + if (!mqtt_enabled_ || topic.empty() || !connected()) { + return false; // quit, not using MQTT + } + // check free mem #ifndef EMSESP_STANDALONE // if (ESP.getFreeHeap() < 60 * 1024 || ESP.getMaxAllocHeap() < 40 * 1024) { diff --git a/src/core/roomcontrol.cpp b/src/core/roomcontrol.cpp index 4d8fd7bac..7366bc8f8 100644 --- a/src/core/roomcontrol.cpp +++ b/src/core/roomcontrol.cpp @@ -76,9 +76,11 @@ uint8_t Roomctrl::get_hc(uint8_t addr) { if (addr >= 0x40 && addr <= 0x44 && type_[addr - 0x40] == SENSOR) { return addr - 0x40; // SENSOR } else if (addr >= 0x38 && addr <= 0x3B - && (type_[addr - 0x38] == RC100H || type_[addr - 0x38] == RC200 || type_[addr - 0x38] == RC100 || type_[addr - 0x38] == RT800)) { - return addr - 0x38; // RC100H, RC200 - } else if (addr >= 0x18 && addr <= 0x1B && (type_[addr - 0x18] == RC20 || type_[addr - 0x18] == FB10)) { + && (type_[addr - 0x38] == RC100H || type_[addr - 0x38] == RC200 || type_[addr - 0x38] == RC100 || type_[addr - 0x38] == RT800 + || type_[addr - 0x38] == RC120RF)) { + return addr - 0x38; // RC100H, RC200 + } + else if (addr >= 0x18 && addr <= 0x1B && (type_[addr - 0x18] == RC20 || type_[addr - 0x18] == FB10)) { return addr - 0x18; // RC20, FB10 } return 0xFF; // invalid @@ -88,7 +90,7 @@ uint8_t Roomctrl::get_hc(uint8_t addr) { * if remote control is active send the temperature every 15 seconds */ void Roomctrl::send(uint8_t addr) { - if (addr & 0x80) { + if ((addr & 0x80) || EMSESP::system_.readonly_mode()) { return; } uint8_t hc = get_hc(addr); @@ -108,7 +110,7 @@ void Roomctrl::send(uint8_t addr) { EMSESP::logger().warning("remotetemp timeout hc%d, stop sending roomtemperature to thermostat", hc); } if (switch_off_[hc] || (uuid::get_uptime() - send_time_[hc]) > SEND_INTERVAL) { // check interval - if (type_[hc] == RC100H || type_[hc] == RT800) { + if (type_[hc] == RC100H || type_[hc] == RT800 || type_[hc] == RC120RF) { if (sendtype_[hc] == SendType::HUMI) { // send humidity if (switch_off_[hc]) { remotehum_[hc] = EMS_VALUE_UINT8_NOTSET; @@ -145,6 +147,9 @@ void Roomctrl::send(uint8_t addr) { * check if there is a message for the remote room controller */ void Roomctrl::check(uint8_t addr, const uint8_t * data, const uint8_t length) { + if (EMSESP::system_.readonly_mode()) { + return; + } uint8_t hc = get_hc(addr); if (hc >= HCS || length < 5) { return; @@ -249,6 +254,14 @@ void Roomctrl::version(uint8_t addr, uint8_t dst, uint8_t hc) { data[7] = EMSbus::calculate_crc(data, 7); // append CRC EMSuart::transmit(data, 8); return; + } else if (type_[hc] == RC120RF) { + data[5] = 16; // version 16.02 + data[6] = 2; + data[7] = 0; + data[8] = 0xFF; + data[9] = EMSbus::calculate_crc(data, 9); // append CRC + EMSuart::transmit(data, 10); + return; } } @@ -308,7 +321,7 @@ void Roomctrl::temperature(uint8_t addr, uint8_t dst, uint8_t hc) { data[5] = 0x2B + hc; data[6] = (uint8_t)(remotetemp_[hc] >> 8); data[7] = (uint8_t)(remotetemp_[hc] & 0xFF); - uint16_t t1 = remotetemp_[hc] * 10 + 3; + uint16_t t1 = remotetemp_[hc] * 10; data[8] = (uint8_t)(t1 >> 8); data[9] = (uint8_t)(t1 & 0xFF); data[10] = 1; // not sure what this is and if we need it, maybe mode? @@ -339,13 +352,27 @@ void Roomctrl::temperature(uint8_t addr, uint8_t dst, uint8_t hc) { data[5] = 0x2B + hc; data[6] = (uint8_t)(remotetemp_[hc] >> 8); data[7] = (uint8_t)(remotetemp_[hc] & 0xFF); - uint16_t t1 = remotetemp_[hc] * 10 + 3; + uint16_t t1 = remotetemp_[hc] * 10; data[8] = (uint8_t)(t1 >> 8); data[9] = (uint8_t)(t1 & 0xFF); data[10] = 1; // not sure what this is and if we need it, maybe mode? data[11] = 9; // not sure what this is and if we need it, maybe mode? data[12] = EMSbus::calculate_crc(data, 12); // append CRC EMSuart::transmit(data, 13); + } else if (type_[hc] == RC120RF) { + data[2] = 0xFF; + data[3] = 0; + data[4] = 3; + data[5] = 0x2B + hc; + data[6] = (uint8_t)(remotetemp_[hc] >> 8); + data[7] = (uint8_t)(remotetemp_[hc] & 0xFF); + uint16_t t1 = remotetemp_[hc] * 10; + data[8] = (uint8_t)(t1 >> 8); + data[9] = (uint8_t)(t1 & 0xFF); + data[10] = 0; // not sure what this is and if we need it + data[11] = 0; // not sure what this is and if we need it + data[12] = EMSbus::calculate_crc(data, 12); // append CRC + EMSuart::transmit(data, 13); } } diff --git a/src/core/roomcontrol.h b/src/core/roomcontrol.h index 939f54353..b7adb5df3 100644 --- a/src/core/roomcontrol.h +++ b/src/core/roomcontrol.h @@ -25,7 +25,7 @@ namespace emsesp { class Roomctrl { public: // Product-Id of the remote - enum RemoteType : uint8_t { NONE = 0, RC20 = 113, FB10 = 109, RC100H = 200, SENSOR = 0x40, RC200 = 157, RC100 = 165, RT800 = 3 }; + enum RemoteType : uint8_t { NONE = 0, RC20 = 113, FB10 = 109, RC100H = 200, SENSOR = 0x40, RC200 = 157, RC100 = 165, RT800 = 3, RC120RF = 249 }; static void send(uint8_t addr); static void check(uint8_t addr, const uint8_t * data, const uint8_t length); diff --git a/src/core/temperaturesensor.cpp b/src/core/temperaturesensor.cpp index c3820d3e6..cc9e757eb 100644 --- a/src/core/temperaturesensor.cpp +++ b/src/core/temperaturesensor.cpp @@ -473,10 +473,15 @@ void TemperatureSensor::publish_values(const bool force) { return; } - if (force && Mqtt::publish_single()) { + if (force) { + if (Mqtt::publish_single()) { for (const auto & sensor : sensors_) { publish_sensor(sensor); } + return; + } else if (!EMSESP::mqtt_.get_publish_onchange(0)) { + return; // wait for first time periode + } } JsonDocument doc; @@ -543,6 +548,8 @@ void TemperatureSensor::publish_values(const bool force) { config["uniq_id"] = uniq_s; config["def_ent_id"] = (std::string) "sensor." + uniq_s; config["name"] = (const char *)sensor.name(); + config["stat_cla"] = "measurement"; + config["dev_cla"] = "temperature"; // dev section with model is only created on the 1st sensor Mqtt::add_ha_dev_section(config.as(), "Temperature Sensors", !ha_dev_created); diff --git a/src/devices/thermostat.cpp b/src/devices/thermostat.cpp index 98b965a44..30d102465 100644 --- a/src/devices/thermostat.cpp +++ b/src/devices/thermostat.cpp @@ -2109,6 +2109,8 @@ bool Thermostat::set_remotetemp(const char * value, const int8_t id) { Roomctrl::set_remotetemp(Roomctrl::RC100H, hc->hc(), hc->remotetemp); // RC100H } else if (hc->control == 2) { // RC100(2) Roomctrl::set_remotetemp(Roomctrl::RC100, hc->hc(), hc->remotetemp); // RC100 + } else if (hc->control == 5) { + Roomctrl::set_remotetemp(Roomctrl::RC120RF, hc->hc(), hc->remotetemp); } else if (hc->control == 6) { Roomctrl::set_remotetemp(Roomctrl::RT800, hc->hc(), hc->remotetemp); } else { @@ -2141,6 +2143,9 @@ bool Thermostat::set_remotehum(const char * value, const int8_t id) { if (hc->control == 3) { Roomctrl::set_remotehum(Roomctrl::RC100H, hc->hc(), hc->remotehum); // RC100H return true; + } else if (hc->control == 5) { + Roomctrl::set_remotehum(Roomctrl::RC120RF, hc->hc(), hc->remotehum); + return true; } else if (hc->control == 6) { Roomctrl::set_remotehum(Roomctrl::RT800, hc->hc(), hc->remotehum); return true; @@ -2310,6 +2315,8 @@ bool Thermostat::set_control(const char * value, const int8_t id) { Roomctrl::set_remotetemp(Roomctrl::RC100, hc->hc(), hc->remotetemp); } else if (ctrl == 3) { Roomctrl::set_remotetemp(Roomctrl::RC100H, hc->hc(), hc->remotetemp); + } else if (ctrl == 5) { + Roomctrl::set_remotetemp(Roomctrl::RC120RF, hc->hc(), hc->remotetemp); // RC120 } else if (ctrl == 6) { Roomctrl::set_remotetemp(Roomctrl::RT800, hc->hc(), hc->remotetemp); } else { diff --git a/src/web/WebCustomEntityService.cpp b/src/web/WebCustomEntityService.cpp index 482b021b3..62d409c71 100644 --- a/src/web/WebCustomEntityService.cpp +++ b/src/web/WebCustomEntityService.cpp @@ -378,10 +378,20 @@ void WebCustomEntityService::publish_single(CustomEntityItem & entity) { } // publish to Mqtt -void WebCustomEntityService::publish() { +void WebCustomEntityService::publish(const bool force) { if (!Mqtt::enabled() || customEntityItems_->empty()) { return; } + if (force) { + if (Mqtt::publish_single()) { + for (CustomEntityItem & entityItem : *customEntityItems_) { + publish_single(entityItem); + } + return; + } else if (!EMSESP::mqtt_.get_publish_onchange(0)) { + return; // wait for first time periode + } + } JsonDocument doc; JsonObject output = doc.to(); diff --git a/src/web/WebCustomEntityService.h b/src/web/WebCustomEntityService.h index 517d19c88..3302edd83 100644 --- a/src/web/WebCustomEntityService.h +++ b/src/web/WebCustomEntityService.h @@ -58,7 +58,7 @@ class WebCustomEntityService : public StatefulService { void begin(); void publish_single(CustomEntityItem & entity); - void publish(); + void publish(const bool force = false); bool command_setvalue(const char * value, const int8_t id, const char * name); bool get_value_info(JsonObject output, const char * cmd); void get_value_json(JsonObject output, CustomEntityItem const & entity); diff --git a/src/web/WebSchedulerService.cpp b/src/web/WebSchedulerService.cpp index c8af8f825..f88a1f8b1 100644 --- a/src/web/WebSchedulerService.cpp +++ b/src/web/WebSchedulerService.cpp @@ -105,10 +105,6 @@ StateUpdateResult WebScheduler::update(JsonObject root, WebScheduler & webSchedu CommandFlag::ADMIN_ONLY); } } - - EMSESP::webSchedulerService.ha_reset(); - EMSESP::webSchedulerService.publish(); - return StateUpdateResult::CHANGED; } @@ -217,17 +213,17 @@ void WebSchedulerService::publish_single(const char * name, const bool state) { // publish to Mqtt void WebSchedulerService::publish(const bool force) { - if (force) { - ha_configdone_ = false; - } - if (!Mqtt::enabled() || scheduleItems_->empty()) { return; } - - if (Mqtt::publish_single() && force) { - for (const ScheduleItem & scheduleItem : *scheduleItems_) { - publish_single(scheduleItem.name, scheduleItem.active); + if (force) { + if (Mqtt::publish_single()) { + for (const ScheduleItem & scheduleItem : *scheduleItems_) { + publish_single(scheduleItem.name, scheduleItem.active); + } + return; + } else if (!EMSESP::mqtt_.get_publish_onchange(0)) { + return; // wait for first time periode } }