diff --git a/interface/package.json b/interface/package.json index 591f41fc3..0726d973c 100644 --- a/interface/package.json +++ b/interface/package.json @@ -3,11 +3,11 @@ "version": "0.1.0", "private": true, "dependencies": { - "@material-ui/core": "^4.11.3", + "@material-ui/core": "^4.11.4", "@material-ui/icons": "^4.11.2", "@types/lodash": "^4.14.168", - "@types/node": "^14.14.37", - "@types/react": "^17.0.3", + "@types/node": "^15.0.1", + "@types/react": "^17.0.4", "@types/react-dom": "^17.0.3", "@types/react-material-ui-form-validator": "^2.1.0", "@types/react-router": "^5.1.13", @@ -17,7 +17,7 @@ "jwt-decode": "^3.1.2", "lodash": "^4.17.21", "mime-types": "^2.1.30", - "notistack": "^1.0.5", + "notistack": "^1.0.6", "parse-ms": "^3.0.0", "react": "^17.0.2", "react-dom": "^17.0.2", diff --git a/src/dallassensor.cpp b/src/dallassensor.cpp index 76d8e571f..dd1dd7dc5 100644 --- a/src/dallassensor.cpp +++ b/src/dallassensor.cpp @@ -318,10 +318,18 @@ bool DallasSensor::command_info(const char * value, const int8_t id, JsonObject for (const auto & sensor : sensors_) { char sensorID[10]; // sensor{1-n} snprintf_P(sensorID, 10, PSTR("sensor%d"), i++); - JsonObject dataSensor = json.createNestedObject(sensorID); - dataSensor["id"] = sensor.to_string(); - if (Helpers::hasValue(sensor.temperature_c)) { - dataSensor["temp"] = (float)(sensor.temperature_c) / 10; + if (id == 0) { + if (Mqtt::dallas_format() == Mqtt::Dallas_Format::SENSORID && Helpers::hasValue(sensor.temperature_c)) { + json[sensor.to_string()] = (float)(sensor.temperature_c) / 10; + } else if (Helpers::hasValue(sensor.temperature_c)) { + json[sensorID] = (float)(sensor.temperature_c) / 10; + } + } else { + JsonObject dataSensor = json.createNestedObject(sensorID); + dataSensor["id"] = sensor.to_string(); + if (Helpers::hasValue(sensor.temperature_c)) { + dataSensor["temp"] = (float)(sensor.temperature_c) / 10; + } } } diff --git a/src/device_library.h b/src/device_library.h index 8acff9f5c..b3cf33d41 100644 --- a/src/device_library.h +++ b/src/device_library.h @@ -80,7 +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 +{216, DeviceType::THERMOSTAT, F("CRF200S"), DeviceFlags::EMS_DEVICE_FLAG_CRF | DeviceFlags::EMS_DEVICE_FLAG_NO_WRITE}, // 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 5eb577a3a..e0f78b946 100644 --- a/src/devices/boiler.cpp +++ b/src/devices/boiler.cpp @@ -99,7 +99,7 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const register_device_value(TAG_BOILER_DATA, &heatingActive_, DeviceValueType::BOOL, nullptr, FL_(heatingActive), DeviceValueUOM::NONE); register_device_value(TAG_BOILER_DATA, &tapwaterActive_, DeviceValueType::BOOL, nullptr, FL_(tapwaterActive), DeviceValueUOM::NONE); register_device_value(TAG_BOILER_DATA, &selFlowTemp_, DeviceValueType::UINT, nullptr, FL_(selFlowTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_flow_temp)); - register_device_value(TAG_BOILER_DATA, &selBurnPow_, DeviceValueType::UINT, nullptr, FL_(selBurnPow), DeviceValueUOM::PERCENT); + register_device_value(TAG_BOILER_DATA, &selBurnPow_, DeviceValueType::UINT, nullptr, FL_(selBurnPow), DeviceValueUOM::PERCENT, MAKE_CF_CB(set_burn_power)); register_device_value(TAG_BOILER_DATA, &heatingPumpMod_, DeviceValueType::UINT, nullptr, FL_(heatingPumpMod), DeviceValueUOM::PERCENT); register_device_value(TAG_BOILER_DATA, &heatingPump2Mod_, DeviceValueType::UINT, nullptr, FL_(heatingPump2Mod), DeviceValueUOM::PERCENT); register_device_value(TAG_BOILER_DATA, &outdoorTemp_, DeviceValueType::SHORT, FL_(div10), FL_(outdoorTemp), DeviceValueUOM::DEGREES); @@ -635,10 +635,10 @@ void Boiler::process_HpOutdoor(std::shared_ptr telegram) { has_update(telegram->read_value(hpTr4_, 18)); has_update(telegram->read_value(hpTr5_, 20)); has_update(telegram->read_value(hpTr6_, 0)); - has_update(telegram->read_value(hpTr7_, 31)); + has_update(telegram->read_value(hpTr7_, 30)); has_update(telegram->read_value(hpTl2_, 12)); - has_update(telegram->read_value(hpPl1_, 27)); - has_update(telegram->read_value(hpPh1_, 29)); + has_update(telegram->read_value(hpPl1_, 26)); + has_update(telegram->read_value(hpPh1_, 28)); } // 0x2A - MC110Status @@ -800,6 +800,20 @@ bool Boiler::set_flow_temp(const char * value, const int8_t id) { return true; } +// set selected burner power +bool Boiler::set_burn_power(const char * value, const int8_t id) { + int v = 0; + if (!Helpers::value2number(value, v)) { + LOG_WARNING(F("Set burner max. power: Invalid value")); + return false; + } + + LOG_INFO(F("Setting burner max. power to %d %"), v); + write_command(EMS_TYPE_UBASetPoints, 1, v, EMS_TYPE_UBASetPoints); + + return true; +} + // Set the warm water flow temperature offset 0x33 bool Boiler::set_wWFlowTempOffset(const char * value, const int8_t id) { int v = 0; diff --git a/src/devices/boiler.h b/src/devices/boiler.h index 87a239192..deeb3585c 100644 --- a/src/devices/boiler.h +++ b/src/devices/boiler.h @@ -207,6 +207,7 @@ class Boiler : public EMSdevice { bool set_warmwater_maxpower(const char * value, const int8_t id); bool set_wWFlowTempOffset(const char * value, const int8_t id); bool set_flow_temp(const char * value, const int8_t id); + bool set_burn_power(const char * value, const int8_t id); bool set_heating_activated(const char * value, const int8_t id); bool set_heating_temp(const char * value, const int8_t id); bool set_min_power(const char * value, const int8_t id); diff --git a/src/devices/thermostat.cpp b/src/devices/thermostat.cpp index 80fe8af51..c03c1161a 100644 --- a/src/devices/thermostat.cpp +++ b/src/devices/thermostat.cpp @@ -111,6 +111,13 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i set_typeids = {}; register_telegram_type(monitor_typeids[0], F("EasyMonitor"), true, MAKE_PF_CB(process_EasyMonitor)); + } else if (model == EMSdevice::EMS_DEVICE_FLAG_CRF) { + monitor_typeids = {0x02A5, 0x02A6, 0x02A7, 0x02A8}; + set_typeids = {}; + for (uint8_t i = 0; i < monitor_typeids.size(); i++) { + register_telegram_type(monitor_typeids[i], F("CRFMonitor"), true, MAKE_PF_CB(process_CRFMonitor)); + } + // RC300/RC100 } else if ((model == EMSdevice::EMS_DEVICE_FLAG_RC300) || (model == EMSdevice::EMS_DEVICE_FLAG_RC100)) { monitor_typeids = {0x02A5, 0x02A6, 0x02A7, 0x02A8}; @@ -292,7 +299,8 @@ std::shared_ptr Thermostat::heating_circuit(std::sha // not found, search device-id types for remote thermostats if (telegram->src >= 0x18 && telegram->src <= 0x1B) { - hc_num = telegram->src - 0x17; + hc_num = telegram->src - 0x17; + toggle_ = true; } // still didn't recognize it, ignore it @@ -469,6 +477,12 @@ uint8_t Thermostat::HeatingCircuit::get_mode() const { } else if (mode == 2) { return HeatingCircuit::Mode::AUTO; } + } else if (model == EMSdevice::EMS_DEVICE_FLAG_CRF) { + if (mode == 0) { + return HeatingCircuit::Mode::AUTO; + } else if (mode == 1) { + return HeatingCircuit::Mode::OFF; + } } else if ((model == EMSdevice::EMS_DEVICE_FLAG_RC300) || (model == EMSdevice::EMS_DEVICE_FLAG_RC100)) { if (mode == 0) { return HeatingCircuit::Mode::MANUAL; @@ -515,6 +529,12 @@ uint8_t Thermostat::HeatingCircuit::get_mode_type() const { } else if (modetype == 1) { return HeatingCircuit::Mode::DAY; } + } else if (model == EMS_DEVICE_FLAG_CRF) { + if (modetype == 0) { + return HeatingCircuit::Mode::OFF; + } else if (modetype == 1) { + return HeatingCircuit::Mode::ON; + } } else if (model == EMS_DEVICE_FLAG_RC300) { if (modetype == 0) { return HeatingCircuit::Mode::ECO; @@ -751,6 +771,19 @@ void Thermostat::process_JunkersMonitor(std::shared_ptr telegram has_update(telegram->read_value(hc->mode, 1)); // 1 = manual, 2 = auto } +// type 0x02A5 - data from Worchester CRF200 +void Thermostat::process_CRFMonitor(std::shared_ptr telegram) { + std::shared_ptr hc = heating_circuit(telegram); + if (hc == nullptr) { + return; + } + has_update(telegram->read_value(hc->curr_roomTemp, 0)); // is * 10 + has_update(telegram->read_bitvalue(hc->modetype, 2, 0)); + has_update(telegram->read_bitvalue(hc->mode, 2, 4)); // bit 4, mode (auto=0 or off=1) + has_update(telegram->read_value(hc->setpoint_roomTemp, 6, 1)); // is * 2, force as single byte + has_update(telegram->read_value(hc->targetflowtemp, 4)); +} + // type 0x02A5 - data from the Nefit RC1010/3000 thermostat (0x18) and RC300/310s on 0x10 void Thermostat::process_RC300Monitor(std::shared_ptr telegram) { std::shared_ptr hc = heating_circuit(telegram); @@ -2267,6 +2300,11 @@ void Thermostat::register_device_values_hc(std::shared_ptrprogram, DeviceValueType::UINT, nullptr, FL_(program), DeviceValueUOM::NONE, MAKE_CF_CB(set_program)); register_device_value(tag, &hc->tempautotemp, DeviceValueType::UINT, FL_(div2), FL_(tempautotemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_tempautotemp)); break; + case EMS_DEVICE_FLAG_CRF: + register_device_value(tag, &hc->mode, DeviceValueType::ENUM, FL_(enum_mode5), FL_(mode), DeviceValueUOM::NONE); + register_device_value(tag, &hc->modetype, DeviceValueType::ENUM, FL_(enum_modetype5), FL_(modetype), DeviceValueUOM::NONE); + register_device_value(tag, &hc->targetflowtemp, DeviceValueType::UINT, nullptr, FL_(targetflowtemp), DeviceValueUOM::DEGREES); + break; case EMS_DEVICE_FLAG_RC20: register_device_value(tag, &hc->mode, DeviceValueType::ENUM, FL_(enum_mode2), FL_(mode), DeviceValueUOM::NONE, MAKE_CF_CB(set_mode)); break; diff --git a/src/devices/thermostat.h b/src/devices/thermostat.h index b3059decf..075b43a2d 100644 --- a/src/devices/thermostat.h +++ b/src/devices/thermostat.h @@ -101,6 +101,7 @@ class Thermostat : public EMSdevice { ROOMINFLUENCE, TEMPAUTO, NOREDUCE, + ON, UNKNOWN }; @@ -276,6 +277,7 @@ class Thermostat : public EMSdevice { void process_RC20Set_2(std::shared_ptr telegram); void process_RC10Monitor(std::shared_ptr telegram); void process_RC10Set(std::shared_ptr telegram); + void process_CRFMonitor(std::shared_ptr telegram); void process_RC300Monitor(std::shared_ptr telegram); void process_RC300Set(std::shared_ptr telegram); void process_RC300Summer(std::shared_ptr telegram); diff --git a/src/emsdevice.h b/src/emsdevice.h index 06ffc2c80..86bdf91d0 100644 --- a/src/emsdevice.h +++ b/src/emsdevice.h @@ -349,6 +349,7 @@ class EMSdevice { static constexpr uint8_t EMS_DEVICE_FLAG_RC300 = 8; static constexpr uint8_t EMS_DEVICE_FLAG_RC100 = 9; static constexpr uint8_t EMS_DEVICE_FLAG_JUNKERS = 10; + static constexpr uint8_t EMS_DEVICE_FLAG_CRF = 11; // CRF200 only monitor void reserve_device_values(uint8_t elements) { devicevalues_.reserve(elements); diff --git a/src/emsesp.cpp b/src/emsesp.cpp index 20f3bf936..38c8b741d 100644 --- a/src/emsesp.cpp +++ b/src/emsesp.cpp @@ -562,6 +562,27 @@ bool EMSESP::get_device_value_info(JsonObject & root, const char * cmd, const in return emsdevice->get_value_info(root, cmd, id); } } + + if (devicetype == DeviceType::DALLASSENSOR) { + uint8_t i = 1; + for (const auto & sensor : EMSESP::sensor_devices()) { + char sensorID[10]; + snprintf_P(sensorID, 10, PSTR("sensor%d"), i++); + if ((strcmp(cmd, sensorID) == 0) || (strcmp(cmd, Helpers::toLower(sensor.to_string()).c_str()) == 0)) { + root["name"] = sensor.to_string(); + if (Helpers::hasValue(sensor.temperature_c)) { + root["value"] = (float)(sensor.temperature_c) / 10; + } + root["type"] = F_(number); + root["min"] = -55; + root["max"] = 125; + root["unit"] = EMSdevice::uom_to_string(DeviceValueUOM::DEGREES); + root["writeable"] = false; + return true; + } + } + } + return false; } diff --git a/src/locale_EN.h b/src/locale_EN.h index f6ec5713e..3c5c224f4 100644 --- a/src/locale_EN.h +++ b/src/locale_EN.h @@ -308,11 +308,13 @@ MAKE_PSTR_LIST(enum_mode, F_(manual), F_(auto)) MAKE_PSTR_LIST(enum_mode2, F_(off), F_(manual), F_(auto)) MAKE_PSTR_LIST(enum_mode3, F_(night), F_(day), F_(auto)) MAKE_PSTR_LIST(enum_mode4, F_(blank), F_(manual), F_(auto), F_(holiday)) +MAKE_PSTR_LIST(enum_mode5, F_(auto), F_(off)) MAKE_PSTR_LIST(enum_modetype, F_(eco), F_(comfort)) MAKE_PSTR_LIST(enum_modetype2, F_(day)) MAKE_PSTR_LIST(enum_modetype3, F_(night), F_(day)) MAKE_PSTR_LIST(enum_modetype4, F_(blank), F_(nofrost), F_(eco), F_(heat)) +MAKE_PSTR_LIST(enum_modetype5, F_(off), F_(on)) MAKE_PSTR_LIST(enum_reducemode, F_(nofrost), F_(reduce), F_(room), F_(outdoor)) diff --git a/src/system.cpp b/src/system.cpp index 18fb363da..103c41435 100644 --- a/src/system.cpp +++ b/src/system.cpp @@ -940,6 +940,11 @@ bool System::command_info(const char * value, const int8_t id, JsonObject & json } } } + if (EMSESP::sensor_devices().size()) { + JsonObject obj = devices2.createNestedObject(); + obj["type"] = F("Dallassensor"); + obj["name"] = F("Dallassensor"); + } return true; } diff --git a/src/telegram.cpp b/src/telegram.cpp index 97e61284e..39588aaa3 100644 --- a/src/telegram.cpp +++ b/src/telegram.cpp @@ -567,9 +567,10 @@ void TxService::retry_tx(const uint8_t operation, const uint8_t * data, const ui reset_retry_count(); // give up increment_telegram_fail_count(); // another Tx fail - LOG_ERROR(F("Last Tx %s operation failed after %d retries. Ignoring request."), + LOG_ERROR(F("Last Tx %s operation failed after %d retries. Ignoring request: %s"), (operation == Telegram::Operation::TX_WRITE) ? F("Write") : F("Read"), - MAXIMUM_TX_RETRIES); + MAXIMUM_TX_RETRIES), + telegram_last_->to_string().c_str(); return; }