Merge pull request #923 from MichaelDvP/dev

fixes and the tested heatpump/heatsource entities
This commit is contained in:
Proddy
2023-01-22 13:06:23 +01:00
committed by GitHub
32 changed files with 4038 additions and 11252 deletions

View File

@@ -28,6 +28,11 @@
- Settings for heatpump silent mode and additional heater [[#802](https://github.com/emsesp/EMS-ESP32/issues/802)] [[#803](https://github.com/emsesp/EMS-ESP32/issues/803)]
- Zone module MZ100 [#826](https://github.com/emsesp/EMS-ESP32/issues/826)
- Default MQTT hostname is blank [#829](https://github.com/emsesp/EMS-ESP32/issues/829)
- wwCurFlow for ems+ devices [#829](https://github.com/emsesp/EMS-ESP32/issues/829)
- Add Rego 3000, TR120RF thermostats [#917](https://github.com/emsesp/EMS-ESP32/issues/917)
- Add config for ESP32-S3
- Add heatpump silent mode and other entities [#896](https://github.com/emsesp/EMS-ESP32/issues/896)
- Allow reboot to other partition (factory or asymetric OTA)
## Fixed
@@ -36,6 +41,10 @@
- Commands for multiple thermostats [#826](https://github.com/emsesp/EMS-ESP32/issues/826)
- API queries for multiple devices [#865](https://github.com/emsesp/EMS-ESP32/issues/865)
- Console crash when using call with command `hcx` only. [#841](https://github.com/emsesp/EMS-ESP32/issues/841)
- heatingPump2Mod was wrong, changed to absBurnPow [[#908](https://github.com/emsesp/EMS-ESP32/issues/908)
- rounding of web input values
- analog sensor with single gpio number [#915](https://github.com/emsesp/EMS-ESP32/issues/915)
- HA dallas and analog configs: remove/rebuild on change [#888](https://github.com/emsesp/EMS-ESP32/issues/888)
## Changed
@@ -47,5 +56,5 @@
- analog/dallas values command as list like ems-devices
- analog/dallas HA-entities based on id
- MQTT Base is a mandatory field. Removed MQTT topic length from settings
- HA duration class for time entities [[#822](https://github.com/emsesp/EMS-ESP32/issues/822
- AM200 alternative heatsource as class heatsource [[#857](https://github.com/emsesp/EMS-ESP32/issues/857
- HA duration class for time entities [[#822](https://github.com/emsesp/EMS-ESP32/issues/822)
- AM200 alternative heatsource as class heatsource [[#857](https://github.com/emsesp/EMS-ESP32/issues/857)

View File

@@ -1,5 +1,5 @@
{
"adapter": "react",
"baseLocale": "pl",
"$schema": "https://unpkg.com/typesafe-i18n@5.18.0/schema/typesafe-i18n.json"
"$schema": "https://unpkg.com/typesafe-i18n@5.18.1/schema/typesafe-i18n.json"
}

14750
interface/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -8,7 +8,7 @@
"@emotion/styled": "^11.10.5",
"@msgpack/msgpack": "^2.8.0",
"@mui/icons-material": "^5.11.0",
"@mui/material": "^5.11.3",
"@mui/material": "^5.11.4",
"@table-library/react-table-library": "4.0.23",
"@types/lodash": "^4.14.191",
"@types/node": "^18.11.18",
@@ -26,7 +26,7 @@
"react-dom": "^18.2.0",
"react-dropzone": "^14.2.3",
"react-icons": "^4.7.1",
"react-router-dom": "^6.6.1",
"react-router-dom": "^6.6.2",
"react-scripts": "5.0.1",
"sockette": "^2.0.6",
"typesafe-i18n": "^5.18.1",

View File

@@ -210,6 +210,7 @@ const SystemLog: FC = () => {
margin="normal"
select
>
<MenuItem value={-1}>OFF</MenuItem>
<MenuItem value={3}>ERROR</MenuItem>
<MenuItem value={4}>WARNING</MenuItem>
<MenuItem value={5}>NOTICE</MenuItem>

View File

@@ -263,9 +263,9 @@ const SettingsCustomization: FC = () => {
(new_de.ma ? '<' + new_de.ma : '')
);
// check size in bytes to match buffer in CPP, which is 4096
// check size in bytes to match buffer in CPP, which is 2048
const bytes = new TextEncoder().encode(JSON.stringify(masked_entities)).length;
if (bytes > 4000) {
if (bytes > 2000) {
enqueueSnackbar(LL.CUSTOMIZATIONS_FULL(), { variant: 'warning' });
return;
}

View File

@@ -252,7 +252,8 @@ export const BOARD_PROFILES: BoardProfiles = {
OLIMEX: 'Olimex ESP32-EVB',
OLIMEXPOE: 'Olimex ESP32-POE',
C3MINI: 'Wemos C3 Mini',
S2MINI: 'Wemos S2 Mini'
S2MINI: 'Wemos S2 Mini',
S3MINI: 'Liligo S3'
};
export interface BoardProfileName {

View File

@@ -17,11 +17,24 @@ void RestartService::restart(AsyncWebServerRequest * request) {
void RestartService::partition(AsyncWebServerRequest * request) {
const esp_partition_t * factory_partition = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_FACTORY, NULL);
if (!factory_partition) {
request->send(400); // bad request
return;
}
if (factory_partition) {
esp_ota_set_boot_partition(factory_partition);
request->onDisconnect(RestartService::restartNow);
request->send(200);
return;
}
const esp_partition_t * ota_partition = esp_ota_get_next_update_partition(NULL);
if (!ota_partition) {
request->send(400); // bad request
return;
}
uint64_t buffer;
esp_partition_read(ota_partition, 0, &buffer, 8);
if (buffer == 0xFFFFFFFFFFFFFFFF) { // partition empty
request->send(400); // bad request
return;
}
esp_ota_set_boot_partition(ota_partition);
request->onDisconnect(RestartService::restartNow);
request->send(200);
}

View File

@@ -32,8 +32,18 @@ void SystemStatus::systemStatus(AsyncWebServerRequest * request) {
root["psram_size"] = emsesp::EMSESP::system_.PSram();
root["free_psram"] = ESP.getFreePsram() / 1024;
}
const esp_partition_t * factory_partition = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_FACTORY, NULL);
root["has_loader"] = factory_partition != NULL;
const esp_partition_t * partition = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_FACTORY, NULL);
if (partition != NULL) { // factory partition found
root["has_loader"] = true;
} else { // check for not empty, smaller OTA partition
partition = esp_ota_get_next_update_partition(NULL);
if (partition) {
uint64_t buffer;
esp_partition_read(partition, 0, &buffer, 8);
const esp_partition_t * running = esp_ota_get_running_partition();
root["has_loader"] = (buffer != 0xFFFFFFFFFFFFFFFF && running->size != partition->size);
}
}
response->setLength();
request->send(response);

View File

@@ -70,6 +70,11 @@ void UploadFileService::handleUpload(AsyncWebServerRequest * request, const Stri
handleError(request, 503); // service unavailable
return;
}
#elif CONFIG_IDF_TARGET_ESP32S3
if (len > 12 && (data[0] != 0xE9 || data[12] != 3)) {
handleError(request, 503); // service unavailable
return;
}
#endif
// it's firmware - initialize the ArduinoOTA updater
if (Update.begin(fsize)) {

View File

@@ -1188,6 +1188,17 @@ rest_server.post(EMSESP_BOARDPROFILE_ENDPOINT, (req, res) => {
data.eth_power = 0
data.eth_phy_addr = 0
data.eth_clock_mode = 0
} else if (board_profile == 'S3MINI') {
// Liligo S3 mini
data.led_gpio = 17
data.dallas_gpio = 18
data.rx_gpio = 8
data.tx_gpio = 5
data.pbutton_gpio = 0
data.phy_type = 0
data.eth_power = 0
data.eth_phy_addr = 0
data.eth_clock_mode = 0
}
console.log('boardProfile POST. Sending back, profile: ' + board_profile + ', ' + 'data: ' + JSON.stringify(data))

View File

@@ -118,3 +118,15 @@ board_upload.flash_size = 4MB
board_build.partitions = esp32_partition_4M.csv
build_flags = ${common.build_flags}
build_unflags = ${common.unbuild_flags}
[env:esp32s3]
extra_scripts =
pre:scripts/build_interface.py
scripts/rename_fw.py
board = lolin_s3
platform = espressif32@5.2.0
board_upload.flash_size = 16MB
board_build.partitions = esp32_partition_16M.csv
build_flags = ${common.build_flags}
build_unflags = ${common.unbuild_flags}
upload_protocol = esptool

View File

@@ -67,6 +67,10 @@ void AnalogSensor::reload() {
#if defined(EMSESP_STANDALONE)
analog_enabled_ = true; // for local offline testing
#endif
for (auto sensor : sensors_) {
remove_ha_topic(sensor.gpio());
sensor.ha_registered = false;
}
if (!analog_enabled_) {
sensors_.clear();
return;
@@ -137,12 +141,12 @@ void AnalogSensor::reload() {
for (auto & sensor : sensors_) {
sensor.ha_registered = false; // force HA configs to be re-created
if (sensor.type() == AnalogType::ADC) {
LOG_DEBUG("Adding analog ADC sensor on GPIO%d", sensor.gpio());
LOG_DEBUG("Adding analog ADC sensor on GPIO %02d", sensor.gpio());
// analogSetPinAttenuation does not work with analogReadMilliVolts
sensor.analog_ = 0; // initialize
sensor.last_reading_ = 0;
} else if (sensor.type() == AnalogType::COUNTER) {
LOG_DEBUG("Adding analog I/O Counter sensor on GPIO%d", sensor.gpio());
LOG_DEBUG("Adding analog I/O Counter sensor on GPIO %02d", sensor.gpio());
pinMode(sensor.gpio(), INPUT_PULLUP);
#if CONFIG_IDF_TARGET_ESP32
if (sensor.gpio() == 25 || sensor.gpio() == 26) {
@@ -157,7 +161,7 @@ void AnalogSensor::reload() {
sensor.poll_ = digitalRead(sensor.gpio());
publish_sensor(sensor);
} else if (sensor.type() == AnalogType::TIMER || sensor.type() == AnalogType::RATE) {
LOG_DEBUG("Adding analog Timer/Rate sensor on GPIO%d", sensor.gpio());
LOG_DEBUG("Adding analog Timer/Rate sensor on GPIO %02d", sensor.gpio());
pinMode(sensor.gpio(), INPUT_PULLUP);
sensor.polltime_ = uuid::get_uptime();
sensor.last_polltime_ = uuid::get_uptime();
@@ -166,7 +170,7 @@ void AnalogSensor::reload() {
sensor.set_value(0);
publish_sensor(sensor);
} else if (sensor.type() == AnalogType::DIGITAL_IN) {
LOG_DEBUG("Adding analog Read sensor on GPIO%d", sensor.gpio());
LOG_DEBUG("Adding analog Read sensor on GPIO %02d", sensor.gpio());
pinMode(sensor.gpio(), INPUT_PULLUP);
sensor.set_value(digitalRead(sensor.gpio())); // initial value
sensor.set_uom(0); // no uom, just for safe measures
@@ -174,7 +178,7 @@ void AnalogSensor::reload() {
sensor.poll_ = digitalRead(sensor.gpio());
publish_sensor(sensor);
} else if (sensor.type() == AnalogType::DIGITAL_OUT) {
LOG_DEBUG("Adding analog Write sensor on GPIO%d", sensor.gpio());
LOG_DEBUG("Adding analog Write sensor on GPIO %02d", sensor.gpio());
pinMode(sensor.gpio(), OUTPUT);
#if CONFIG_IDF_TARGET_ESP32
if (sensor.gpio() == 25 || sensor.gpio() == 26) {
@@ -204,7 +208,7 @@ void AnalogSensor::reload() {
sensor.set_uom(0); // no uom, just for safe measures
publish_sensor(sensor);
} else if (sensor.type() >= AnalogType::PWM_0) {
LOG_DEBUG("Adding PWM output sensor on GPIO%d", sensor.gpio());
LOG_DEBUG("Adding PWM output sensor on GPIO %02d", sensor.gpio());
uint channel = sensor.type() - AnalogType::PWM_0;
ledcSetup(channel, sensor.factor(), 13);
ledcAttachPin(sensor.gpio(), channel);
@@ -309,7 +313,7 @@ bool AnalogSensor::update(uint8_t gpio, const std::string & name, double offset,
found_sensor = true; // found the record
// see if it's marked for deletion
if (type == AnalogType::MARK_DELETED) {
LOG_DEBUG("Removing analog sensor GPIO %d", gpio);
LOG_DEBUG("Removing analog sensor GPIO %02d", gpio);
settings.analogCustomizations.remove(AnalogCustomization);
} else {
// update existing record
@@ -318,7 +322,7 @@ bool AnalogSensor::update(uint8_t gpio, const std::string & name, double offset,
AnalogCustomization.factor = factor;
AnalogCustomization.uom = uom;
AnalogCustomization.type = type;
LOG_DEBUG("Customizing existing analog GPIO %d", gpio);
LOG_DEBUG("Customizing existing analog GPIO %02d", gpio);
}
return StateUpdateResult::CHANGED; // persist the change
}
@@ -344,7 +348,7 @@ bool AnalogSensor::update(uint8_t gpio, const std::string & name, double offset,
newSensor.uom = uom;
newSensor.type = type;
settings.analogCustomizations.push_back(newSensor);
LOG_DEBUG("Adding new customization for analog sensor GPIO %d", gpio);
LOG_DEBUG("Adding new customization for analog sensor GPIO %02d", gpio);
return StateUpdateResult::CHANGED; // persist the change
},
"local");
@@ -385,10 +389,10 @@ void AnalogSensor::remove_ha_topic(const uint8_t gpio) const {
return;
}
#ifdef EMSESP_DEBUG
LOG_DEBUG("Removing HA config for analog sensor GPIO %d", gpio);
LOG_DEBUG("Removing HA config for analog sensor GPIO %02d", gpio);
#endif
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
snprintf(topic, sizeof(topic), "sensor/%s/analogsensor_%d/config", Mqtt::basename().c_str(), gpio);
snprintf(topic, sizeof(topic), "sensor/%s/analogsensor_%02d/config", Mqtt::basename().c_str(), gpio);
Mqtt::publish_ha(topic);
}
@@ -435,7 +439,7 @@ void AnalogSensor::publish_values(const bool force) {
// create HA config
if (Mqtt::ha_enabled() && (!sensor.ha_registered || force)) {
LOG_DEBUG("Recreating HA config for analog sensor GPIO %d", sensor.gpio());
LOG_DEBUG("Recreating HA config for analog sensor GPIO %02d", sensor.gpio());
StaticJsonDocument<EMSESP_JSON_SIZE_MEDIUM> config;
@@ -445,7 +449,7 @@ void AnalogSensor::publish_values(const bool force) {
char str[50];
if (Mqtt::is_nested()) {
snprintf(str, sizeof(str), "{{value_json['%d'].value}}", sensor.gpio());
snprintf(str, sizeof(str), "{{value_json['%02d'].value}}", sensor.gpio());
} else {
snprintf(str, sizeof(str), "{{value_json['%s']}", sensor.name().c_str());
}
@@ -453,9 +457,9 @@ void AnalogSensor::publish_values(const bool force) {
char uniq_s[70];
if (Mqtt::entity_format() == 2) {
snprintf(uniq_s, sizeof(uniq_s), "%s_analogsensor_%d", Mqtt::basename().c_str(), sensor.gpio());
snprintf(uniq_s, sizeof(uniq_s), "%s_analogsensor_%02d", Mqtt::basename().c_str(), sensor.gpio());
} else {
snprintf(uniq_s, sizeof(uniq_s), "analogsensor_%d", sensor.gpio());
snprintf(uniq_s, sizeof(uniq_s), "analogsensor_%02d", sensor.gpio());
}
config["object_id"] = uniq_s;
@@ -473,7 +477,7 @@ void AnalogSensor::publish_values(const bool force) {
ids.add("ems-esp");
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
snprintf(topic, sizeof(topic), "sensor/%s/analogsensor_%d/config", Mqtt::basename().c_str(), sensor.gpio());
snprintf(topic, sizeof(topic), "sensor/%s/analogsensor_%02d/config", Mqtt::basename().c_str(), sensor.gpio());
Mqtt::publish_ha(topic, config.as<JsonObject>());
@@ -601,18 +605,22 @@ AnalogSensor::Sensor::Sensor(const uint8_t gpio, const std::string & name, const
std::string AnalogSensor::Sensor::name() const {
if (name_.empty()) {
char name[50];
snprintf(name, sizeof(name), "Analog Sensor GPIO%d", gpio_);
snprintf(name, sizeof(name), "Analog Sensor GPIO %02d", gpio_);
return name;
}
return name_;
}
// set the counter value, id is gpio-no
// set the dig_out/counter/DAC/PWM value, id is gpio-no
bool AnalogSensor::command_setvalue(const char * value, const int8_t gpio) {
float val;
if (!Helpers::value2float(value, val)) {
bool b;
if (!Helpers::value2bool(value, b)) {
return false;
}
val = b ? 1 : 0;
}
for (auto & sensor : sensors_) {
if (sensor.gpio() == gpio) {
if (sensor.type() == AnalogType::COUNTER) {

View File

@@ -694,7 +694,7 @@ void Console::load_system_commands(unsigned int context) {
std::vector<int8_t> data; // led, dallas, rx, tx, button, phy_type, eth_power, eth_phy_addr, eth_clock_mode
std::string board_profile = Helpers::toUpper(arguments.front());
if (!EMSESP::system_.load_board_profile(data, board_profile)) {
shell.println("Invalid board profile (S32, E32, MH-ET, NODEMCU, OLIMEX, OLIMEXPOE, C3MINI, S2MINI, CUSTOM)");
shell.println("Invalid board profile (S32, E32, MH-ET, NODEMCU, OLIMEX, OLIMEXPOE, C3MINI, S2MINI, S3MINI, CUSTOM)");
return;
}
EMSESP::webSettingsService.update(

View File

@@ -75,6 +75,7 @@ void DallasSensor::reload() {
});
for (auto & sensor : sensors_) {
remove_ha_topic(sensor.id());
sensor.ha_registered = false; // force HA configs to be re-created
}
}
@@ -498,7 +499,10 @@ void DallasSensor::publish_values(const bool force) {
// create the HA MQTT config
// to e.g. homeassistant/sensor/ems-esp/dallassensor_28-233D-9497-0C03/config
if (Mqtt::ha_enabled()) {
if (!sensor.ha_registered || force) {
if (!has_value && sensor.ha_registered) {
remove_ha_topic(sensor.id());
sensor.ha_registered = false;
} else if (!sensor.ha_registered || force) {
LOG_DEBUG("Recreating HA config for sensor ID %s", sensor.id().c_str());
StaticJsonDocument<EMSESP_JSON_SIZE_MEDIUM> config;

View File

@@ -236,6 +236,8 @@ enum {
#define EMSESP_PLATFORM "ESP32-C3";
#elif CONFIG_IDF_TARGET_ESP32S2
#define EMSESP_PLATFORM "ESP32-S2";
#elif CONFIG_IDF_TARGET_ESP32S3
#define EMSESP_PLATFORM "ESP32-S3";
#elif CONFIG_IDF_TARGET_ESP32 || EMSESP_STANDALONE
#define EMSESP_PLATFORM "ESP32";
#else

View File

@@ -32,7 +32,7 @@
{115, DeviceType::BOILER, "Topline/GB162", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{121, DeviceType::BOILER, "Cascade MCM10", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{122, DeviceType::BOILER, "Proline", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{123, DeviceType::BOILER, "GBx72/Trendline/Cerapur/Greenstar Si/27i", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{123, DeviceType::BOILER, "GBx72/Trendline/Cerapur/Greenstar Si/27i-30i", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{131, DeviceType::BOILER, "GB212", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{132, DeviceType::BOILER, "GC7000F", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{133, DeviceType::BOILER, "Logano GB125/KB195i/Logamatic MC110", DeviceFlags::EMS_DEVICE_FLAG_NONE},
@@ -98,6 +98,7 @@
{172, DeviceType::THERMOSTAT, "Rego 2000/3000", DeviceFlags::EMS_DEVICE_FLAG_RC300}, // 0x10
{216, DeviceType::THERMOSTAT, "CRF200S", DeviceFlags::EMS_DEVICE_FLAG_CRF | DeviceFlags::EMS_DEVICE_FLAG_NO_WRITE}, // 0x18
{246, DeviceType::THERMOSTAT, "Comfort+2RF", DeviceFlags::EMS_DEVICE_FLAG_CRF | DeviceFlags::EMS_DEVICE_FLAG_NO_WRITE}, // 0x18
{253, DeviceType::THERMOSTAT, "Rego 3000", DeviceFlags::EMS_DEVICE_FLAG_RC300}, // 0x10
// Thermostat - Sieger - 0x10 / 0x17
{ 66, DeviceType::THERMOSTAT, "ES72/RC20", DeviceFlags::EMS_DEVICE_FLAG_RC20_N}, // 0x17 or remote
@@ -120,6 +121,7 @@
// Thermostat remote - 0x38
{ 3, DeviceType::THERMOSTAT, "RT800", DeviceFlags::EMS_DEVICE_FLAG_RC100H},
{200, DeviceType::THERMOSTAT, "RC100H", DeviceFlags::EMS_DEVICE_FLAG_RC100H},
{249, DeviceType::THERMOSTAT, "TR120RF", DeviceFlags::EMS_DEVICE_FLAG_RC100H},
// Solar Modules - 0x30 (for solar), 0x2A, 0x41 (for ww)
{ 73, DeviceType::SOLAR, "SM10", DeviceFlags::EMS_DEVICE_FLAG_SM10},
@@ -140,6 +142,7 @@
{204, DeviceType::MIXER, "MP100", DeviceFlags::EMS_DEVICE_FLAG_MP}, // pool
// Heat Pumps - 0x38? This is a thermostat like RC100H
// also prod-id of wifi module and wireless base
{252, DeviceType::HEATPUMP, "HP Module", DeviceFlags::EMS_DEVICE_FLAG_NONE},
// Heat Pumps - 0x53

View File

@@ -83,6 +83,8 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
register_telegram_type(0x48B, "HPPumps", true, MAKE_PF_CB(process_HpPumps));
register_telegram_type(0x491, "HPAdditionalHeater", true, MAKE_PF_CB(process_HpAdditionalHeater));
register_telegram_type(0x499, "HPDhwSettings", true, MAKE_PF_CB(process_HpDhwSettings));
register_telegram_type(0x49C, "HPSettings2", true, MAKE_PF_CB(process_HpSettings2));
register_telegram_type(0x49D, "HPSettings3", true, MAKE_PF_CB(process_HpSettings3));
}
/*
@@ -103,7 +105,6 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &tapwaterActive_, DeviceValueType::BOOL, FL_(tapwaterActive), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &selFlowTemp_, DeviceValueType::UINT, FL_(selFlowTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_flow_temp));
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &heatingPumpMod_, DeviceValueType::UINT, FL_(heatingPumpMod), DeviceValueUOM::PERCENT);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &heatingPump2Mod_, DeviceValueType::UINT, FL_(heatingPump2Mod), DeviceValueUOM::PERCENT);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&outdoorTemp_,
DeviceValueType::SHORT,
@@ -180,6 +181,7 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
DeviceValueTAG::TAG_DEVICE_DATA, &boil2HystOff_, DeviceValueType::INT, FL_(boil2HystOff), DeviceValueUOM::DEGREES_R, MAKE_CF_CB(set_hyst2_off), 0, 20);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &setFlowTemp_, DeviceValueType::UINT, FL_(setFlowTemp), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &setBurnPow_, DeviceValueType::UINT, FL_(setBurnPow), DeviceValueUOM::PERCENT);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &absBurnPow_, DeviceValueType::UINT, FL_(absBurnPow), DeviceValueUOM::PERCENT);
register_device_value(
DeviceValueTAG::TAG_DEVICE_DATA, &selBurnPow_, DeviceValueType::UINT, FL_(selBurnPow), DeviceValueUOM::PERCENT, MAKE_CF_CB(set_burn_power), 0, 254);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &curBurnPow_, DeviceValueType::UINT, FL_(curBurnPow), DeviceValueUOM::PERCENT);
@@ -475,12 +477,21 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
10,
1000);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&auxMaxTemp_,
&auxMaxLimit_,
DeviceValueType::UINT,
DeviceValueNumOp::DV_NUMOP_MUL10,
FL_(auxMaxTemp),
DeviceValueNumOp::DV_NUMOP_DIV10,
FL_(auxMaxLimit),
DeviceValueUOM::K,
MAKE_CF_CB(set_auxMaxTemp),
MAKE_CF_CB(set_auxMaxLimit),
0,
10);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&auxLimitStart_,
DeviceValueType::UINT,
DeviceValueNumOp::DV_NUMOP_DIV10,
FL_(auxLimitStart),
DeviceValueUOM::K,
MAKE_CF_CB(set_auxLimitStart),
0,
10);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
@@ -524,6 +535,20 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
FL_(silentMode),
DeviceValueUOM::NONE,
MAKE_CF_CB(set_silentMode));
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&silentFrom_,
DeviceValueType::UINT,
DeviceValueNumOp::DV_NUMOP_MUL15,
FL_(silentFrom),
DeviceValueUOM::MINUTES,
MAKE_CF_CB(set_silentFrom));
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&silentTo_,
DeviceValueType::UINT,
DeviceValueNumOp::DV_NUMOP_MUL15,
FL_(silentTo),
DeviceValueUOM::MINUTES,
MAKE_CF_CB(set_silentTo));
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&minTempSilent_,
DeviceValueType::INT,
@@ -555,6 +580,40 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
MAKE_CF_CB(set_tempDiffCool),
3,
10);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &vp_cooling_, DeviceValueType::BOOL, FL_(vp_cooling), DeviceValueUOM::NONE, MAKE_CF_CB(set_vp_cooling));
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &heatCable_, DeviceValueType::BOOL, FL_(heatCable), DeviceValueUOM::NONE, MAKE_CF_CB(set_heatCable));
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &VC0valve_, DeviceValueType::BOOL, FL_(VC0valve), DeviceValueUOM::NONE, MAKE_CF_CB(set_VC0valve));
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &primePump_, DeviceValueType::BOOL, FL_(primePump), DeviceValueUOM::NONE, MAKE_CF_CB(set_primePump));
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&primePumpMod_,
DeviceValueType::UINT,
FL_(primePumpMod),
DeviceValueUOM::PERCENT,
MAKE_CF_CB(set_primePumpMod));
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&hp3wayValve_,
DeviceValueType::BOOL,
FL_(hp3wayValve),
DeviceValueUOM::NONE,
MAKE_CF_CB(set_hp3wayValve));
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&elHeatStep1_,
DeviceValueType::BOOL,
FL_(elHeatStep1),
DeviceValueUOM::NONE,
MAKE_CF_CB(set_elHeatStep1));
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&elHeatStep2_,
DeviceValueType::BOOL,
FL_(elHeatStep2),
DeviceValueUOM::NONE,
MAKE_CF_CB(set_elHeatStep2));
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&elHeatStep3_,
DeviceValueType::BOOL,
FL_(elHeatStep3),
DeviceValueUOM::NONE,
MAKE_CF_CB(set_elHeatStep3));
// heatpump DHW settings
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW,
&wwAlternatingOper_,
@@ -905,7 +964,7 @@ void Boiler::process_UBAParameterWW(std::shared_ptr<const Telegram> telegram) {
has_update(telegram, wwHystOff_, 4); // Hyst off (default -1)
has_update(telegram, wwFlowTempOffset_, 5); // default 40
has_update(telegram, wwCircPump_, 6); // 0xFF means on
has_enumupdate(telegram, wwCircMode_, 7, 1); // 1=1x3min 6=6x3min 7=continuous
has_update(telegram, wwCircMode_, 7); // 0=off, 1=1x3min 6=6x3min 7=continuous
has_update(telegram, wwDisinfectionTemp_, 8);
has_bitupdate(telegram, wwChargeType_, 10, 0); // 0 = charge pump, 0xff = 3-way valve
@@ -1018,9 +1077,11 @@ void Boiler::process_UBAMonitorSlow(std::shared_ptr<const Telegram> telegram) {
/*
* UBAMonitorSlowPlus2 - type 0xE3
* 88 00 E3 00 04 00 00 00 00 01 00 00 00 00 00 02 22 2B 64 46 01 00 00 61
* https://github.com/Th3M3/buderus_ems-wiki/blob/master/Quelle_08.md
* https://github.com/emsesp/EMS-ESP32/issues/908
*/
void Boiler::process_UBAMonitorSlowPlus2(std::shared_ptr<const Telegram> telegram) {
has_update(telegram, heatingPump2Mod_, 13); // Heat Pump Modulation
has_update(telegram, absBurnPow_, 13); // current burner absolute power (percent of rating plate power)
}
/*
@@ -1078,7 +1139,7 @@ void Boiler::process_UBAParameterWWPlus(std::shared_ptr<const Telegram> telegram
has_update(telegram, wwHystOff_, 8);
has_update(telegram, wwFlowTempOffset_, 9);
has_update(telegram, wwCircPump_, 10); // 0x01 means yes
has_enumupdate(telegram, wwCircMode_, 11, 1); // 1=1x3min... 6=6x3min, 7=continuous
has_update(telegram, wwCircMode_, 11); // 0=off, 1=1x3min... 6=6x3min, 7=continuous
has_update(telegram, wwDisinfectionTemp_, 12); // setting here, status in E9
has_update(telegram, wwAlternatingOper_, 14); // 0x01 means enabled
has_update(telegram, wwSelTempSingle_, 16);
@@ -1105,6 +1166,7 @@ void Boiler::process_UBAMonitorWWPlus(std::shared_ptr<const Telegram> telegram)
has_update(telegram, wwSetTemp_, 0);
has_update(telegram, wwCurTemp_, 1);
has_update(telegram, wwCurTemp2_, 3);
has_update(telegram, wwCurFlow_, 11);
has_update(telegram, wwWorkM_, 14, 3); // force to 3 bytes
has_update(telegram, wwStarts_, 17, 3); // force to 3 bytes
@@ -1439,6 +1501,8 @@ void Boiler::process_HpSilentMode(std::shared_ptr<const Telegram> telegram) {
has_update(telegram, hpHystCool_, 35); // is / 5, maybe offset swapped with pool
has_update(telegram, hpHystPool_, 33); // is / 5
has_update(telegram, hpCircPumpWw_, 46);
has_update(telegram, silentFrom_, 52); // in steps of 15 min
has_update(telegram, silentTo_, 53); // in steps of 15 min
}
// Boiler(0x08) -B-> All(0x00), ?(0x0488), data: 8E 00 00 00 00 00 01 03
@@ -1461,7 +1525,8 @@ void Boiler::process_HpAdditionalHeater(std::shared_ptr<const Telegram> telegram
has_update(telegram, auxHeaterOff_, 2);
has_update(telegram, auxHeatMode_, 4); // eco/comfort
has_update(telegram, tempParMode_, 5);
has_update(telegram, auxMaxTemp_, 14); // is *10
has_update(telegram, auxMaxLimit_, 14); // is * 10
has_update(telegram, auxLimitStart_, 15); // is * 10
has_update(telegram, auxHeaterDelay_, 16); // is / 10
}
@@ -1473,6 +1538,25 @@ void Boiler::process_HpDhwSettings(std::shared_ptr<const Telegram> telegram) {
has_update(telegram, wwEcoPlusOffTemp_, 5);
}
// 0x49C:
// Boiler(0x08) -B-> All(0x00), ?(0x049C), data: 00 00 00 00
void Boiler::process_HpSettings2(std::shared_ptr<const Telegram> telegram) {
has_update(telegram, vp_cooling_, 3);
}
// 0x49D
// Boiler(0x08) -B-> All(0x00), ?(0x049D), data: 00 00 00 00 00 00 00 00 00 00 00 00
void Boiler::process_HpSettings3(std::shared_ptr<const Telegram> telegram) {
has_update(telegram, heatCable_, 2);
has_update(telegram, VC0valve_, 3);
has_update(telegram, primePump_, 4);
has_update(telegram, primePumpMod_, 5);
has_update(telegram, hp3wayValve_, 6);
has_update(telegram, elHeatStep1_, 7);
has_update(telegram, elHeatStep2_, 8);
has_update(telegram, elHeatStep3_, 9);
}
/*
* Hybrid heatpump with telegram 0xBB is readable and writeable in boiler and thermostat
* thermostat always overwrites settings in boiler
@@ -1899,13 +1983,15 @@ bool Boiler::set_pump_delay(const char * value, const int8_t id) {
// note some boilers do not have this setting, than it's done by thermostat
// on a RC35 it's by EMSESP::send_write_request(0x37, 0x10, 2, &set, 1, 0); (set is 1,2,3) 1=hot, 2=eco, 3=intelligent
// on a RC310 it's 1=high, 2=eco
// eco key on controller: tele.05, offset 70: 0xAA =eco, 0x55= comfort, https://github.com/emsesp/EMS-ESP32/issues/908
bool Boiler::set_ww_mode(const char * value, const int8_t id) {
uint8_t set;
uint8_t comfort[] = {0x00, 0xD8, 0xEC};
uint8_t comfort[] = {0x00, 0xD8, 0xEC}; // heat, eco, intelligent
if (is_fetch(EMS_TYPE_UBAParameterWWPlus)) {
if (Helpers::value2enum(value, set, FL_(enum_comfort1))) {
write_command(EMS_TYPE_UBAParameterWWPlus, 13, comfort[set], EMS_TYPE_UBAParameterWWPlus);
write_command(0x05, 70, set ? 0xAA : 0x55); //
return true;
}
} else {
@@ -2042,7 +2128,7 @@ bool Boiler::set_ww_circulation_pump(const char * value, const int8_t id) {
}
// Set the mode of circulation, 1x3min, ... 6x3min, continuous
// true = on, false = off
// if 0-off, switching is not possibe, if 1-7 switching to off is not possible
bool Boiler::set_ww_circulation_mode(const char * value, const int8_t id) {
uint8_t v;
if (!Helpers::value2enum(value, v, FL_(enum_freq))) {
@@ -2050,9 +2136,9 @@ bool Boiler::set_ww_circulation_mode(const char * value, const int8_t id) {
}
if (is_fetch(EMS_TYPE_UBAParameterWWPlus)) {
write_command(EMS_TYPE_UBAParameterWWPlus, 11, v + 1, EMS_TYPE_UBAParameterWWPlus);
write_command(EMS_TYPE_UBAParameterWWPlus, 11, v, EMS_TYPE_UBAParameterWWPlus);
} else {
write_command(EMS_TYPE_UBAParameterWW, 7, v + 1, EMS_TYPE_UBAParameterWW);
write_command(EMS_TYPE_UBAParameterWW, 7, v, EMS_TYPE_UBAParameterWW);
}
return true;
@@ -2254,6 +2340,24 @@ bool Boiler::set_silentMode(const char * value, const int8_t id) {
return true;
}
bool Boiler::set_silentFrom(const char * value, const int8_t id) {
int v;
if (!Helpers::value2number(value, v)) {
return false;
}
write_command(0x484, 52, v / 15, 0x484);
return true;
}
bool Boiler::set_silentTo(const char * value, const int8_t id) {
int v;
if (!Helpers::value2number(value, v)) {
return false;
}
write_command(0x484, 53, v / 15, 0x484);
return true;
}
bool Boiler::set_minTempSilent(const char * value, const int8_t id) {
int v;
if (Helpers::value2temperature(value, v)) {
@@ -2310,10 +2414,10 @@ bool Boiler::set_auxHeatMode(const char * value, const int8_t id) {
return false;
}
bool Boiler::set_auxMaxTemp(const char * value, const int8_t id) {
bool Boiler::set_auxLimit(const char * value, const int8_t id) {
float v;
if (Helpers::value2float(value, v)) {
write_command(0x491, 14, (uint8_t)(v * 10), 0x491);
write_command(0x491, id, (uint8_t)(v * 10), 0x491);
return true;
}
return false;
@@ -2375,17 +2479,76 @@ bool Boiler::set_hpCircPumpWw(const char * value, const int8_t id) {
return false;
}
bool Boiler::set_vp_cooling(const char * value, const int8_t id) {
bool v;
if (Helpers::value2bool(value, v)) {
write_command(0x49C, 3, v ? 1 : 0, 0x49C);
return true;
}
return false;
}
bool Boiler::set_heatCable(const char * value, const int8_t id) {
bool v;
if (Helpers::value2bool(value, v)) {
write_command(0x49D, 2, v ? 1 : 0, 0x49D);
return true;
}
return false;
}
bool Boiler::set_VC0valve(const char * value, const int8_t id) {
bool v;
if (Helpers::value2bool(value, v)) {
write_command(0x49D, 3, v ? 1 : 0, 0x49D);
return true;
}
return false;
}
bool Boiler::set_primePump(const char * value, const int8_t id) {
bool v;
if (Helpers::value2bool(value, v)) {
write_command(0x49D, 4, v ? 1 : 0, 0x49D);
return true;
}
return false;
}
bool Boiler::set_primePumpMod(const char * value, const int8_t id) {
int v;
if (Helpers::value2number(value, v)) {
write_command(0x49D, 5, v, 0x49D);
return true;
}
return false;
}
bool Boiler::set_hp3wayValve(const char * value, const int8_t id) {
bool v;
if (Helpers::value2bool(value, v)) {
write_command(0x49D, 6, v ? 1 : 0, 0x49D);
return true;
}
return false;
}
bool Boiler::set_elHeatStep(const char * value, const int8_t id) {
bool v;
if (Helpers::value2bool(value, v)) {
write_command(0x49D, 6 + id, v ? 1 : 0, 0x49D);
return true;
}
return false;
}
// dhw alternating operation, turn on/off; heatpumps only?
bool Boiler::set_wwAlternatingOper(const char * value, const int8_t id) {
bool v;
if (!Helpers::value2bool(value, v)) {
return false;
}
// if (is_fetch(EMS_TYPE_UBAParameterWWPlus)) { // do we need/want this?
write_command(EMS_TYPE_UBAParameterWWPlus, 14, v ? 1 : 0, EMS_TYPE_UBAParameterWWPlus);
// } else {
// write_command(EMS_TYPE_UBAParameterWW, 14, v ? 0xFF : 0, EMS_TYPE_UBAParameterWW);
// }
return true;
}

View File

@@ -101,7 +101,7 @@ class Boiler : public EMSdevice {
uint8_t tapwaterActive_; // Hot tap water is on/off
uint8_t selFlowTemp_; // Selected flow temperature
uint8_t selBurnPow_; // Burner max power % (can be > 100%)
uint8_t heatingPump2Mod_; // heatpump modulation from 0xE3 (heatpumps)
uint8_t absBurnPow_; // absolute burner power in % of rating plate
uint8_t heatingPumpMod_; // Pump modulation %
int16_t outdoorTemp_; // Outside temperature
uint16_t curFlowTemp_; // Current flow temperature
@@ -218,13 +218,16 @@ class Boiler : public EMSdevice {
uint8_t pvCooling_;
uint8_t manDefrost_;
uint8_t auxHeatMode_;
uint8_t auxMaxTemp_;
uint8_t auxMaxLimit_;
uint8_t auxLimitStart_;
uint8_t auxHeaterOnly_;
uint8_t auxHeaterOff_;
uint8_t auxHeaterStatus_;
uint16_t auxHeaterDelay_;
uint8_t silentMode_;
int8_t minTempSilent_;
uint8_t silentFrom_;
uint8_t silentTo_;
int8_t tempParMode_;
int8_t auxHeatMixValve_;
uint16_t hpHystHeat_;
@@ -238,6 +241,16 @@ class Boiler : public EMSdevice {
uint8_t wwEcoOffTemp_;
uint8_t wwEcoPlusOffTemp_;
uint8_t vp_cooling_;
uint8_t heatCable_;
uint8_t VC0valve_;
uint8_t primePump_;
uint8_t primePumpMod_;
uint8_t hp3wayValve_;
uint8_t elHeatStep1_;
uint8_t elHeatStep2_;
uint8_t elHeatStep3_;
/*
// Hybrid heatpump with telegram 0xBB is readable and writeable in boiler and thermostat
// thermostat always overwrites settings in boiler
@@ -290,6 +303,8 @@ class Boiler : public EMSdevice {
void process_HpValve(std::shared_ptr<const Telegram> telegram);
void process_HpPumps(std::shared_ptr<const Telegram> telegram);
void process_HpDhwSettings(std::shared_ptr<const Telegram> telegram);
void process_HpSettings2(std::shared_ptr<const Telegram> telegram);
void process_HpSettings3(std::shared_ptr<const Telegram> telegram);
// commands - none of these use the additional id parameter
bool set_ww_mode(const char * value, const int8_t id);
@@ -361,16 +376,24 @@ class Boiler : public EMSdevice {
}
bool set_silentMode(const char * value, const int8_t id);
bool set_minTempSilent(const char * value, const int8_t id);
bool set_silentFrom(const char * value, const int8_t id);
bool set_silentTo(const char * value, const int8_t id);
bool set_additionalHeaterOnly(const char * value, const int8_t id);
bool set_additionalHeater(const char * value, const int8_t id);
bool set_additionalHeaterDelay(const char * value, const int8_t id);
bool set_tempParMode(const char * value, const int8_t id);
bool set_auxHeatMode(const char * value, const int8_t id);
bool set_auxMaxTemp(const char * value, const int8_t id);
bool set_manDefrost(const char * value, const int8_t id);
bool set_pvCooling(const char * value, const int8_t id);
bool set_hpCircPumpWw(const char * value, const int8_t id);
bool set_auxLimit(const char * value, const int8_t id);
inline bool set_auxMaxLimit(const char * value, const int8_t id) {
return set_auxLimit(value, 14);
}
inline bool set_auxLimitStart(const char * value, const int8_t id) {
return set_auxLimit(value, 15);
}
bool set_hpHyst(const char * value, const int8_t id);
inline bool set_hpHystHeat(const char * value, const int8_t id) {
return set_hpHyst(value, 37);
@@ -398,6 +421,22 @@ class Boiler : public EMSdevice {
inline bool set_wwEcoPlusOffTemp(const char * value, const int8_t id) {
return set_wwOffTemp(value, 5);
}
bool set_vp_cooling(const char * value, const int8_t id);
bool set_heatCable(const char * value, const int8_t id);
bool set_VC0valve(const char * value, const int8_t id);
bool set_primePump(const char * value, const int8_t id);
bool set_primePumpMod(const char * value, const int8_t id);
bool set_hp3wayValve(const char * value, const int8_t id);
bool set_elHeatStep(const char * value, const int8_t id);
inline bool set_elHeatStep1(const char * value, const int8_t id) {
return set_elHeatStep(value, 1);
}
inline bool set_elHeatStep2(const char * value, const int8_t id) {
return set_elHeatStep(value, 2);
}
inline bool set_elHeatStep3(const char * value, const int8_t id) {
return set_elHeatStep(value, 3);
}
bool set_wwAlternatingOper(const char * value, const int8_t id);
bool set_wwAltOpPrio(const char * value, const int8_t id);
inline bool set_wwAltOpPrioHeat(const char * value, const int8_t id) {

View File

@@ -74,6 +74,12 @@ Heatsource::Heatsource(uint8_t device_type, uint8_t device_id, uint8_t product_i
DeviceValueNumOp::DV_NUMOP_DIV10,
FL_(aCylBottomTemp),
DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_AHS1 + ahs,
&flueGasTemp_,
DeviceValueType::SHORT,
DeviceValueNumOp::DV_NUMOP_DIV10,
FL_(flueGasTemp),
DeviceValueUOM::DEGREES);
// register_device_value(DeviceValueTAG::TAG_AHS1 + ahs, &valveByPass_, DeviceValueType::BOOL, nullptr, FL_(valveByPass), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_AHS1 + ahs, &valveBuffer_, DeviceValueType::UINT, FL_(valveBuffer), DeviceValueUOM::PERCENT);
register_device_value(DeviceValueTAG::TAG_AHS1 + ahs, &valveReturn_, DeviceValueType::UINT, FL_(valveReturn), DeviceValueUOM::PERCENT);
@@ -161,6 +167,12 @@ Heatsource::Heatsource(uint8_t device_type, uint8_t device_id, uint8_t product_i
DeviceValueTAG::TAG_AHS1 + ahs, &blockHyst_, DeviceValueType::INT, FL_(blockHyst), DeviceValueUOM::DEGREES_R, MAKE_CF_CB(set_blockHyst), 0, 50);
register_device_value(
DeviceValueTAG::TAG_AHS1 + ahs, &releaseWait_, DeviceValueType::UINT, FL_(releaseWait), DeviceValueUOM::MINUTES, MAKE_CF_CB(set_releaseWait), 0, 240);
register_device_value(DeviceValueTAG::TAG_AHS1 + ahs, &burner_, DeviceValueType::BOOL, FL_(burner), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_AHS1 + ahs, &aPump_, DeviceValueType::BOOL, FL_(aPump), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_AHS1 + ahs, &heatRequest_, DeviceValueType::UINT, FL_(heatRequest), DeviceValueUOM::PERCENT);
register_device_value(DeviceValueTAG::TAG_AHS1 + ahs, &blockRemain_, DeviceValueType::UINT, FL_(blockRemain), DeviceValueUOM::MINUTES);
register_device_value(DeviceValueTAG::TAG_AHS1 + ahs, &blockRemainWw_, DeviceValueType::UINT, FL_(blockRemainWw), DeviceValueUOM::MINUTES);
}
// cascaded heating sources, only some values per individual heatsource (hs)
@@ -214,6 +226,7 @@ void Heatsource::process_UBAMonitorFastPlus(std::shared_ptr<const Telegram> tele
void Heatsource::process_amTempMessage(std::shared_ptr<const Telegram> telegram) {
has_update(telegram, curFlowTemp_, 0); // TB4
has_update(telegram, retTemp_, 2); // TR2
has_update(telegram, flueGasTemp_, 4);
has_update(telegram, aFlowTemp_, 6);
has_update(telegram, aRetTemp_, 8);
has_update(telegram, cylTopTemp_, 10);
@@ -226,14 +239,11 @@ void Heatsource::process_amTempMessage(std::shared_ptr<const Telegram> telegram)
void Heatsource::process_amStatusMessage(std::shared_ptr<const Telegram> telegram) {
has_update(telegram, aPumpMod_, 0); // PR1
// offset 1: bitfield 01-pump on, 02-VR1 opening, 04-VR1 closing, 08-VB1 opening, 10-VB1 closing
// uint8_t stat = aPump_ | setValveBuffer_ << 3 | setValveReturn_ << 1;
// if (telegram->read_value(stat, 1)) {
// has_update(aPump_, stat & 0x01);
// has_update(valveBuffer_, (stat >> 3) & 0x03);
// has_update(valveReturn_, (stat >> 1) & 0x03);
// }
// actually we dont know the offset of VR2
// has_update(telegram, valveBypass_, ?); // VR2
has_bitupdate(telegram, burner_, 1, 5);
has_bitupdate(telegram, aPump_, 1, 0);
has_update(telegram, heatRequest_, 2); // percent
has_update(telegram, valveReturn_, 4); // VR1, percent
has_update(telegram, valveBuffer_, 5); // VB1, percent
}
@@ -275,6 +285,8 @@ void Heatsource::process_amCommandMessage(std::shared_ptr<const Telegram> telegr
// Rx: 60 00 FF 00 04 50 00 FF 00 FF FF 00 0D 00 01 00 00 00 00 01 03 01 00 03 00 2D 19 C8 02 94 00 4A
// Rx: 60 00 FF 19 04 50 00 FF FF 39
void Heatsource::process_amExtraMessage(std::shared_ptr<const Telegram> telegram) {
has_update(telegram, blockRemain_, 24); // minutes
has_update(telegram, blockRemainWw_, 25); // minutes
}
#pragma GCC diagnostic pop

View File

@@ -44,9 +44,16 @@ class Heatsource : public EMSdevice {
uint8_t aPumpMod_; // PR1 - percent
uint8_t valveBuffer_; // VB1
uint8_t valveReturn_; // VR1
uint16_t flueGasTemp_;
// uint8_t valveBypass_; // VR2 position unknown
// uint8_t heatSource_; // OEV
uint8_t burner_; // bit 5, offset 1, 54E
uint8_t aPump_; // bit 0, offset 1, 54E
uint8_t heatRequest_; // offset 2, percent
uint8_t blockRemain_; // offset 24, 550 min
uint8_t blockRemainWw_; // offset 25, 550 min
// Settings:
uint8_t vr2Config_; // pos 12: off(00)/Keelbypass(01)/(hc1pump(02) only standalone)
uint8_t ahsActivated_; // pos 00: Alternate heat source activation: No(00),Yes(01)

View File

@@ -493,6 +493,7 @@ void EMSdevice::add_device_value(uint8_t tag,
std::string custom_fullname = std::string(""); // custom fullname
auto short_name = name[0]; // entity name
bool has_cmd = (f != nullptr); // is it a command?
bool ignore = false; // ignore this entity?
// get fullname, getting translation if it exists
const char * const * fullname;
@@ -524,6 +525,7 @@ void EMSdevice::add_device_value(uint8_t tag,
// get Mask
uint8_t mask = Helpers::hextoint(entity_id.substr(0, 2).c_str());
state = mask << 4; // set state high bits to flag, turn off active and ha flags
ignore = (mask & 0x80) == 0x80; // do not register
// see if there is a custom name in the entity string
if (has_custom_name) {
custom_fullname = entity_id.substr(custom_name_pos + 1);
@@ -534,6 +536,9 @@ void EMSdevice::add_device_value(uint8_t tag,
}
}
});
if (ignore) {
return;
}
// add the device entity
devicevalues_.emplace_back(

View File

@@ -1019,12 +1019,6 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, const
device_p->device_type = DeviceType::HEATSOURCE;
break;
}
} else if (device.device_type == DeviceType::HEATSOURCE) {
device_p = &device;
if (device_id == EMSdevice::EMS_DEVICE_ID_BOILER) { // AHS as only heatsource on d 0x08
device_p->device_type = DeviceType::BOILER;
}
break;
} else {
// it's not a boiler, but we have a match
device_p = &device;
@@ -1045,6 +1039,17 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, const
auto device_type = device_p->device_type;
auto flags = device_p->flags;
// check for integrated modules with same product id
if (device_type == DeviceType::HEATPUMP) {
if (device_id == EMSdevice::EMS_DEVICE_ID_MODEM) {
device_type = DeviceType::GATEWAY;
name = "WiFi module";
} else if (device_id == EMSdevice::EMS_DEVICE_ID_RFBASE) {
device_type = DeviceType::CONNECT;
name = "Wireless sensor base";
}
}
// empty reply to version, read a generic device from database
if (product_id == 0) {
// check for known device IDs

View File

@@ -249,10 +249,11 @@ char * Helpers::render_value(char * result, const double value, const int8_t for
return nullptr;
}
uint32_t p[] = {0, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000};
uint32_t p[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000};
char * ret = result;
auto whole = (int32_t)value;
double v = value < 0 ? value - 1.0 / (2 * p[format]) : value + 1.0 / (2 * p[format]);
auto whole = (int32_t)v;
itoa(whole, result, 10);
@@ -261,7 +262,7 @@ char * Helpers::render_value(char * result, const double value, const int8_t for
}
*result++ = '.';
auto decimal = abs((int32_t)((value - whole) * p[format]));
auto decimal = abs((int32_t)((v - whole) * p[format]));
for (int8_t i = 1; i < format; i++) {
if (decimal < p[i]) {
*result++ = '0'; // add leading zeros
@@ -598,14 +599,14 @@ bool Helpers::value2bool(const char * value, bool & value_b) {
std::string bool_str = toLower(value);
if ((bool_str == std::string(Helpers::translated_word(FL_(on)))) || (bool_str == toLower(Helpers::translated_word(FL_(ON))))
|| (bool_str == "on") || (bool_str == "1") || (bool_str == "true")) {
if ((bool_str == std::string(Helpers::translated_word(FL_(on)))) || (bool_str == toLower(Helpers::translated_word(FL_(ON)))) || (bool_str == "on")
|| (bool_str == "1") || (bool_str == "true")) {
value_b = true;
return true; // is a bool
}
if ((bool_str == std::string(Helpers::translated_word(FL_(off)))) || (bool_str == toLower(Helpers::translated_word(FL_(OFF))))
|| (bool_str == "off") || (bool_str == "0") || (bool_str == "false")) {
if ((bool_str == std::string(Helpers::translated_word(FL_(off)))) || (bool_str == toLower(Helpers::translated_word(FL_(OFF)))) || (bool_str == "off")
|| (bool_str == "0") || (bool_str == "false")) {
value_b = false;
return true; // is a bool
}
@@ -767,7 +768,7 @@ const char * Helpers::translated_word(const char * const * strings, const bool f
}
// see how many translations we have for this entity. if there is no translation for this, revert to EN
if (force_en || (Helpers::count_items(strings) >= language_index + 1 && strlen(strings[language_index]))) {
if (!force_en && (Helpers::count_items(strings) >= language_index + 1 && strlen(strings[language_index]))) {
index = language_index;
}
return strings[index];

View File

@@ -227,7 +227,7 @@ MAKE_PSTR(tag_boiler_data_ww_mqtt, "ww")
MAKE_PSTR(tag_device_data_ww_mqtt, "")
// Home Assistant - this is special and has no translations
MAKE_PSTR_LIST(climate, "")
MAKE_PSTR_LIST(climate, "HA climate config creation")
// syslog
MAKE_PSTR_LIST(list_syslog_level, "off", "emerg", "alert", "crit", "error", "warn", "notice", "info", "debug", "trace", "all")
@@ -249,7 +249,7 @@ MAKE_PSTR_ENUM(enum_progMode, FL_(prog1), FL_(prog2))
MAKE_PSTR_ENUM(enum_progMode4, FL_(proga), FL_(progb), FL_(progc), FL_(progd), FL_(proge), FL_(progf))
MAKE_PSTR_ENUM(enum_climate, FL_(seltemp), FL_(roomtemp))
MAKE_PSTR_ENUM(enum_charge, FL_(chargepump), FL_(3wayvalve))
MAKE_PSTR_ENUM(enum_freq, FL_(1x3min), FL_(2x3min), FL_(3x3min), FL_(4x3min), FL_(5x3min), FL_(6x3min), FL_(continuous))
MAKE_PSTR_ENUM(enum_freq, FL_(off), FL_(1x3min), FL_(2x3min), FL_(3x3min), FL_(4x3min), FL_(5x3min), FL_(6x3min), FL_(continuous))
MAKE_PSTR_ENUM(enum_off_time_date_manual, FL_(off), FL_(time), FL_(date), FL_(manual))
MAKE_PSTR_ENUM(enum_comfort, FL_(hot), FL_(eco), FL_(intelligent))
MAKE_PSTR_ENUM(enum_comfort1, FL_(high_comfort), FL_(eco))

View File

@@ -270,8 +270,8 @@ MAKE_PSTR_LIST(heatingActive, "heatingactive", "heating active", "Heizen aktiv",
MAKE_PSTR_LIST(tapwaterActive, "tapwateractive", "tapwater active", "Warmwasser aktiv", "Warm water actief", "Varmvatten aktiv", "c.w.u. aktywne", "varmtvann aktiv", "eau chaude active")
MAKE_PSTR_LIST(selFlowTemp, "selflowtemp", "selected flow temperature", "Sollwert Vorlauftemperatur", "Ingestelde aanvoertemperatuur", "Börvärde Flödestemperatur", "wybrana temperatura zasilania", "valgt turtemperatur", "température de flux selectionnée")
MAKE_PSTR_LIST(selBurnPow, "selburnpow", "burner selected max power", "Sollwert Brennerleistung", "Ingestelde maximale brandervermogen", "Brännare vald maxeffekt", "wybrana moc źródła ciepła", "settpunkt brennerkapasitet", "puissance max du brûleur selectionnée")
MAKE_PSTR_LIST(absBurnPow, "absburnpow", "burner current power (absolute)", "Brennerleistung (absolut)", "Brandervermogen (abs)", "Värmepanna aktuell effekt (abs)", "aktualna moc źródła ciepła (abs)", "brennereffekt", "puissance du brûleur actuelle (abs)")
MAKE_PSTR_LIST(heatingPumpMod, "heatingpumpmod", "heating pump modulation", "Heizungspumpe 1 Modulation", "Modulatie verwarmingspomp", "Modulering Värmepump", "wysterowanie pompy c.o.", "varmepumpemodulering", "modulation de la pompe à chaleur")
MAKE_PSTR_LIST(heatingPump2Mod, "heatingpump2mod", "heating pump 2 modulation", "Heizungspumpe 2 Modulation", "Modulatie verwarmingspomp 2", "Modulering Värmepump 2", "wysterowanie pompy c.o. 2", "varmepumpe 2 modulering", "modulation de la pompe à chaleur 2")
MAKE_PSTR_LIST(outdoorTemp, "outdoortemp", "outside temperature", "Aussentemperatur", "Buitentemperatuur", "Utomhustemperatur", "temperatura zewnętrzna", "utetemperatur", "température extérieure")
MAKE_PSTR_LIST(curFlowTemp, "curflowtemp", "current flow temperature", "aktuelle Vorlauftemperatur", "Huidige aanvoertemperatuur", "Flödestemperatur", "temperatura zasilania", "aktuell strømmetemperatur", "température actuelle du flux")
MAKE_PSTR_LIST(retTemp, "rettemp", "return temperature", "Rücklauftemperatur", "Retourtemperatuur", "Returtemperatur", "temperatura powrotu", "returtemperatur", "température de retour")
@@ -395,16 +395,27 @@ MAKE_PSTR_LIST(hpHystCool, "hphystcool", "on/off hyst cool", "Schalthysterese K
MAKE_PSTR_LIST(hpHystPool, "hphystpool", "on/off hyst pool", "Schalthysterese Pool", "an/uit-hysteresis in zwembadbedri", "Hystereses Pool", "histereza wł./wył. podgrzewania basenu", "", "Hystérésis Marche en mode piscine") // TODO translate
MAKE_PSTR_LIST(tempDiffHeat, "tempdiffheat", "temp. diff. TC3/TC0 heat", "Temp.diff. TC3/TC0 Heizen", "Temp.vers. TC3/TC0 verw", "Delta(T) TC3/TC0 Uppvärm.", "różnica temperatur TC3/TC0 w trakcie ogrzewania", "", "Delta T TC3/TC0 Chauff") // TODO translate
MAKE_PSTR_LIST(tempDiffCool, "tempdiffcool", "temp. diff. TC3/TC0 cool", "Temp.diff. TC3/TC0 Kühlen", "Temp.vers. TC3/TC0 koel.", "Delta(T) TC3/TC0 Kyla", "różnica temperatur TC3/TC0 w trakcie chłodzenia", "", "Delta T TC3/TC0 Refroid.") // TODO translate
MAKE_PSTR_LIST(silentFrom, "silentfrom", "silent mode from", "Silentmodus Start") // TODO translate
MAKE_PSTR_LIST(silentTo, "silentto", "silent mode to", "Silentmodus Ende") // TODO translate
MAKE_PSTR_LIST(wwComfOffTemp, "wwcomfoff", "comfort switch off", "Komfort Ausschalttemp", "Comfort Uitschakeltemp.", "Komfortläge avstängingstemp.", "temperatura wyłączania w trybie komfort", "", "Confort Temp. d'arrêt") // TODO translate
MAKE_PSTR_LIST(wwEcoOffTemp, "wwecooff", "eco switch off", "ECO Ausschalttemp", "Eco Uitschakeltemp.", "Ekoläge avstängningstemp.", "temperatura wyłączania w trybie eko", "", "Eco Temp. d'arrêt") // TODO translate
MAKE_PSTR_LIST(wwEcoPlusOffTemp, "wwecoplusoff", "eco+ switch off", "ECO+ Ausschalttemp", "Eco+ Uitschakeltemp.", "Eko+ avstängningstemp.", "temperatura wyłączania w trybie eko+", "", "Eco+ Temp. d'arrêt") // TODO translate
MAKE_PSTR_LIST(auxHeatMode, "auxheatrmode", "aux heater mode", "Modus Zusatzheizer", "", "", "", "", "") // TODO translate
MAKE_PSTR_LIST(auxMaxTemp, "auxmaxtemp", "aux heater max temperature", "Zusatzheizer Maximaltemp.", "", "", "", "", "") // TODO translate
MAKE_PSTR_LIST(auxMaxLimit, "auxmaxlimit", "aux heater max limit", "Zusatzheizer max. Grenze", "", "", "", "", "") // TODO translate
MAKE_PSTR_LIST(auxLimitStart, "auxlimitstart", "aux heater limit start", "Zusatzheizer Grenze Start", "", "", "", "", "") // TODO translate
MAKE_PSTR_LIST(manDefrost, "mandefrost", "manual defrost", "Manuelle Enteisung", "", "", "", "", "") // TODO translate
MAKE_PSTR_LIST(pvCooling, "pvcooling", "Cooling only with PV", "Kühlen nur mit PV", "", "", "", "", "") // TODO translate
MAKE_PSTR_LIST(hpCircPumpWw, "hpcircpumpww", "circulation pump available during dhw", "", "", "", "", "", "") // TODO translate
MAKE_PSTR_LIST(vp_cooling, "vpcooling", "valve/pump cooling") // TODO translate
MAKE_PSTR_LIST(VC0valve, "vc0valve", "VC0 valve") // TODO translate
MAKE_PSTR_LIST(primePump, "primepump", "primary heatpump") // TODO translate
MAKE_PSTR_LIST(primePumpMod, "primepumpmod", "primary heatpump modulation") // TODO translate
MAKE_PSTR_LIST(hp3wayValve, "hp3way", "3-way valve") // TODO translate
MAKE_PSTR_LIST(elHeatStep1, "elheatstep1", "el. heater step 1") // TODO translate
MAKE_PSTR_LIST(elHeatStep2, "elheatstep2", "el. heater step 2") // TODO translate
MAKE_PSTR_LIST(elHeatStep3, "elheatstep3", "el. heater step 3") // TODO translate
MAKE_PSTR_LIST(wwAlternatingOper, "wwalternatingop", "alternating operation", "", "", "", "praca naprzemienna", "", "") // TODO translate
MAKE_PSTR_LIST(wwAltOpPrioHeat, "wwaltopprioheat", "prioritise heating during dhw", "", "", "", "czas na ogrzewanie w trakcie c.w.u", "", "") // TODO translate
MAKE_PSTR_LIST(wwAltOpPrioWw, "wwaltopprioww", "prioritise dhw during heating", "", "", "", "czas na c.w.u w trakcie ogrzewania", "", "") // TODO translate
@@ -442,8 +453,14 @@ MAKE_PSTR_LIST(sysRetTemp, "sysrettemp", "system return temperature", "System R
MAKE_PSTR_LIST(valveByPass, "valvebypass", "bypass valve", "Bypass-Ventil", "Bypass klep", "Bypassventil", "zawór obejścia", "", "vanne dérivation") // TODO translate
MAKE_PSTR_LIST(valveBuffer, "valvebuffer", "buffer valve", "Puffer-Ventil", "Bufferklep", "Buffertventil", "zawór bufora", "", "vanne tampon") // TODO translate
MAKE_PSTR_LIST(valveReturn, "valvereturn", "return valve", "Rückfluss-Ventil", "Retourklep", "Returventil", "zawór powrotu", "", "vanne retour") // TODO translate
MAKE_PSTR_LIST(aPumpMod, "altpumpmod", "alternative hs pump modulation", "Alternativer WE Pumpenmodulation", "Alternatieve warmtebron pomp modulatie", "Alternativ Pumpmodulering Värmekälla", "modulacja pompy alternatywnego źródła ciepła", "alternativ pumpemodulering varmekilde", "modulation alternative pompe hs")
MAKE_PSTR_LIST(aPumpMod, "apumpmod", "alternative hs pump modulation", "Alternativer WE Pumpenmodulation", "Alternatieve warmtebron pomp modulatie", "Alternativ Pumpmodulering Värmekälla", "modulacja pompy alternatywnego źródła ciepła", "alternativ pumpemodulering varmekilde", "modulation alternative pompe hs")
MAKE_PSTR_LIST(heatSource, "heatsource", "alternative heating active", "Alternativer Wärmeerzeuger aktiv", "Alternatieve warmtebron aktief", "Alternativ Värmekälla aktiv", "aktywne alternatywne źródło ciepła", "alternativ varmekilde aktiv", "chauffage alternatif actif")
MAKE_PSTR_LIST(aPump, "apump", "alternative hs pump", "Alternativer WE Pumpe", "Alternatieve warmtebron pomp", "Alternativ Pump Värmekälla", "pompy alternatywnego źródła ciepła", "alternativ pumpe varmekilde", "alternative pompe hs")
MAKE_PSTR_LIST(burner, "burner", "burner", "Brenner", "", "", "", "", "") // TODO translate
MAKE_PSTR_LIST(heatRequest, "heatrequest", "heat request", "Wärmeanforderung", "", "", "", "", "") // TODO translate
MAKE_PSTR_LIST(blockRemain, "blockremain", "remaining blocktime", "verbleibende Blockzeit", "", "", "", "", "") // TODO translate
MAKE_PSTR_LIST(blockRemainWw, "blockremainww", "remaining blocktime dhw", "verbleibende Blockzeit WW", "", "", "", "", "") // TODO translate
MAKE_PSTR_LIST(flueGasTemp, "fluegastemp", "flue gas temperature", "Abgastemperatur", "", "", "", "", "") // TODO translate
MAKE_PSTR_LIST(vr2Config, "vr2config", "vr2 configuration", "VR2 Konfiguration", "VR2 configuratie", "VR2 Konfiguration", "konfiguracja VR2", "vr2 konfigurasjon", "configuration vr2")
MAKE_PSTR_LIST(ahsActivated, "ahsactivated", "alternate heat source activation", "Alt. Wärmeerzeuger aktiviert", "Altenatieve warmtebron geactiveerd", "Alternativ värmekälla aktivering", "aktywacja alternatywnego źródła ciepła", "alternativ varmekilde aktivering", "activation source chaleur alternative")

View File

@@ -33,6 +33,8 @@
#include "../esp32s2/rom/rtc.h"
#elif CONFIG_IDF_TARGET_ESP32C3
#include "../esp32c3/rom/rtc.h"
#elif CONFIG_IDF_TARGET_ESP32S3
#include "../esp32s3/rom/rtc.h"
#else
#error Target CONFIG_IDF_TARGET is not supported
#endif
@@ -369,6 +371,8 @@ bool System::is_valid_gpio(uint8_t pin) {
#elif CONFIG_IDF_TARGET_ESP32C3
// https://www.wemos.cc/en/latest/c3/c3_mini.html
if ((pin >= 11 && pin <= 19) || (pin > 21)) {
#elif CONFIG_IDF_TARGET_ESP32S3
if ((pin >= 19 && pin <= 20) || (pin >= 22 && pin <= 37) || (pin >= 39 && pin <= 42) || (pin > 48)) {
#endif
return false; // bad pin
}
@@ -1418,7 +1422,9 @@ bool System::load_board_profile(std::vector<int8_t> & data, const std::string &
} else if (board_profile == "C3MINI") {
data = {7, 1, 4, 5, 9, PHY_type::PHY_TYPE_NONE, 0, 0, 0}; // Lolin C3 Mini
} else if (board_profile == "S2MINI") {
data = {15, 7, 11, 12, 0, PHY_type::PHY_TYPE_NONE, 0, 0, 0}; //Lolin S2 Mini
data = {15, 7, 11, 12, 0, PHY_type::PHY_TYPE_NONE, 0, 0, 0}; // Lolin S2 Mini
} else if (board_profile == "S3MINI") {
data = {17, 18, 8, 5, 0, PHY_type::PHY_TYPE_NONE, 0, 0, 0}; // Liligo S3
} else if (board_profile == "CUSTOM") {
// send back current values
data = {(int8_t)EMSESP::system_.led_gpio_,

View File

@@ -1 +1 @@
#define EMSESP_APP_VERSION "3.5.0-dev.15"
#define EMSESP_APP_VERSION "3.5.0-dev.16"

View File

@@ -57,6 +57,9 @@ void WebLogService::start() {
limit_log_messages_ = maximum_log_messages_;
compact_ = settings.weblog_compact;
uuid::log::Logger::register_handler(this, (uuid::log::Level)settings.weblog_level);
if ((uuid::log::Level)settings.weblog_level == uuid::log::Level::OFF) {
log_messages_.clear();
}
});
}
@@ -72,6 +75,9 @@ void WebLogService::log_level(uuid::log::Level level) {
},
"local");
uuid::log::Logger::register_handler(this, level);
if (level == uuid::log::Level::OFF) {
log_messages_.clear();
}
}
size_t WebLogService::num_log_messages() const {

View File

@@ -91,6 +91,8 @@ StateUpdateResult WebSettings::update(JsonObject & root, WebSettings & settings)
settings.board_profile = root["board_profile"] | "C3MINI";
#elif CONFIG_IDF_TARGET_ESP32S2
settings.board_profile = root["board_profile"] | "S2MINI";
#elif CONFIG_IDF_TARGET_ESP32S3
settings.board_profile = root["board_profile"] | "S3MINI";
#elif CONFIG_IDF_TARGET_ESP32
settings.board_profile = root["board_profile"] | EMSESP_DEFAULT_BOARD_PROFILE;
#endif