Merge remote-tracking branch 'origin/dev'

This commit is contained in:
proddy
2022-09-18 14:33:23 +02:00
104 changed files with 7102 additions and 17907 deletions

View File

@@ -403,12 +403,19 @@ void AnalogSensor::publish_values(const bool force) {
snprintf(str, sizeof(str), "{{value_json['%d'].value}}", sensor.gpio());
config["val_tpl"] = str;
snprintf(str, sizeof(str), "Analog Sensor %s", sensor.name().c_str());
snprintf(str, sizeof(str), "analog_sensor_%s", sensor.name().c_str());
config["object_id"] = str;
snprintf(str, sizeof(str), "%s", sensor.name().c_str());
config["name"] = str;
snprintf(str, sizeof(str), "analogsensor_%d", sensor.gpio());
config["uniq_id"] = str;
if (sensor.uom() != DeviceValueUOM::NONE) {
config["unit_of_meas"] = EMSdevice::uom_to_string(sensor.uom());
}
JsonObject dev = config.createNestedObject("dev");
JsonArray ids = dev.createNestedArray("ids");
ids.add("ems-esp");

View File

@@ -45,7 +45,7 @@ class AnalogSensor {
std::string name() const;
void set_name(const std::string & name) {
name_ = name;
name_ = name;
}
uint8_t gpio() const {

View File

@@ -276,7 +276,7 @@ uint8_t Command::call(const uint8_t device_type, const char * cmd, const char *
}
}
// call the function baesed on type
// call the function based on type
if (cf->cmdfunction_json_) {
return_code = ((cf->cmdfunction_json_)(value, id, output)) ? CommandRet::OK : CommandRet::ERROR;
}

View File

@@ -227,10 +227,6 @@ void EMSESPShell::add_console_commands() {
EMSESP::webSettingsService.read([&](WebSettings & settings) {
shell.printfln(F_(tx_mode_fmt), settings.tx_mode);
shell.printfln(F_(bus_id_fmt), settings.ems_bus_id);
char buffer[4];
shell.printfln(F_(master_thermostat_fmt),
settings.master_thermostat == 0 ? read_flash_string(F_(auto)).c_str()
: Helpers::hextoa(buffer, settings.master_thermostat));
shell.printfln(F_(board_profile_fmt), settings.board_profile.c_str());
});
});
@@ -261,23 +257,6 @@ void EMSESPShell::add_console_commands() {
}
});
commands->add_command(ShellContext::MAIN,
CommandFlags::ADMIN,
flash_string_vector{F_(set), F_(master), F_(thermostat)},
flash_string_vector{F_(deviceid_mandatory)},
[](Shell & shell, const std::vector<std::string> & arguments) {
uint8_t value = Helpers::hextoint(arguments.front().c_str());
EMSESP::webSettingsService.update(
[&](WebSettings & settings) {
settings.master_thermostat = value;
EMSESP::actual_master_thermostat(value); // set the internal value too
char buffer[5];
shell.printfln(F_(master_thermostat_fmt), !value ? read_flash_string(F_(auto)).c_str() : Helpers::hextoa(buffer, value));
return StateUpdateResult::CHANGED;
},
"local");
});
#ifndef EMSESP_STANDALONE
commands->add_command(ShellContext::MAIN,
CommandFlags::USER,
@@ -419,7 +398,7 @@ void EMSESPShell::add_console_commands() {
shell.print(F("Available commands are: "));
Command::show(shell, device_type, false); // non-verbose mode
} else if (return_code != CommandRet::OK) {
shell.println(F("Bad syntax"));
shell.printfln(F("Bad syntax (error code %d)"), return_code);
}
},
[&](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments) -> std::vector<std::string> {

View File

@@ -497,7 +497,10 @@ void DallasSensor::publish_values(const bool force) {
snprintf(str, sizeof(str), "{{value_json['%s'].temp}}", sensor.id().c_str());
config["val_tpl"] = str;
snprintf(str, sizeof(str), "Temperature Sensor %s", sensor.name().c_str());
snprintf(str, sizeof(str), "temperature_sensor_%s", sensor.name().c_str());
config["object_id"] = str;
snprintf(str, sizeof(str), "%s", sensor.name().c_str());
config["name"] = str;
snprintf(str, sizeof(str), "dallasensor_%s", sensor.id().c_str());

View File

@@ -57,7 +57,7 @@ class DallasSensor {
std::string name() const;
void set_name(const std::string & name) {
name_ = name;
name_ = name;
}
bool apply_customization();

View File

@@ -52,10 +52,6 @@
#define EMSESP_DEFAULT_TRACELOG_RAW false
#endif
#ifndef EMSESP_DEFAULT_MASTER_THERMOSTAT
#define EMSESP_DEFAULT_MASTER_THERMOSTAT 0 // not set
#endif
#ifndef EMSESP_DEFAULT_SHOWER_TIMER
#define EMSESP_DEFAULT_SHOWER_TIMER false
#endif

View File

@@ -42,11 +42,12 @@
{173, DeviceType::BOILER, F("Geo 5xx"), DeviceFlags::EMS_DEVICE_FLAG_HEATPUMP},
{195, DeviceType::BOILER, F("Condens 5000i/Greenstar 8000"), DeviceFlags::EMS_DEVICE_FLAG_NONE},
{203, DeviceType::BOILER, F("Logamax U122/Cerapur"), DeviceFlags::EMS_DEVICE_FLAG_NONE},
{206, DeviceType::BOILER, F("Ecomline Excellent"), DeviceFlags::EMS_DEVICE_FLAG_NONE},
{208, DeviceType::BOILER, F("Logamax Plus/GB192/Condens GC9000"), DeviceFlags::EMS_DEVICE_FLAG_NONE},
{210, DeviceType::BOILER, F("Cascade MC400"), DeviceFlags::EMS_DEVICE_FLAG_NONE},
{211, DeviceType::BOILER, F("EasyControl Adapter"), DeviceFlags::EMS_DEVICE_FLAG_NONE},
{228, DeviceType::BOILER, F("Alternative Heatsource"), DeviceFlags::EMS_DEVICE_FLAG_AM200},
{234, DeviceType::BOILER, F("Logamax Plus GB122/Condense 2300"), DeviceFlags::EMS_DEVICE_FLAG_NONE},
{206, DeviceType::BOILER, F("Ecomline Excellent"), DeviceFlags::EMS_DEVICE_FLAG_NONE},
// Controllers - 0x09 / 0x10 / 0x50
{ 68, DeviceType::CONTROLLER, F("BC10/RFM20"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09
@@ -111,6 +112,9 @@
{191, DeviceType::THERMOSTAT, F("FR120"), DeviceFlags::EMS_DEVICE_FLAG_JUNKERS | DeviceFlags::EMS_DEVICE_FLAG_JUNKERS_OLD}, // older model
{192, DeviceType::THERMOSTAT, F("FW120"), DeviceFlags::EMS_DEVICE_FLAG_JUNKERS},
// Thermostat remote - 0x38
{200, DeviceType::THERMOSTAT, F("RC100H"), DeviceFlags::EMS_DEVICE_FLAG_RC100H},
// Solar Modules - 0x30 (for solar), 0x2A, 0x41 (for ww)
{ 73, DeviceType::SOLAR, F("SM10"), DeviceFlags::EMS_DEVICE_FLAG_SM10},
{101, DeviceType::SOLAR, F("ISM1"), DeviceFlags::EMS_DEVICE_FLAG_ISM},
@@ -128,11 +132,12 @@
{161, DeviceType::MIXER, F("MM200"), DeviceFlags::EMS_DEVICE_FLAG_MMPLUS},
{204, DeviceType::MIXER, F("MP100"), DeviceFlags::EMS_DEVICE_FLAG_MP}, // pool
// Heat Pumps - 0x38
{200, DeviceType::HEATPUMP, F("HP Module"), DeviceFlags::EMS_DEVICE_FLAG_NONE},
{248, DeviceType::HEATPUMP, F("Hybrid Manager HM200"), DeviceFlags::EMS_DEVICE_FLAG_NONE},
// Heat Pumps - 0x38?
{252, DeviceType::HEATPUMP, F("HP Module"), DeviceFlags::EMS_DEVICE_FLAG_NONE},
// Heat Pumps - 0x53
{248, DeviceType::HEATPUMP, F("Hybrid Manager HM200"), DeviceFlags::EMS_DEVICE_FLAG_NONE},
// Connect devices - 0x02
{171, DeviceType::CONNECT, F("OpenTherm Converter"), DeviceFlags::EMS_DEVICE_FLAG_NONE},
{205, DeviceType::CONNECT, F("Moduline Easy Connect"), DeviceFlags::EMS_DEVICE_FLAG_NONE},
@@ -145,6 +150,9 @@
// Switches - 0x11
{ 71, DeviceType::SWITCH, F("WM10"), DeviceFlags::EMS_DEVICE_FLAG_NONE},
// EM10 error contact and analog flowtemp control- 0x12
{ 74, DeviceType::GATEWAY, F("Error Module EM10"), DeviceFlags::EMS_DEVICE_FLAG_NONE},
// Gateways - 0x48
{189, DeviceType::GATEWAY, F("KM200/MB LAN 2"), DeviceFlags::EMS_DEVICE_FLAG_NONE},

File diff suppressed because it is too large Load Diff

View File

@@ -131,7 +131,7 @@ class Boiler : public EMSdevice {
uint32_t burn2WorkMin_; // burner stage 2 operating time
uint32_t heatWorkMin_; // Total heat operating time
uint32_t UBAuptime_; // Total UBA working hours
char lastCode_[50]; // last error code
char lastCode_[55]; // last error code
char serviceCode_[4]; // 3 character status/service code
uint16_t serviceCodeNumber_; // error/service code
uint8_t emergencyOps_;
@@ -198,6 +198,38 @@ class Boiler : public EMSdevice {
// Pool unit
int8_t poolSetTemp_;
// Alternative Heatsource AM200
int16_t cylTopTemp_; // TB1
int16_t cylCenterTemp_; // TB2
int16_t cylBottomTemp_; // TB3
int16_t aFlowTemp_; // TA1
int16_t aRetTemp_; // TR1
uint8_t aPumpMod_; // PR1 - percent
// uint8_t valveByPass_; // VR2
uint8_t valveBuffer_; // VB1
uint8_t valveReturn_; // VR1
// uint8_t heatSource_; // OEV
// 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)
uint8_t aPumpConfig_; // pos 04: Buffer primary pump->Config pump: No(00),Yes(01)
uint8_t aPumpSignal_; // pos 03: Output for PR1 pump: On/Off(00),PWM(01),PWM invers(02)
uint8_t aPumpMin_; // pos 21: Min output pump PR1 (%)
uint8_t tempRise_; // pos 01: AHS return temp rise: No(00),Yes(01) (mixer VR1)
uint8_t setReturnTemp_; // pos 06: Set temp return (°C) (VR1)
uint16_t mixRuntime_; // pos 10/11?: Mixer run time (s) (VR1)
// uint8_t setFlowTemp_; // pos 07: Set flow temp AHS (°C) (Buffer)
uint8_t bufBypass_; // pos 02: Puffer bypass: No(00), Mischer(01), Ventil(02) (Buffer)
uint16_t bufMixRuntime_; // pos 8/9: Bypass mixer run time: [time] (s) (Buffer)
uint8_t bufConfig_; // pos 20: Konfig WW-Speicher Monovalent(01), Bivalent(02) (buffer)
uint8_t blockMode_; // pos 16: Config htg. blocking mode: No(00),Automatic(01),Always block02) (blocking)
uint8_t blockTerm_; // pos 17: Config of block terminal: NO(00), NC(01)
int8_t blockHyst_; // pos 14?: Hyst. for bolier block (K)
uint8_t releaseWait_; // pos 15: Boiler release wait time (min)
/*
* Hybrid heatpump with telegram 0xBB is readable and writeable in boiler and thermostat
* thermostat always overwrites settings in boiler
@@ -242,10 +274,14 @@ class Boiler : public EMSdevice {
void process_HpOutdoor(std::shared_ptr<const Telegram> telegram);
void process_HpPool(std::shared_ptr<const Telegram> telegram);
void process_HybridHp(std::shared_ptr<const Telegram> telegram);
void process_amTempMessage(std::shared_ptr<const Telegram> telegram);
void process_amStatusMessage(std::shared_ptr<const Telegram> telegram);
void process_amSettingMessage(std::shared_ptr<const Telegram> telegram);
void process_amCommandMessage(std::shared_ptr<const Telegram> telegram);
void process_amExtraMessage(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);
bool set_ww_mode1(const char * value, const int8_t id);
bool set_ww_activated(const char * value, const int8_t id);
bool set_tapwarmwater_activated(const char * value, const int8_t id);
bool set_ww_onetime(const char * value, const int8_t id);
@@ -282,6 +318,24 @@ class Boiler : public EMSdevice {
bool set_pool_temp(const char * value, const int8_t id);
bool set_emergency_temp(const char * value, const int8_t id);
bool set_emergency_ops(const char * value, const int8_t id);
bool set_vr2Config(const char * value, const int8_t id); // pos 12: off(00)/Keelbypass(01)/(hc1pump(02) only standalone)
bool set_ahsActivated(const char * value, const int8_t id); // pos 00: Alternate heat source activation: No(00),Yes(01)
bool set_aPumpConfig(const char * value, const int8_t id); // pos 04: Buffer primary pump->Config pump: No(00),Yes(01)
bool set_aPumpSignal(const char * value, const int8_t id); // pos 03: Output for PR1 pump: On/Off(00),PWM(01),PWM invers(02)
bool set_aPumpMin(const char * value, const int8_t id); // pos 21: Min output pump PR1 (%)
bool set_tempRise(const char * value, const int8_t id); // pos 01: AHS return temp rise: No(00),Yes(01) (mixer VR1)
bool set_setReturnTemp(const char * value, const int8_t id); // pos 06: Set temp return (°C) (VR1)
bool set_mixRuntime(const char * value, const int8_t id); // pos 10/11?: Mixer run time (s) (VR1)
bool set_setFlowTemp(const char * value, const int8_t id); // pos 07: Set flow temp AHS (°C) (Buffer)
bool set_bufBypass(const char * value, const int8_t id); // pos 02: Puffer bypass: No(00), Mischer(01), Ventil(02) (Buffer)
bool set_bufMixRuntime(const char * value, const int8_t id); // pos 8/9: Bypass mixer run time: [time] (s) (Buffer)
bool set_bufConfig(const char * value, const int8_t id); // pos 20: Konfig WW-Speicher Monovalent(01), Bivalent(02) (buffer)
bool set_blockMode(const char * value, const int8_t id); // pos 16: Config htg. blocking mode: No(00),Automatic(01),Always block02) (blocking)
bool set_blockTerm(const char * value, const int8_t id); // pos 17: Config of block terminal: NO(00), NC(01)
bool set_blockHyst(const char * value, const int8_t id); // pos 14?: Hyst. for bolier block (K)
bool set_releaseWait(const char * value, const int8_t id); // pos 15: Boiler release wait time (min)
/*
bool set_hybridStrategy(const char * value, const int8_t id);
bool set_switchOverTemp(const char * value, const int8_t id);

View File

@@ -27,7 +27,7 @@ Controller::Controller(uint8_t device_type, uint8_t device_id, uint8_t product_i
// IVT broadcasts Thermostat time from controller (0x09) if display is off.
if ((flags & 0x0F) == EMS_DEVICE_FLAG_IVT) {
register_telegram_type(0x06, F("RCTime"), false, MAKE_PF_CB(process_dateTime));
register_device_value(DeviceValueTAG::TAG_NONE, &dateTime_, DeviceValueType::STRING, nullptr, FL_(dateTime), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &dateTime_, DeviceValueType::STRING, nullptr, FL_(dateTime), DeviceValueUOM::NONE);
}
}
@@ -37,7 +37,7 @@ void Controller::process_dateTime(std::shared_ptr<const Telegram> telegram) {
return;
}
char newdatetime[sizeof(dateTime_)];
// publish as dd.mm.yyyy hh:mmF
// publish as dd.mm.yyyy hh:mm
snprintf(newdatetime,
sizeof(dateTime_),
"%02d.%02d.%04d %02d:%02d",

View File

@@ -29,7 +29,7 @@ Generic::Generic(uint8_t device_type, uint8_t device_id, uint8_t product_id, con
// RF-Sensor 0x40 sending temperature in telegram 0x435, see https://github.com/emsesp/EMS-ESP32/issues/103
if (device_id == 0x40) {
register_telegram_type(0x435, F("RFSensorMessage"), false, MAKE_PF_CB(process_RFSensorMessage));
register_device_value(DeviceValueTAG::TAG_NONE, &rfTemp_, DeviceValueType::SHORT, FL_(div10), FL_(RFTemp), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &rfTemp_, DeviceValueType::SHORT, FL_(div10), FL_(RFTemp), DeviceValueUOM::DEGREES);
}
}

View File

@@ -25,12 +25,12 @@ REGISTER_FACTORY(Heatpump, EMSdevice::DeviceType::HEATPUMP);
Heatpump::Heatpump(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const std::string & name, uint8_t flags, uint8_t brand)
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
// telegram handlers
register_telegram_type(0x042B, F("HP1"), true, MAKE_PF_CB(process_HPMonitor1));
register_telegram_type(0x047B, F("HP2"), true, MAKE_PF_CB(process_HPMonitor2));
register_telegram_type(0x042B, F("HP1"), false, MAKE_PF_CB(process_HPMonitor1));
register_telegram_type(0x047B, F("HP2"), false, MAKE_PF_CB(process_HPMonitor2));
// device values
register_device_value(DeviceValueTAG::TAG_NONE, &airHumidity_, DeviceValueType::UINT, FL_(div2), FL_(airHumidity), DeviceValueUOM::PERCENT);
register_device_value(DeviceValueTAG::TAG_NONE, &dewTemperature_, DeviceValueType::UINT, nullptr, FL_(dewTemperature), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &airHumidity_, DeviceValueType::UINT, nullptr, FL_(airHumidity), DeviceValueUOM::PERCENT);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &dewTemperature_, DeviceValueType::UINT, nullptr, FL_(dewTemperature), DeviceValueUOM::DEGREES);
}
/*

View File

@@ -30,9 +30,9 @@ Mixer::Mixer(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c
if (flags == EMSdevice::EMS_DEVICE_FLAG_MP) {
register_telegram_type(0x5BA, F("HpPoolStatus"), true, MAKE_PF_CB(process_HpPoolStatus));
type_ = Type::MP;
register_device_value(DeviceValueTAG::TAG_NONE, &poolTemp_, DeviceValueType::SHORT, FL_(div10), FL_(poolTemp), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_NONE, &poolShuntStatus_, DeviceValueType::ENUM, FL_(enum_shunt), FL_(poolShuntStatus), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_NONE, &poolShunt_, DeviceValueType::UINT, nullptr, FL_(poolShunt), DeviceValueUOM::PERCENT);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &poolTemp_, DeviceValueType::SHORT, FL_(div10), FL_(poolTemp), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &poolShuntStatus_, DeviceValueType::ENUM, FL_(enum_shunt), FL_(poolShuntStatus), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &poolShunt_, DeviceValueType::UINT, nullptr, FL_(poolShunt), DeviceValueUOM::PERCENT);
}
// EMS+

View File

@@ -134,37 +134,43 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c
}
// common solar values for all modules (except dhw)
register_device_value(DeviceValueTAG::TAG_NONE, &collectorTemp_, DeviceValueType::SHORT, FL_(div10), FL_(collectorTemp), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_NONE, &cylBottomTemp_, DeviceValueType::SHORT, FL_(div10), FL_(cylBottomTemp), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_NONE, &solarPump_, DeviceValueType::BOOL, nullptr, FL_(solarPump), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_NONE, &pumpWorkTime_, DeviceValueType::TIME, nullptr, FL_(pumpWorkTime), DeviceValueUOM::MINUTES);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &collectorTemp_, DeviceValueType::SHORT, FL_(div10), FL_(collectorTemp), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &cylBottomTemp_, DeviceValueType::SHORT, FL_(div10), FL_(cylBottomTemp), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &solarPump_, DeviceValueType::BOOL, nullptr, FL_(solarPump), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &pumpWorkTime_, DeviceValueType::TIME, nullptr, FL_(pumpWorkTime), DeviceValueUOM::MINUTES);
register_device_value(
DeviceValueTAG::TAG_NONE, &cylMaxTemp_, DeviceValueType::UINT, nullptr, FL_(cylMaxTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_cylMaxTemp));
register_device_value(DeviceValueTAG::TAG_NONE, &collectorShutdown_, DeviceValueType::BOOL, nullptr, FL_(collectorShutdown), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_NONE, &cylHeated_, DeviceValueType::BOOL, nullptr, FL_(cylHeated), DeviceValueUOM::NONE);
DeviceValueTAG::TAG_DEVICE_DATA, &cylMaxTemp_, DeviceValueType::UINT, nullptr, FL_(cylMaxTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_cylMaxTemp));
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &collectorShutdown_, DeviceValueType::BOOL, nullptr, FL_(collectorShutdown), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &cylHeated_, DeviceValueType::BOOL, nullptr, FL_(cylHeated), DeviceValueUOM::NONE);
// values per device flag
if (flags == EMSdevice::EMS_DEVICE_FLAG_SM10) {
register_device_value(DeviceValueTAG::TAG_NONE, &solarPumpMod_, DeviceValueType::UINT, nullptr, FL_(solarPumpMod), DeviceValueUOM::PERCENT);
register_device_value(
DeviceValueTAG::TAG_NONE, &solarPumpMinMod_, DeviceValueType::UINT, nullptr, FL_(pumpMinMod), DeviceValueUOM::PERCENT, MAKE_CF_CB(set_PumpMinMod));
register_device_value(DeviceValueTAG::TAG_NONE,
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &solarPumpMod_, DeviceValueType::UINT, nullptr, FL_(solarPumpMod), DeviceValueUOM::PERCENT);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&solarPumpMinMod_,
DeviceValueType::UINT,
nullptr,
FL_(pumpMinMod),
DeviceValueUOM::PERCENT,
MAKE_CF_CB(set_PumpMinMod));
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&solarPumpTurnonDiff_,
DeviceValueType::UINT,
nullptr,
FL_(solarPumpTurnonDiff),
DeviceValueUOM::DEGREES_R,
MAKE_CF_CB(set_TurnonDiff));
register_device_value(DeviceValueTAG::TAG_NONE,
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&solarPumpTurnoffDiff_,
DeviceValueType::UINT,
nullptr,
FL_(solarPumpTurnoffDiff),
DeviceValueUOM::DEGREES_R,
MAKE_CF_CB(set_TurnoffDiff));
register_device_value(DeviceValueTAG::TAG_NONE, &solarPower_, DeviceValueType::SHORT, nullptr, FL_(solarPower), DeviceValueUOM::W);
register_device_value(DeviceValueTAG::TAG_NONE, &energyLastHour_, DeviceValueType::ULONG, FL_(div10), FL_(energyLastHour), DeviceValueUOM::WH);
register_device_value(DeviceValueTAG::TAG_NONE, &maxFlow_, DeviceValueType::UINT, FL_(div10), FL_(maxFlow), DeviceValueUOM::LMIN, MAKE_CF_CB(set_SM10MaxFlow));
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &solarPower_, DeviceValueType::SHORT, nullptr, FL_(solarPower), DeviceValueUOM::W);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &energyLastHour_, DeviceValueType::ULONG, FL_(div10), FL_(energyLastHour), DeviceValueUOM::WH);
register_device_value(
DeviceValueTAG::TAG_DEVICE_DATA, &maxFlow_, DeviceValueType::UINT, FL_(div10), FL_(maxFlow), DeviceValueUOM::LMIN, MAKE_CF_CB(set_SM10MaxFlow));
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW,
&wwMinTemp_,
DeviceValueType::UINT,
@@ -172,7 +178,7 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c
FL_(wwMinTemp),
DeviceValueUOM::DEGREES,
MAKE_CF_CB(set_wwMinTemp));
register_device_value(DeviceValueTAG::TAG_NONE,
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&solarIsEnabled_,
DeviceValueType::BOOL,
nullptr,
@@ -182,102 +188,122 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c
/* unknown values for testing and logging. Used by MichaelDvP
register_device_value(
DeviceValueTAG::TAG_NONE, &setting3_, DeviceValueType::UINT, nullptr, FL_(setting3), DeviceValueUOM::NONE, MAKE_CF_CB(set_CollectorMaxTemp));
DeviceValueTAG::TAG_DEVICE_DATA, &setting3_, DeviceValueType::UINT, nullptr, FL_(setting3), DeviceValueUOM::NONE, MAKE_CF_CB(set_CollectorMaxTemp));
register_device_value(
DeviceValueTAG::TAG_NONE, &setting4_, DeviceValueType::UINT, nullptr, FL_(setting4), DeviceValueUOM::NONE, MAKE_CF_CB(set_CollectorMinTemp));
register_device_value(DeviceValueTAG::TAG_NONE, &data11_, DeviceValueType::UINT, nullptr, FL_(data11), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_NONE, &data12_, DeviceValueType::UINT, nullptr, FL_(data12), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_NONE, &data1_, DeviceValueType::UINT, nullptr, FL_(data1), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_NONE, &data0_, DeviceValueType::UINT, nullptr, FL_(data0), DeviceValueUOM::NONE);
DeviceValueTAG::TAG_DEVICE_DATA, &setting4_, DeviceValueType::UINT, nullptr, FL_(setting4), DeviceValueUOM::NONE, MAKE_CF_CB(set_CollectorMinTemp));
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &data11_, DeviceValueType::UINT, nullptr, FL_(data11), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &data12_, DeviceValueType::UINT, nullptr, FL_(data12), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &data1_, DeviceValueType::UINT, nullptr, FL_(data1), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &data0_, DeviceValueType::UINT, nullptr, FL_(data0), DeviceValueUOM::NONE);
*/
}
if (flags == EMSdevice::EMS_DEVICE_FLAG_ISM) {
register_device_value(DeviceValueTAG::TAG_NONE, &cylMiddleTemp_, DeviceValueType::SHORT, FL_(div10), FL_(cylMiddleTemp), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_NONE, &retHeatAssist_, DeviceValueType::SHORT, FL_(div10), FL_(retHeatAssist), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_NONE, &m1Valve_, DeviceValueType::BOOL, nullptr, FL_(m1Valve), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_NONE, &energyLastHour_, DeviceValueType::ULONG, FL_(div10), FL_(energyLastHour), DeviceValueUOM::WH);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &cylMiddleTemp_, DeviceValueType::SHORT, FL_(div10), FL_(cylMiddleTemp), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &retHeatAssist_, DeviceValueType::SHORT, FL_(div10), FL_(retHeatAssist), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &m1Valve_, DeviceValueType::BOOL, nullptr, FL_(m1Valve), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &energyLastHour_, DeviceValueType::ULONG, FL_(div10), FL_(energyLastHour), DeviceValueUOM::WH);
}
if (flags == EMSdevice::EMS_DEVICE_FLAG_SM100) {
register_device_value(DeviceValueTAG::TAG_NONE, &solarPumpMod_, DeviceValueType::UINT, nullptr, FL_(solarPumpMod), DeviceValueUOM::PERCENT);
register_device_value(DeviceValueTAG::TAG_NONE,
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &solarPumpMod_, DeviceValueType::UINT, nullptr, FL_(solarPumpMod), DeviceValueUOM::PERCENT);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&solarPumpMinMod_,
DeviceValueType::UINT,
FL_(mul5),
FL_(pumpMinMod),
DeviceValueUOM::PERCENT,
MAKE_CF_CB(set_PumpMinMod));
register_device_value(DeviceValueTAG::TAG_NONE,
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&solarPumpTurnonDiff_,
DeviceValueType::UINT,
FL_(div10),
FL_(solarPumpTurnonDiff),
DeviceValueUOM::DEGREES,
MAKE_CF_CB(set_TurnonDiff));
register_device_value(DeviceValueTAG::TAG_NONE,
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&solarPumpTurnoffDiff_,
DeviceValueType::UINT,
FL_(div10),
FL_(solarPumpTurnoffDiff),
DeviceValueUOM::DEGREES,
MAKE_CF_CB(set_TurnoffDiff));
register_device_value(DeviceValueTAG::TAG_NONE, &collector2Temp_, DeviceValueType::SHORT, FL_(div10), FL_(collector2Temp), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_NONE, &cylMiddleTemp_, DeviceValueType::SHORT, FL_(div10), FL_(cylMiddleTemp), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_NONE, &retHeatAssist_, DeviceValueType::SHORT, FL_(div10), FL_(retHeatAssist), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_NONE, &m1Valve_, DeviceValueType::BOOL, nullptr, FL_(m1Valve), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_NONE, &m1Power_, DeviceValueType::UINT, nullptr, FL_(m1Power), DeviceValueUOM::PERCENT);
register_device_value(DeviceValueTAG::TAG_NONE, &solarPump2_, DeviceValueType::BOOL, nullptr, FL_(solarPump2), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_NONE, &solarPump2Mod_, DeviceValueType::UINT, nullptr, FL_(solarPump2Mod), DeviceValueUOM::PERCENT);
register_device_value(DeviceValueTAG::TAG_NONE, &cylBottomTemp2_, DeviceValueType::SHORT, FL_(div10), FL_(cyl2BottomTemp), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_NONE, &heatExchangerTemp_, DeviceValueType::SHORT, FL_(div10), FL_(heatExchangerTemp), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_NONE, &cylPumpMod_, DeviceValueType::UINT, nullptr, FL_(cylPumpMod), DeviceValueUOM::PERCENT);
register_device_value(DeviceValueTAG::TAG_NONE, &valveStatus_, DeviceValueType::BOOL, nullptr, FL_(valveStatus), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_NONE, &cylHeated_, DeviceValueType::BOOL, nullptr, FL_(cylHeated), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_NONE, &collectorShutdown_, DeviceValueType::BOOL, nullptr, FL_(collectorShutdown), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_NONE,
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &collector2Temp_, DeviceValueType::SHORT, FL_(div10), FL_(collector2Temp), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &cylMiddleTemp_, DeviceValueType::SHORT, FL_(div10), FL_(cylMiddleTemp), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &retHeatAssist_, DeviceValueType::SHORT, FL_(div10), FL_(retHeatAssist), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &m1Valve_, DeviceValueType::BOOL, nullptr, FL_(m1Valve), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &m1Power_, DeviceValueType::UINT, nullptr, FL_(m1Power), DeviceValueUOM::PERCENT);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &solarPump2_, DeviceValueType::BOOL, nullptr, FL_(solarPump2), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &solarPump2Mod_, DeviceValueType::UINT, nullptr, FL_(solarPump2Mod), DeviceValueUOM::PERCENT);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &cylBottomTemp2_, DeviceValueType::SHORT, FL_(div10), FL_(cyl2BottomTemp), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&heatExchangerTemp_,
DeviceValueType::SHORT,
FL_(div10),
FL_(heatExchangerTemp),
DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &cylPumpMod_, DeviceValueType::UINT, nullptr, FL_(cylPumpMod), DeviceValueUOM::PERCENT);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &valveStatus_, DeviceValueType::BOOL, nullptr, FL_(valveStatus), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &cylHeated_, DeviceValueType::BOOL, nullptr, FL_(cylHeated), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &collectorShutdown_, DeviceValueType::BOOL, nullptr, FL_(collectorShutdown), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&collectorMaxTemp_,
DeviceValueType::UINT,
nullptr,
FL_(collectorMaxTemp),
DeviceValueUOM::DEGREES,
MAKE_CF_CB(set_CollectorMaxTemp));
register_device_value(DeviceValueTAG::TAG_NONE,
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&collectorMinTemp_,
DeviceValueType::UINT,
nullptr,
FL_(collectorMinTemp),
DeviceValueUOM::DEGREES,
MAKE_CF_CB(set_CollectorMinTemp));
register_device_value(DeviceValueTAG::TAG_NONE, &energyLastHour_, DeviceValueType::ULONG, FL_(div10), FL_(energyLastHour), DeviceValueUOM::WH);
register_device_value(DeviceValueTAG::TAG_NONE, &energyToday_, DeviceValueType::ULONG, nullptr, FL_(energyToday), DeviceValueUOM::WH);
register_device_value(DeviceValueTAG::TAG_NONE, &energyTotal_, DeviceValueType::ULONG, FL_(div10), FL_(energyTotal), DeviceValueUOM::KWH);
register_device_value(DeviceValueTAG::TAG_NONE, &pump2WorkTime_, DeviceValueType::TIME, nullptr, FL_(pump2WorkTime), DeviceValueUOM::MINUTES);
register_device_value(DeviceValueTAG::TAG_NONE, &m1WorkTime_, DeviceValueType::TIME, nullptr, FL_(m1WorkTime), DeviceValueUOM::MINUTES);
// register_device_value(DeviceValueTAG::TAG_NONE, &cyl2MaxTemp_, DeviceValueType::UINT, nullptr, FL_(cyl2MaxTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_cyl2MaxTemp));
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &energyLastHour_, DeviceValueType::ULONG, FL_(div10), FL_(energyLastHour), DeviceValueUOM::WH);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &energyToday_, DeviceValueType::ULONG, nullptr, FL_(energyToday), DeviceValueUOM::WH);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &energyTotal_, DeviceValueType::ULONG, FL_(div10), FL_(energyTotal), DeviceValueUOM::KWH);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &pump2WorkTime_, DeviceValueType::TIME, nullptr, FL_(pump2WorkTime), DeviceValueUOM::MINUTES);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &m1WorkTime_, DeviceValueType::TIME, nullptr, FL_(m1WorkTime), DeviceValueUOM::MINUTES);
// register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &cyl2MaxTemp_, DeviceValueType::UINT, nullptr, FL_(cyl2MaxTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_cyl2MaxTemp));
register_device_value(DeviceValueTAG::TAG_NONE,
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&heatTransferSystem_,
DeviceValueType::BOOL,
nullptr,
FL_(heatTransferSystem),
DeviceValueUOM::NONE,
MAKE_CF_CB(set_heatTransferSystem));
register_device_value(
DeviceValueTAG::TAG_NONE, &externalCyl_, DeviceValueType::BOOL, nullptr, FL_(externalCyl), DeviceValueUOM::NONE, MAKE_CF_CB(set_externalCyl));
register_device_value(DeviceValueTAG::TAG_NONE,
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&externalCyl_,
DeviceValueType::BOOL,
nullptr,
FL_(externalCyl),
DeviceValueUOM::NONE,
MAKE_CF_CB(set_externalCyl));
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&thermalDisinfect_,
DeviceValueType::BOOL,
nullptr,
FL_(thermalDisinfect),
DeviceValueUOM::NONE,
MAKE_CF_CB(set_thermalDisinfect));
register_device_value(
DeviceValueTAG::TAG_NONE, &heatMetering_, DeviceValueType::BOOL, nullptr, FL_(heatMetering), DeviceValueUOM::NONE, MAKE_CF_CB(set_heatMetering));
register_device_value(
DeviceValueTAG::TAG_NONE, &solarIsEnabled_, DeviceValueType::BOOL, nullptr, FL_(activated), DeviceValueUOM::NONE, MAKE_CF_CB(set_solarEnabled));
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&heatMetering_,
DeviceValueType::BOOL,
nullptr,
FL_(heatMetering),
DeviceValueUOM::NONE,
MAKE_CF_CB(set_heatMetering));
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&solarIsEnabled_,
DeviceValueType::BOOL,
nullptr,
FL_(activated),
DeviceValueUOM::NONE,
MAKE_CF_CB(set_solarEnabled));
// telegram 0x035A
register_device_value(DeviceValueTAG::TAG_NONE,
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&solarPumpMode_,
DeviceValueType::ENUM,
FL_(enum_solarmode),
@@ -285,7 +311,7 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c
DeviceValueUOM::NONE,
MAKE_CF_CB(set_solarMode));
register_device_value( // pump kick for vacuum collector, 00=off
DeviceValueTAG::TAG_NONE,
DeviceValueTAG::TAG_DEVICE_DATA,
&solarPumpKick_,
DeviceValueType::BOOL,
nullptr,
@@ -293,7 +319,7 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c
DeviceValueUOM::NONE,
MAKE_CF_CB(set_solarPumpKick));
register_device_value( // system does not use antifreeze, 00=off
DeviceValueTAG::TAG_NONE,
DeviceValueTAG::TAG_DEVICE_DATA,
&plainWaterMode_,
DeviceValueType::BOOL,
nullptr,
@@ -301,7 +327,7 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c
DeviceValueUOM::NONE,
MAKE_CF_CB(set_plainWaterMode));
register_device_value( // double Match Flow, 00=off
DeviceValueTAG::TAG_NONE,
DeviceValueTAG::TAG_DEVICE_DATA,
&doubleMatchFlow_,
DeviceValueType::BOOL,
nullptr,
@@ -309,21 +335,21 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c
DeviceValueUOM::NONE,
MAKE_CF_CB(set_doubleMatchFlow));
register_device_value(DeviceValueTAG::TAG_NONE,
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&solarPump2MinMod_,
DeviceValueType::UINT,
nullptr,
FL_(pump2MinMod),
DeviceValueUOM::PERCENT,
MAKE_CF_CB(set_Pump2MinMod));
register_device_value(DeviceValueTAG::TAG_NONE,
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&solarPump2TurnonDiff_,
DeviceValueType::UINT,
FL_(div10),
FL_(solarPump2TurnonDiff),
DeviceValueUOM::DEGREES,
MAKE_CF_CB(set_TurnonDiff2));
register_device_value(DeviceValueTAG::TAG_NONE,
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&solarPump2TurnoffDiff_,
DeviceValueType::UINT,
FL_(div10),
@@ -331,7 +357,7 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c
DeviceValueUOM::DEGREES,
MAKE_CF_CB(set_TurnoffDiff2));
register_device_value( // pump kick for vacuum collector, 00=off
DeviceValueTAG::TAG_NONE,
DeviceValueTAG::TAG_DEVICE_DATA,
&solarPump2Kick_,
DeviceValueType::BOOL,
nullptr,
@@ -340,53 +366,53 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c
MAKE_CF_CB(set_solarPump2Kick));
// telegram 0x380
register_device_value(DeviceValueTAG::TAG_NONE,
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&climateZone_,
DeviceValueType::UINT,
nullptr,
FL_(climateZone),
DeviceValueUOM::NONE,
MAKE_CF_CB(set_climateZone)); // climate zone identifier
register_device_value(DeviceValueTAG::TAG_NONE,
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&collector1Area_,
DeviceValueType::USHORT,
FL_(div10),
FL_(collector1Area),
DeviceValueUOM::SQM,
MAKE_CF_CB(set_collector1Area)); // Area of collector field 1
register_device_value(DeviceValueTAG::TAG_NONE,
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&collector1Type_,
DeviceValueType::ENUM,
FL_(enum_collectortype),
FL_(collector1Type),
DeviceValueUOM::NONE,
MAKE_CF_CB(set_collector1Type)); // Type of collector field 1, 01=flat, 02=vacuum
register_device_value(DeviceValueTAG::TAG_NONE,
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&collector2Area_,
DeviceValueType::USHORT,
FL_(div10),
FL_(collector2Area),
DeviceValueUOM::SQM,
MAKE_CF_CB(set_collector2Area)); // Area of collector field 2
register_device_value(DeviceValueTAG::TAG_NONE,
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&collector2Type_,
DeviceValueType::ENUM,
FL_(enum_collectortype),
FL_(collector2Type),
DeviceValueUOM::NONE,
MAKE_CF_CB(set_collector2Type)); // Type of collector field 2, 01=flat, 02=vacuum
register_device_value(DeviceValueTAG::TAG_NONE,
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&cylPriority_,
DeviceValueType::ENUM,
FL_(enum_cylprio),
FL_(cylPriority),
DeviceValueUOM::NONE,
MAKE_CF_CB(set_cylPriority));
register_device_value(DeviceValueTAG::TAG_NONE, &heatCntFlowTemp_, DeviceValueType::USHORT, FL_(div10), FL_(heatCntFlowTemp), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_NONE, &heatCntRetTemp_, DeviceValueType::USHORT, FL_(div10), FL_(heatCntRetTemp), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_NONE, &heatCnt_, DeviceValueType::UINT, nullptr, FL_(heatCnt), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_NONE, &swapFlowTemp_, DeviceValueType::USHORT, FL_(div10), FL_(swapFlowTemp), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_NONE, &swapRetTemp_, DeviceValueType::USHORT, FL_(div10), FL_(swapRetTemp), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &heatCntFlowTemp_, DeviceValueType::USHORT, FL_(div10), FL_(heatCntFlowTemp), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &heatCntRetTemp_, DeviceValueType::USHORT, FL_(div10), FL_(heatCntRetTemp), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &heatCnt_, DeviceValueType::UINT, nullptr, FL_(heatCnt), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &swapFlowTemp_, DeviceValueType::USHORT, FL_(div10), FL_(swapFlowTemp), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &swapRetTemp_, DeviceValueType::USHORT, FL_(div10), FL_(swapRetTemp), DeviceValueUOM::DEGREES);
}
}

View File

@@ -24,13 +24,14 @@ REGISTER_FACTORY(Switch, EMSdevice::DeviceType::SWITCH);
Switch::Switch(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const std::string & name, uint8_t flags, uint8_t brand)
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
// WM10 module, device_id 0x11
register_telegram_type(0x9C, F("WM10MonitorMessage"), false, MAKE_PF_CB(process_WM10MonitorMessage));
register_telegram_type(0x9D, F("WM10SetMessage"), false, MAKE_PF_CB(process_WM10SetMessage));
register_telegram_type(0x1E, F("WM10TempMessage"), false, MAKE_PF_CB(process_WM10TempMessage));
register_device_value(DeviceValueTAG::TAG_NONE, &activated_, DeviceValueType::BOOL, nullptr, FL_(activated), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_NONE, &flowTempHc_, DeviceValueType::USHORT, FL_(div10), FL_(flowTempHc), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_NONE, &status_, DeviceValueType::INT, nullptr, FL_(status), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &activated_, DeviceValueType::BOOL, nullptr, FL_(activated), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &flowTempHc_, DeviceValueType::USHORT, FL_(div10), FL_(flowTempHc), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &status_, DeviceValueType::INT, nullptr, FL_(status), DeviceValueUOM::NONE);
}
// message 0x9D switch on/off

File diff suppressed because it is too large Load Diff

View File

@@ -38,6 +38,7 @@ class Thermostat : public EMSdevice {
int16_t roomTemp;
int16_t remotetemp; // for readback
uint8_t tempautotemp;
int8_t remoteseltemp;
uint8_t mode;
uint8_t modetype;
uint8_t summermode;
@@ -56,6 +57,7 @@ class Thermostat : public EMSdevice {
uint8_t manualtemp;
uint8_t summersetmode;
uint8_t hpoperatingmode;
uint8_t hpoperatingstate;
uint8_t roominfluence;
uint8_t roominfl_factor;
int16_t curroominfl;
@@ -80,6 +82,8 @@ class Thermostat : public EMSdevice {
char switchtime1[16];
char switchtime2[16];
uint8_t climate;
uint8_t switchonoptimization;
uint8_t statusbyte; // from RC300monitor
// RC 10
uint8_t reducehours; // night reduce duration
@@ -130,6 +134,7 @@ class Thermostat : public EMSdevice {
ON,
DAYLOW,
DAYMID,
REMOTESELTEMP,
UNKNOWN
};
@@ -160,6 +165,7 @@ class Thermostat : public EMSdevice {
// each thermostat has a list of heating controller type IDs for reading and writing
std::vector<uint16_t> monitor_typeids;
std::vector<uint16_t> set_typeids;
std::vector<uint16_t> set2_typeids;
std::vector<uint16_t> timer_typeids;
std::vector<uint16_t> timer2_typeids;
std::vector<uint16_t> summer_typeids;
@@ -189,12 +195,14 @@ class Thermostat : public EMSdevice {
uint8_t offtemp_; // Set Temperature when mode is Off / 10 (e.g.: 0x0F = 7.5 degrees Celsius)
uint8_t mixingvalves_; // Number of Mixing Valves: (0x00=0, 0x01=1, 0x02=2)
int8_t dampedoutdoortemp_;
uint16_t tempsensor1_;
uint16_t tempsensor2_;
int16_t dampedoutdoortemp2_;
uint8_t floordrystatus_;
uint8_t floordrytemp_;
int8_t dampedoutdoortemp_;
int16_t tempsensor1_;
int16_t tempsensor2_;
int16_t dampedoutdoortemp2_;
uint8_t floordrystatus_;
uint8_t floordrytemp_;
uint8_t dewtemperature_;
uint8_t humidity_;
uint8_t wwExtra1_; // wwExtra active for wwSystem 1
uint8_t wwExtra2_;
@@ -217,6 +225,8 @@ class Thermostat : public EMSdevice {
uint8_t wwDailyHeating_;
uint8_t wwDailyHeatTime_;
uint8_t wwWhenModeOff_;
char wwHoliday_[26];
char wwVacation_[26];
// HybridHP
uint8_t hybridStrategy_; // co2 = 1, cost = 2, temperature = 3, mix = 4
@@ -357,6 +367,7 @@ class Thermostat : public EMSdevice {
void process_CRFMonitor(std::shared_ptr<const Telegram> telegram);
void process_RC300Monitor(std::shared_ptr<const Telegram> telegram);
void process_RC300Set(std::shared_ptr<const Telegram> telegram);
void process_RC300Set2(std::shared_ptr<const Telegram> telegram);
void process_RC300Summer(std::shared_ptr<const Telegram> telegram);
void process_RC300Summer2(std::shared_ptr<const Telegram> telegram);
void process_RC300WWmode(std::shared_ptr<const Telegram> telegram);
@@ -373,6 +384,9 @@ class Thermostat : public EMSdevice {
void process_JunkersRemoteMonitor(std::shared_ptr<const Telegram> telegram);
void process_JunkersHybridSettings(std::shared_ptr<const Telegram> telegram);
void process_JunkersSetMixer(std::shared_ptr<const Telegram> telegram);
void process_RemoteTemp(std::shared_ptr<const Telegram> telegram);
void process_RemoteHumidity(std::shared_ptr<const Telegram> telegram);
void process_RemoteCorrection(std::shared_ptr<const Telegram> telegram);
// internal helper functions
bool set_mode_n(const uint8_t mode, const uint8_t hc_num);
@@ -412,7 +426,6 @@ class Thermostat : public EMSdevice {
bool set_vacreducetemp(const char * value, const int8_t id);
bool set_vacreducemode(const char * value, const int8_t id);
bool set_nofrostmode(const char * value, const int8_t id);
bool set_remotetemp(const char * value, const int8_t id);
bool set_roominfluence(const char * value, const int8_t id);
bool set_roominfl_factor(const char * value, const int8_t id);
@@ -426,6 +439,8 @@ class Thermostat : public EMSdevice {
bool set_controlmode(const char * value, const int8_t id);
bool set_wwprio(const char * value, const int8_t id);
bool set_fastheatup(const char * value, const int8_t id);
bool set_switchonoptimization(const char * value, const int8_t id);
bool set_remoteseltemp(const char * value, const int8_t id);
// set functions - these don't use the id/hc, the parameters are ignored
bool set_wwmode(const char * value, const int8_t id);
@@ -446,6 +461,12 @@ class Thermostat : public EMSdevice {
bool set_wwDailyHeating(const char * value, const int8_t id);
bool set_wwDailyHeatTime(const char * value, const int8_t id);
bool set_wwwhenmodeoff(const char * value, const int8_t id);
bool set_wwVacation(const char * value, const int8_t id) {
return set_holiday(value, DeviceValueTAG::TAG_WWC1, true);
}
bool set_wwHoliday(const char * value, const int8_t id) {
return set_holiday(value, DeviceValueTAG::TAG_WWC1);
}
bool set_datetime(const char * value, const int8_t id);
bool set_minexttemp(const char * value, const int8_t id);

View File

@@ -114,7 +114,7 @@ std::string EMSdevice::device_type_2_device_name(const uint8_t device_type) {
// returns device_type from a string
uint8_t EMSdevice::device_name_2_device_type(const char * topic) {
if (!topic) {
return DeviceType::UNKNOWN; // nullptr
return DeviceType::UNKNOWN;
}
// convert topic to lowercase and compare
@@ -244,6 +244,16 @@ bool EMSdevice::is_fetch(uint16_t telegram_id) const {
return false;
}
// check for a tag to create a nest
bool EMSdevice::has_tag(const uint8_t tag) const {
for (const auto & dv : devicevalues_) {
if (dv.tag == tag && tag >= DeviceValueTAG::TAG_HC1) {
return true;
}
}
return false;
}
// list of registered device entries
// called from the command 'entities'
void EMSdevice::list_device_entries(JsonObject & output) const {
@@ -469,7 +479,7 @@ void EMSdevice::register_device_value(uint8_t tag,
flags |= CommandFlag::MQTT_SUB_FLAG_HC;
} else if (tag >= DeviceValueTAG::TAG_WWC1 && tag <= DeviceValueTAG::TAG_WWC10) {
flags |= CommandFlag::MQTT_SUB_FLAG_WWC;
} else if (tag == DeviceValueTAG::TAG_DEVICE_DATA_WW) {
} else if (tag == DeviceValueTAG::TAG_DEVICE_DATA_WW || tag == DeviceValueTAG::TAG_BOILER_DATA_WW) {
flags |= CommandFlag::MQTT_SUB_FLAG_WW;
}
@@ -541,7 +551,7 @@ void EMSdevice::publish_value(void * value_p) const {
if (dv.value_p == value_p && !dv.has_state(DeviceValueState::DV_API_MQTT_EXCLUDE)) {
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
if (Mqtt::publish_single2cmd()) {
if (dv.tag >= DeviceValueTAG::TAG_HC1 && dv.tag <= DeviceValueTAG::TAG_WWC10) {
if (dv.tag >= DeviceValueTAG::TAG_HC1) {
snprintf(topic,
sizeof(topic),
"%s/%s/%s",
@@ -563,7 +573,7 @@ void EMSdevice::publish_value(void * value_p) const {
}
int8_t divider = (dv.options_size == 1) ? Helpers::atoint(read_flash_string(dv.options[0]).c_str()) : 0;
char payload[50] = {'\0'};
char payload[55] = {'\0'};
uint8_t fahrenheit = !EMSESP::system_.fahrenheit() ? 0 : (dv.uom == DeviceValueUOM::DEGREES) ? 2 : (dv.uom == DeviceValueUOM::DEGREES_R) ? 1 : 0;
switch (dv.type) {
@@ -900,11 +910,9 @@ bool EMSdevice::get_value_info(JsonObject & output, const char * cmd, const int8
JsonObject json = output;
int8_t tag = id;
// check if we have hc or wwc
if (id >= 1 && id <= 8) {
// check if we have hc or wwc or hs
if (id >= 1 && id <= (1 + DeviceValueTAG::TAG_HS16 - DeviceValueTAG::TAG_HC1)) {
tag = DeviceValueTAG::TAG_HC1 + id - 1;
} else if (id >= 9 && id <= 19) {
tag = DeviceValueTAG::TAG_WWC1 + id - 9;
}
// make a copy of the string command for parsing

View File

@@ -52,6 +52,8 @@ class EMSdevice {
static std::string tag_to_string(uint8_t tag);
static std::string tag_to_mqtt(uint8_t tag);
bool has_tag(const uint8_t tag) const;
inline uint8_t device_id() const {
return device_id_;
}
@@ -307,6 +309,7 @@ class EMSdevice {
static constexpr uint8_t EMS_DEVICE_ID_BOILER = 0x08; // fixed device_id for Master Boiler/UBA
static constexpr uint8_t EMS_DEVICE_ID_BOILER_1 = 0x70; // fixed device_id for 1st. Cascade Boiler/UBA
static constexpr uint8_t EMS_DEVICE_ID_BOILER_F = 0x7F; // fixed device_id for last Cascade Boiler/UBA
static constexpr uint8_t EMS_DEVICE_ID_AM200 = 0x60; // fixed device_id for alternative Heating AM200
// generic type IDs
static constexpr uint16_t EMS_TYPE_VERSION = 0x02; // type ID for Version information. Generic across all EMS devices.
@@ -324,6 +327,7 @@ class EMSdevice {
static constexpr uint8_t EMS_DEVICE_FLAG_HT3 = 3;
static constexpr uint8_t EMS_DEVICE_FLAG_HEATPUMP = 4;
static constexpr uint8_t EMS_DEVICE_FLAG_HYBRID = 5;
static constexpr uint8_t EMS_DEVICE_FLAG_AM200 = 6;
// Solar Module
static constexpr uint8_t EMS_DEVICE_FLAG_SM10 = 1;
@@ -351,6 +355,7 @@ class EMSdevice {
static constexpr uint8_t EMS_DEVICE_FLAG_RC100 = 10;
static constexpr uint8_t EMS_DEVICE_FLAG_JUNKERS = 11;
static constexpr uint8_t EMS_DEVICE_FLAG_CRF = 12; // CRF200 only monitor
static constexpr uint8_t EMS_DEVICE_FLAG_RC100H = 13; // with humidity
uint8_t count_entities();
bool has_entities() const;

View File

@@ -53,45 +53,46 @@ const __FlashStringHelper * DeviceValue::DeviceValueUOM_s[] __attribute__((__ali
// must be an int of 4 bytes, 32bit aligned
const __FlashStringHelper * const DeviceValue::DeviceValueTAG_s[] PROGMEM = {
F_(tag_none), // ""
F_(tag_heartbeat), // ""
F_(tag_boiler_data), // ""
F_(tag_device_data_ww), // "ww"
F_(tag_thermostat_data), // ""
F_(tag_hc1), // "hc1"
F_(tag_hc2), // "hc2"
F_(tag_hc3), // "hc3"
F_(tag_hc4), // "hc4"
F_(tag_hc5), // "hc5"
F_(tag_hc6), // "hc6"
F_(tag_hc7), // "hc7"
F_(tag_hc8), // "hc8"
F_(tag_wwc1), // "wwc1"
F_(tag_wwc2), // "Wwc2"
F_(tag_wwc3), // "wwc3"
F_(tag_wwc4), // "wwc4"
F_(tag_wwc5), // "wwc5"
F_(tag_wwc6), // "wwc6"
F_(tag_wwc7), // "wwc7"
F_(tag_wwc8), // "wwc8"
F_(tag_wwc9), // "wwc9"
F_(tag_wwc10), // "wwc10"
F_(tag_hs1), // "hs1"
F_(tag_hs2), // "hs2"
F_(tag_hs3), // "hs3"
F_(tag_hs4), // "hs4"
F_(tag_hs5), // "hs5"
F_(tag_hs6), // "hs6"
F_(tag_hs7), // "hs7"
F_(tag_hs8), // "hs8"
F_(tag_hs9), // "hs9"
F_(tag_hs10), // "hs10"
F_(tag_hs11), // "hs11"
F_(tag_hs12), // "hs12"
F_(tag_hs13), // "hs13"
F_(tag_hs14), // "hs14"
F_(tag_hs15), // "hs15"
F_(tag_hs16) // "hs16"
F_(tag_none), // ""
F_(tag_heartbeat), // ""
F_(tag_boiler_data_ww), // "dhw"
F_(tag_device_data), // ""
F_(tag_device_data_ww), // "dhw"
F_(tag_hc1), // "hc1"
F_(tag_hc2), // "hc2"
F_(tag_hc3), // "hc3"
F_(tag_hc4), // "hc4"
F_(tag_hc5), // "hc5"
F_(tag_hc6), // "hc6"
F_(tag_hc7), // "hc7"
F_(tag_hc8), // "hc8"
F_(tag_wwc1), // "wwc1"
F_(tag_wwc2), // "Wwc2"
F_(tag_wwc3), // "wwc3"
F_(tag_wwc4), // "wwc4"
F_(tag_wwc5), // "wwc5"
F_(tag_wwc6), // "wwc6"
F_(tag_wwc7), // "wwc7"
F_(tag_wwc8), // "wwc8"
F_(tag_wwc9), // "wwc9"
F_(tag_wwc10), // "wwc10"
F_(tag_ahs), // "ahs"
F_(tag_hs1), // "hs1"
F_(tag_hs2), // "hs2"
F_(tag_hs3), // "hs3"
F_(tag_hs4), // "hs4"
F_(tag_hs5), // "hs5"
F_(tag_hs6), // "hs6"
F_(tag_hs7), // "hs7"
F_(tag_hs8), // "hs8"
F_(tag_hs9), // "hs9"
F_(tag_hs10), // "hs10"
F_(tag_hs11), // "hs11"
F_(tag_hs12), // "hs12"
F_(tag_hs13), // "hs13"
F_(tag_hs14), // "hs14"
F_(tag_hs15), // "hs15"
F_(tag_hs16) // "hs16"
};
@@ -100,9 +101,9 @@ const __FlashStringHelper * const DeviceValue::DeviceValueTAG_mqtt[] PROGMEM = {
F_(tag_none), // ""
F_(heartbeat), // "heartbeat"
F_(tag_boiler_data_mqtt), // ""
F_(tag_device_data_ww_mqtt), // "ww"
F_(tag_thermostat_data), // ""
F_(tag_boiler_data_ww_mqtt), // "ww"
F_(tag_device_data), // ""
F_(tag_device_data_ww_mqtt), // ""
F_(tag_hc1), // "hc1"
F_(tag_hc2), // "hc2"
F_(tag_hc3), // "hc3"
@@ -121,6 +122,7 @@ const __FlashStringHelper * const DeviceValue::DeviceValueTAG_mqtt[] PROGMEM = {
F_(tag_wwc8), // "wwc8"
F_(tag_wwc9), // "wwc9"
F_(tag_wwc10), // "wwc10"
F_(tag_ahs), // "ahs"
F_(tag_hs1), // "hs1"
F_(tag_hs2), // "hs2"
F_(tag_hs3), // "hs3"

View File

@@ -75,9 +75,9 @@ class DeviceValue {
enum DeviceValueTAG : uint8_t {
TAG_NONE = 0, // wild card
TAG_HEARTBEAT,
TAG_BOILER_DATA,
TAG_BOILER_DATA_WW,
TAG_DEVICE_DATA,
TAG_DEVICE_DATA_WW,
TAG_THERMOSTAT_DATA,
TAG_HC1,
TAG_HC2,
TAG_HC3,
@@ -96,6 +96,7 @@ class DeviceValue {
TAG_WWC8,
TAG_WWC9,
TAG_WWC10,
TAG_AHS,
TAG_HS1,
TAG_HS2,
TAG_HS3,

View File

@@ -28,9 +28,9 @@ ESP8266React EMSESP::esp8266React(&webServer, &dummyFS);
WebSettingsService EMSESP::webSettingsService = WebSettingsService(&webServer, &dummyFS, EMSESP::esp8266React.getSecurityManager());
WebCustomizationService EMSESP::webCustomizationService = WebCustomizationService(&webServer, &dummyFS, EMSESP::esp8266React.getSecurityManager());
#else
ESP8266React EMSESP::esp8266React(&webServer, &LITTLEFS);
WebSettingsService EMSESP::webSettingsService = WebSettingsService(&webServer, &LITTLEFS, EMSESP::esp8266React.getSecurityManager());
WebCustomizationService EMSESP::webCustomizationService = WebCustomizationService(&webServer, &LITTLEFS, EMSESP::esp8266React.getSecurityManager());
ESP8266React EMSESP::esp8266React(&webServer, &LittleFS);
WebSettingsService EMSESP::webSettingsService = WebSettingsService(&webServer, &LittleFS, EMSESP::esp8266React.getSecurityManager());
WebCustomizationService EMSESP::webCustomizationService = WebCustomizationService(&webServer, &LittleFS, EMSESP::esp8266React.getSecurityManager());
#endif
WebStatusService EMSESP::webStatusService = WebStatusService(&webServer, EMSESP::esp8266React.getSecurityManager());
@@ -60,19 +60,18 @@ AnalogSensor EMSESP::analogsensor_; // Analog sensors
Shower EMSESP::shower_; // Shower logic
// static/common variables
uint8_t EMSESP::actual_master_thermostat_ = EMSESP_DEFAULT_MASTER_THERMOSTAT; // which thermostat leads when multiple found
uint16_t EMSESP::watch_id_ = WATCH_ID_NONE; // for when log is TRACE. 0 means no trace set
uint8_t EMSESP::watch_ = 0; // trace off
uint16_t EMSESP::read_id_ = WATCH_ID_NONE;
bool EMSESP::read_next_ = false;
uint16_t EMSESP::publish_id_ = 0;
bool EMSESP::tap_water_active_ = false; // for when Boiler states we having running warm water. used in Shower()
uint32_t EMSESP::last_fetch_ = 0;
uint8_t EMSESP::publish_all_idx_ = 0;
uint8_t EMSESP::unique_id_count_ = 0;
bool EMSESP::trace_raw_ = false;
uint16_t EMSESP::wait_validate_ = 0;
bool EMSESP::wait_km_ = true;
uint16_t EMSESP::watch_id_ = WATCH_ID_NONE; // for when log is TRACE. 0 means no trace set
uint8_t EMSESP::watch_ = 0; // trace off
uint16_t EMSESP::read_id_ = WATCH_ID_NONE;
bool EMSESP::read_next_ = false;
uint16_t EMSESP::publish_id_ = 0;
bool EMSESP::tap_water_active_ = false; // for when Boiler states we having running warm water. used in Shower()
uint32_t EMSESP::last_fetch_ = 0;
uint8_t EMSESP::publish_all_idx_ = 0;
uint8_t EMSESP::unique_id_count_ = 0;
bool EMSESP::trace_raw_ = false;
uint16_t EMSESP::wait_validate_ = 0;
bool EMSESP::wait_km_ = true;
// for a specific EMS device go and request data values
// or if device_id is 0 it will fetch from all our known and active devices
@@ -168,63 +167,6 @@ void EMSESP::scan_devices() {
EMSESP::send_read_request(EMSdevice::EMS_TYPE_UBADevices, EMSdevice::EMS_DEVICE_ID_BOILER);
}
/**
* if thermostat master is 0x18 it handles only ww and hc1, hc2..hc8 handled by devices 0x19..0x1F
* we send to right device and match all reads to 0x18
*/
uint8_t EMSESP::check_master_device(const uint8_t device_id, const uint16_t type_id, const bool read) {
if (device_id != 0x10 && (device_id < 0x18 || device_id > 0x1F)) {
return device_id;
}
if (actual_master_thermostat_ == 0x18) {
uint16_t mon_ids[] = {0x02A5, 0x02A6, 0x02A7, 0x02A8, 0x02A9, 0x02AA, 0x02AB, 0x02AC};
uint16_t set_ids[] = {0x02B9, 0x02BA, 0x02BB, 0x02BC, 0x02BD, 0x02BE, 0x02BF, 0x02C0};
uint16_t summer_ids[] = {0x02AF, 0x02B0, 0x02B1, 0x02B2, 0x02B3, 0x02B4, 0x02B5, 0x02B6};
uint16_t curve_ids[] = {0x029B, 0x029C, 0x029D, 0x029E, 0x029F, 0x02A0, 0x02A1, 0x02A2};
uint16_t summer2_ids[] = {0x0471, 0x0472, 0x0473, 0x0474, 0x0475, 0x0476, 0x0477, 0x0478};
uint16_t master_ids[] = {0x02F5, 0x031B, 0x031D, 0x031E, 0x023A, 0x0267, 0x0240};
// look for heating circuits
for (uint8_t i = 0; i < sizeof(mon_ids) / 2; i++) {
if (type_id == mon_ids[i] || type_id == set_ids[i] || type_id == summer_ids[i] || type_id == curve_ids[i] || type_id == summer2_ids[i]) {
if (read) {
// receiving telegrams and map all to master thermostat at 0x18 (src manipulated)
return 0x18;
} else {
// sending telegrams to the individual thermostats (dst manipulated)
return 0x18 + i;
}
}
}
// look for ids that are only handled by master
for (uint8_t i = 0; i < sizeof(master_ids) / 2; i++) {
if (type_id == master_ids[i]) {
return 0x18;
}
}
} else if (actual_master_thermostat_ == 0x10) {
// Junkers FW200 supports hc1/hc2, hc3/hc4 handled by devices 0x1A...
// see https://github.com/emsesp/EMS-ESP32/issues/336
uint16_t mon_ids[] = {0x0171, 0x0172};
uint16_t set_ids[] = {0x0167, 0x0168};
for (uint8_t i = 0; i < sizeof(mon_ids) / 2; i++) {
if (type_id == mon_ids[i] || type_id == set_ids[i]) {
// reads to master thermostat, writes to remote thermostats
return (read ? actual_master_thermostat_ : 0x1A + i);
}
}
}
return device_id;
}
void EMSESP::actual_master_thermostat(const uint8_t device_id) {
actual_master_thermostat_ = device_id;
}
uint8_t EMSESP::actual_master_thermostat() {
return actual_master_thermostat_;
}
// to watch both type IDs and deviceIDs
void EMSESP::watch_id(uint16_t watch_id) {
watch_id_ = watch_id;
@@ -560,13 +502,13 @@ void EMSESP::publish_device_values(uint8_t device_type) {
bool nested = (Mqtt::is_nested());
// group by device type
for (const auto & emsdevice : emsdevices) {
if (emsdevice && (emsdevice->device_type() == device_type)) {
// specially for MQTT Discovery
// we may have some RETAINED /config topics that reference fields in the data payloads that no longer exist
// remove them immediately to prevent HA from complaining
// we need to do this first before the data payload is published, and only done once!
if (Mqtt::ha_enabled()) {
if (Mqtt::ha_enabled()) {
for (const auto & emsdevice : emsdevices) {
if (emsdevice && (emsdevice->device_type() == device_type)) {
// specially for MQTT Discovery
// we may have some RETAINED /config topics that reference fields in the data payloads that no longer exist
// remove them immediately to prevent HA from complaining
// we need to do this first before the data payload is published, and only done once!
if (emsdevice->ha_config_firstrun()) {
emsdevice->ha_config_clear();
emsdevice->ha_config_firstrun(false);
@@ -575,79 +517,40 @@ void EMSESP::publish_device_values(uint8_t device_type) {
emsdevice->mqtt_ha_entity_config_remove();
}
}
// if its a boiler, generate json for each group and publish it directly. not nested
if (device_type == DeviceType::BOILER) {
json = doc.to<JsonObject>();
if (emsdevice->generate_values(json, DeviceValueTAG::TAG_BOILER_DATA, false, EMSdevice::OUTPUT_TARGET::MQTT)) {
Mqtt::publish(Mqtt::tag_to_topic(device_type, DeviceValueTAG::TAG_BOILER_DATA), json);
}
json = doc.to<JsonObject>();
if (emsdevice->generate_values(json, DeviceValueTAG::TAG_DEVICE_DATA_WW, false, EMSdevice::OUTPUT_TARGET::MQTT)) {
Mqtt::publish(Mqtt::tag_to_topic(device_type, DeviceValueTAG::TAG_DEVICE_DATA_WW), json);
}
need_publish = false;
}
// Thermostat
else if (device_type == DeviceType::THERMOSTAT) {
// only publish the single master thermostat
if (emsdevice->device_id() == EMSESP::actual_master_thermostat()) {
if (nested) {
json = doc.to<JsonObject>();
need_publish |= emsdevice->generate_values(json, DeviceValueTAG::TAG_NONE, true, EMSdevice::OUTPUT_TARGET::MQTT); // nested
} else {
json = doc.to<JsonObject>();
need_publish |= emsdevice->generate_values(json, DeviceValueTAG::TAG_THERMOSTAT_DATA, false, EMSdevice::OUTPUT_TARGET::MQTT); // not nested
need_publish |= emsdevice->generate_values(json, DeviceValueTAG::TAG_DEVICE_DATA_WW, false, EMSdevice::OUTPUT_TARGET::MQTT);
if (need_publish) {
Mqtt::publish(Mqtt::tag_to_topic(device_type, DeviceValueTAG::TAG_NONE), json);
}
for (uint8_t hc_tag = DeviceValueTAG::TAG_HC1; hc_tag <= DeviceValueTAG::TAG_HC8; hc_tag++) {
json = doc.to<JsonObject>();
if (emsdevice->generate_values(json, hc_tag, false, EMSdevice::OUTPUT_TARGET::MQTT)) { // not nested
Mqtt::publish(Mqtt::tag_to_topic(device_type, hc_tag), json);
}
}
need_publish = false;
}
}
}
// Mixer
else if (device_type == DeviceType::MIXER) {
if (nested) {
need_publish |= emsdevice->generate_values(json, DeviceValueTAG::TAG_NONE, true, EMSdevice::OUTPUT_TARGET::MQTT); // nested
} else {
for (uint8_t hc_tag = DeviceValueTAG::TAG_HC1; hc_tag <= DeviceValueTAG::TAG_WWC10; hc_tag++) {
json = doc.to<JsonObject>();
if (emsdevice->generate_values(json, hc_tag, false, EMSdevice::OUTPUT_TARGET::MQTT)) { // not nested
Mqtt::publish(Mqtt::tag_to_topic(device_type, hc_tag), json);
}
}
need_publish = false;
}
} else {
// for all other devices add the values to the json
need_publish |= emsdevice->generate_values(json, DeviceValueTAG::TAG_NONE, true, EMSdevice::OUTPUT_TARGET::MQTT); // nested
}
// we want to create the /config topic after the data payload to prevent HA from throwing up a warning
if (Mqtt::ha_enabled()) {
emsdevice->mqtt_ha_entity_config_create();
}
}
}
// publish it under a single topic, only if we have data to publish
for (uint8_t tag = DeviceValueTAG::TAG_BOILER_DATA_WW; tag <= DeviceValueTAG::TAG_HS16; tag++) {
JsonObject json_hc = json;
bool nest_created = false;
for (const auto & emsdevice : emsdevices) {
if (emsdevice && (emsdevice->device_type() == device_type)) {
if (nested && !nest_created && emsdevice->has_tag(tag)) {
json_hc = doc.createNestedObject(EMSdevice::tag_to_string(tag));
nest_created = true;
}
need_publish |= emsdevice->generate_values(json_hc, tag, false, EMSdevice::OUTPUT_TARGET::MQTT);
}
}
if (need_publish && ((!nested && tag >= DeviceValueTAG::TAG_DEVICE_DATA_WW) || (tag == DeviceValueTAG::TAG_BOILER_DATA_WW))) {
Mqtt::publish(Mqtt::tag_to_topic(device_type, tag), json);
json = doc.to<JsonObject>();
need_publish = false;
}
}
if (need_publish) {
if (doc.overflowed()) {
LOG_WARNING(F("MQTT buffer overflow, please use individual topics"));
}
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
snprintf(topic, sizeof(topic), "%s_data", EMSdevice::device_type_2_device_name(device_type).c_str());
Mqtt::publish(topic, json);
Mqtt::publish(Mqtt::tag_to_topic(device_type, DeviceValueTAG::TAG_NONE), json);
}
// we want to create the /config topic after the data payload to prevent HA from throwing up a warning
if (Mqtt::ha_enabled()) {
for (const auto & emsdevice : emsdevices) {
if (emsdevice && (emsdevice->device_type() == device_type)) {
emsdevice->mqtt_ha_entity_config_create();
}
}
}
}
@@ -742,7 +645,6 @@ std::string EMSESP::pretty_telegram(std::shared_ptr<const Telegram> telegram) {
std::string src_name("");
std::string dest_name("");
std::string type_name("");
std::string direction("");
for (const auto & emsdevice : emsdevices) {
if (emsdevice) {
// get src & dest
@@ -779,16 +681,15 @@ std::string EMSESP::pretty_telegram(std::shared_ptr<const Telegram> telegram) {
type_name = read_flash_string(F("?"));
}
if (telegram->operation == Telegram::Operation::RX_READ) {
direction = read_flash_string(F("<-"));
} else {
direction = read_flash_string(F("->"));
}
std::string str;
str.reserve(200);
str = src_name + "(" + Helpers::hextoa(src) + ") " + direction + " " + dest_name + "(" + Helpers::hextoa(dest) + "), " + type_name + "("
+ Helpers::hextoa(telegram->type_id) + "), data: " + telegram->to_string_message();
if (telegram->operation == Telegram::Operation::RX_READ) {
str = src_name + "(" + Helpers::hextoa(src) + ") <- " + dest_name + "(" + Helpers::hextoa(dest) + "), " + type_name + "("
+ Helpers::hextoa(telegram->type_id) + "), length: " + Helpers::hextoa(telegram->message_data[0]);
} else {
str = src_name + "(" + Helpers::hextoa(src) + ") -> " + dest_name + "(" + Helpers::hextoa(dest) + "), " + type_name + "("
+ Helpers::hextoa(telegram->type_id) + "), data: " + telegram->to_string_message();
}
if (offset) {
str += " (offset " + Helpers::itoa(offset) + ")";
@@ -925,16 +826,13 @@ bool EMSESP::process_telegram(std::shared_ptr<const Telegram> telegram) {
// match device_id and type_id
// calls the associated process function for that EMS device
// returns false if the device_id doesn't recognize it
// after the telegram has been processed, call see if there have been values changed and we need to do a MQTT publish
// after the telegram has been processed, see if there have been values changed and we need to do a MQTT publish
bool found = false;
bool knowndevice = false;
for (const auto & emsdevice : emsdevices) {
if (emsdevice->is_device_id(telegram->src) || emsdevice->is_device_id(telegram->dest)) {
if (emsdevice->is_device_id(telegram->src)) {
knowndevice = true;
found = emsdevice->handle_telegram(telegram);
if (found && emsdevice->is_device_id(telegram->dest)) {
LOG_DEBUG(F("Process setting 0x%02X for device 0x%02X"), telegram->type_id, telegram->dest);
}
// if we correctly processed the telegram then follow up with sending it via MQTT (if enabled)
if (found && Mqtt::connected()) {
if ((mqtt_.get_publish_onchange(emsdevice->device_type()) && emsdevice->has_update())
@@ -951,7 +849,7 @@ bool EMSESP::process_telegram(std::shared_ptr<const Telegram> telegram) {
if (wait_validate_ == telegram->type_id) {
wait_validate_ = 0;
}
if (!found && emsdevice->is_device_id(telegram->src) && telegram->message_length > 0) {
if (!found && telegram->message_length > 0) {
emsdevice->add_handlers_ignored(telegram->type_id);
}
break;
@@ -1007,10 +905,6 @@ void EMSESP::show_devices(uuid::console::Shell & shell) {
for (const auto & emsdevice : emsdevices) {
if (emsdevice && (emsdevice->device_type() == device_class.first)) {
shell.printf(F("%s: %s"), emsdevice->device_type_name().c_str(), emsdevice->to_string().c_str());
if ((num_thermostats > 1) && (emsdevice->device_type() == EMSdevice::DeviceType::THERMOSTAT)
&& (emsdevice->device_id() == actual_master_thermostat())) {
shell.printf(F(" **master device**"));
}
shell.println();
emsdevice->show_telegram_handlers(shell);
@@ -1034,6 +928,9 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, const
// first check to see if we already have it, if so update the record
for (const auto & emsdevice : emsdevices) {
if (emsdevice && emsdevice->is_device_id(device_id)) {
if (product_id == 0) { // update only with valid product_id
return true;
}
LOG_DEBUG(F("Updating details for already active deviceID 0x%02X"), device_id);
emsdevice->product_id(product_id);
emsdevice->version(version);
@@ -1058,9 +955,9 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, const
for (auto & device : device_library_) {
if (device.product_id == product_id) {
// sometimes boilers share the same productID as controllers
// so only add boilers if the device_id is 0x08, which is fixed for EMS
// so only add boilers if the device_id is 0x08 or 0x60 or 0x70.., which is fixed for EMS
if (device.device_type == DeviceType::BOILER) {
if (device_id == EMSdevice::EMS_DEVICE_ID_BOILER
if (device_id == EMSdevice::EMS_DEVICE_ID_BOILER || device_id == EMSdevice::EMS_DEVICE_ID_AM200
|| (device_id >= EMSdevice::EMS_DEVICE_ID_BOILER_1 && device_id <= EMSdevice::EMS_DEVICE_ID_BOILER_F)) {
device_p = &device;
break;
@@ -1203,23 +1100,36 @@ bool EMSESP::command_commands(uint8_t device_type, JsonObject & output, const in
bool EMSESP::command_info(uint8_t device_type, JsonObject & output, const int8_t id, const uint8_t output_target) {
bool has_value = false;
uint8_t tag;
if (id >= 1 && id <= 8) {
tag = DeviceValueTAG::TAG_HC1 + id - 1;
} else if (id >= 9 && id <= 19) {
tag = DeviceValueTAG::TAG_WWC1 + id - 9;
if (id >= 1 && id <= (1 + DeviceValueTAG::TAG_HS16 - DeviceValueTAG::TAG_HC1)) {
tag = DeviceValueTAG::TAG_HC1 + id - 1; // this sets also WWC and HS
} else if (id == -1 || id == 0) {
tag = DeviceValueTAG::TAG_NONE;
} else {
return false;
}
for (const auto & emsdevice : emsdevices) {
if (emsdevice && (emsdevice->device_type() == device_type)
&& ((device_type != DeviceType::THERMOSTAT) || (emsdevice->device_id() == EMSESP::actual_master_thermostat()))) {
has_value |= emsdevice->generate_values(output, tag, (id < 1), output_target); // use nested for id -1 and 0
if (id > 0 || output_target == EMSdevice::OUTPUT_TARGET::API_VERBOSE) {
for (const auto & emsdevice : emsdevices) {
if (emsdevice && (emsdevice->device_type() == device_type)) {
has_value |= emsdevice->generate_values(output, tag, (id < 1), output_target); // use nested for id -1 and 0
}
}
return has_value;
}
// for nested output add for each tag
for (tag = DeviceValueTAG::TAG_BOILER_DATA_WW; tag <= DeviceValueTAG::TAG_HS16; tag++) {
JsonObject output_hc = output;
bool nest_created = false;
for (const auto & emsdevice : emsdevices) {
if (emsdevice && (emsdevice->device_type() == device_type)) {
if (!nest_created && emsdevice->has_tag(tag)) {
output_hc = output.createNestedObject(EMSdevice::tag_to_string(tag));
nest_created = true;
}
has_value |= emsdevice->generate_values(output_hc, tag, true, output_target); // use nested for id -1 and 0
}
}
}
return has_value;
}
@@ -1373,8 +1283,8 @@ void EMSESP::start() {
// start the file system
#ifndef EMSESP_STANDALONE
if (!LITTLEFS.begin(true)) {
Serial.println("LITTLEFS Mount failed. EMS-ESP stopped.");
if (!LittleFS.begin(true)) {
Serial.println("LittleFS Mount Failed. EMS-ESP stopped.");
return;
}
#endif

View File

@@ -134,10 +134,6 @@ class EMSESP {
static uint8_t count_devices();
static uint8_t device_index(const uint8_t device_type, const uint8_t unique_id);
static uint8_t actual_master_thermostat();
static void actual_master_thermostat(const uint8_t device_id);
static uint8_t check_master_device(const uint8_t device_id, const uint16_t type_id, const bool read);
static bool get_device_value_info(JsonObject & root, const char * cmd, const int8_t id, const uint8_t devicetype);
static void show_device_values(uuid::console::Shell & shell);
@@ -261,7 +257,6 @@ class EMSESP {
};
static std::vector<Device_record> device_library_;
static uint8_t actual_master_thermostat_;
static uint16_t watch_id_;
static uint8_t watch_;
static uint16_t read_id_;

View File

@@ -52,7 +52,6 @@ char * Helpers::hextoa(char * result, const uint16_t value) {
return result;
}
// same as above but to a hex string
std::string Helpers::hextoa(const uint16_t value, bool prefix) {
char buf[5];

View File

@@ -65,8 +65,6 @@ MAKE_PSTR_WORD(reconnect)
MAKE_PSTR_WORD(ssid)
MAKE_PSTR_WORD(heartbeat)
MAKE_PSTR_WORD(users)
MAKE_PSTR_WORD(master)
MAKE_PSTR_WORD(pin)
MAKE_PSTR_WORD(publish)
MAKE_PSTR_WORD(timeout)
MAKE_PSTR_WORD(board_profile)
@@ -105,7 +103,6 @@ MAKE_PSTR_WORD(unknown)
MAKE_PSTR_WORD(dallassensor)
// format strings
MAKE_PSTR(master_thermostat_fmt, "Master Thermostat Device ID: %s")
MAKE_PSTR(host_fmt, "Host: %s")
MAKE_PSTR(port_fmt, "Port: %d")
MAKE_PSTR(hostname_fmt, "Hostname: %s")
@@ -206,9 +203,9 @@ MAKE_PSTR(l, "l")
// mqtt tags must not have spaces
MAKE_PSTR(tag_none, "")
MAKE_PSTR(tag_heartbeat, "")
MAKE_PSTR(tag_boiler_data, "")
MAKE_PSTR(tag_device_data_ww, "Warmwasser")
MAKE_PSTR(tag_thermostat_data, "")
MAKE_PSTR(tag_boiler_data_ww, "ww")
MAKE_PSTR(tag_device_data, "")
MAKE_PSTR(tag_device_data_ww, "ww")
MAKE_PSTR(tag_hc1, "hc1")
MAKE_PSTR(tag_hc2, "hc2")
MAKE_PSTR(tag_hc3, "hc3")
@@ -227,6 +224,7 @@ MAKE_PSTR(tag_wwc7, "wwc7")
MAKE_PSTR(tag_wwc8, "wwc8")
MAKE_PSTR(tag_wwc9, "wwc9")
MAKE_PSTR(tag_wwc10, "wwc10")
MAKE_PSTR(tag_ahs, "ahs")
MAKE_PSTR(tag_hs1, "hs1")
MAKE_PSTR(tag_hs2, "hs2")
MAKE_PSTR(tag_hs3, "hs3")
@@ -246,8 +244,9 @@ MAKE_PSTR(tag_hs16, "hs16")
// MQTT topic names
// MAKE_PSTR(tag_heartbeat_mqtt, "heartbeat")
MAKE_PSTR(tag_boiler_data_mqtt, "")
MAKE_PSTR(tag_device_data_ww_mqtt, "ww")
// MAKE_PSTR(tag_boiler_data_mqtt, "")
MAKE_PSTR(tag_boiler_data_ww_mqtt, "ww")
MAKE_PSTR(tag_device_data_ww_mqtt, "")
// boiler
MAKE_PSTR(time, "Zeit")
@@ -262,6 +261,7 @@ MAKE_PSTR_(continuos, "kontinuierlich")
MAKE_PSTR(3wayvalve, "3-Wege Ventil")
MAKE_PSTR(chargepump, "Ladepumpe")
MAKE_PSTR(hot, "Heiss")
MAKE_PSTR(high_comfort, "Heiss Komfort")
MAKE_PSTR(eco, "Eco")
MAKE_PSTR(intelligent, "Intelligent")
MAKE_PSTR_(flow, "Fluss")
@@ -270,6 +270,8 @@ MAKE_PSTR_(buffer, "Speicher")
MAKE_PSTR(bufferedflow, "Durchlaufspeicher")
MAKE_PSTR(layeredbuffer, "Schichtspeicher")
MAKE_PSTR(maintenance, "Wartung")
MAKE_PSTR(heating, "Heizen")
MAKE_PSTR(cooling, "K<EFBFBD>hlen")
// boiler lists
MAKE_PSTR_LIST(tpl_date, F("Format: < dd.mm.yyyy >")) // template for text input
@@ -277,10 +279,19 @@ MAKE_PSTR_LIST(enum_off_time_date_manual, F_(off), F_(time), F_(date), F_(manual
MAKE_PSTR_LIST(enum_freq, F_(off), F_(1x3min), F_(2x3min), F_(3x3min), F_(4x3min), F_(5x3min), F_(6x3min), F_(continuous))
MAKE_PSTR_LIST(enum_charge, F_(chargepump), F_(3wayvalve))
MAKE_PSTR_LIST(enum_comfort, F_(hot), F_(eco), F_(intelligent))
MAKE_PSTR_LIST(enum_comfort1, F_(high_comfort), F_(eco))
MAKE_PSTR_LIST(enum_flow, F_(off), F_(flow), F_(bufferedflow), F_(buffer), F_(layeredbuffer))
MAKE_PSTR_LIST(enum_reset, F("-"), F_(maintenance), F_(error))
// MAKE_PSTR_LIST(enum_bool, F_(off), F_(on))
// AM200 lists
MAKE_PSTR_LIST(enum_vr2Config, F_(off), F("bypass"));
MAKE_PSTR_LIST(enum_aPumpSignal, F_(off), F("pwm"), F("pwm_invers"));
MAKE_PSTR_LIST(enum_bufBypass, F("no"), F_(mixer), F("valve"));
MAKE_PSTR_LIST(enum_bufConfig, F("monovalent"), F("bivalent"));
MAKE_PSTR_LIST(enum_blockMode, F_(off), F_(auto), F("blocking"));
MAKE_PSTR_LIST(enum_blockTerm, F("n_o"), F("n_c"));
//heatpump
MAKE_PSTR_LIST(enum_hpactivity, F("Kein"), F("Heizen"), F("Kühlen"), F("Warmwasser"), F("Pool"))
@@ -311,6 +322,7 @@ MAKE_PSTR(winter, "Winter")
MAKE_PSTR(outdoor, "Aussentemperatur")
MAKE_PSTR_WORD(mpc)
MAKE_PSTR(room, "Raum")
MAKE_PSTR(room_outdoor, "Raum+Au<41>en")
MAKE_PSTR(power, "Leistung")
MAKE_PSTR(constant, "konstant")
MAKE_PSTR(simple, "einfach")
@@ -358,7 +370,7 @@ MAKE_PSTR_LIST(enum_ibaLanguage_RC30, F_(german), F_(dutch))
MAKE_PSTR_LIST(enum_floordrystatus, F_(off), F_(start), F_(heat), F_(hold), F_(cool), F_(end))
MAKE_PSTR_LIST(enum_ibaBuildingType, F_(light), F_(medium), F_(heavy)) // RC300
MAKE_PSTR_LIST(enum_PID, F("fast"), F_(medium), F("slow"))
MAKE_PSTR_LIST(enum_wwMode, F_(off), F_(low), F_(high), F_(auto), F_(own_prog))
MAKE_PSTR_LIST(enum_wwMode, F_(off), F("normal"), F_(comfort), F_(auto), F_(own_prog), F_(eco))
MAKE_PSTR_LIST(enum_wwCircMode, F_(off), F_(on), F_(auto), F_(own_prog))
MAKE_PSTR_LIST(enum_wwMode2, F_(off), F_(on), F_(auto))
MAKE_PSTR_LIST(enum_wwMode3, F_(on), F_(off), F_(auto))
@@ -366,6 +378,7 @@ MAKE_PSTR_LIST(enum_heatingtype, F_(off), F_(radiator), F_(convector), F_(floor)
MAKE_PSTR_LIST(enum_summermode, F_(summer), F_(auto), F_(winter))
MAKE_PSTR_LIST(enum_hpoperatingmode, F_(off), F_(auto), F("heizen"), F("kühlen"))
MAKE_PSTR_LIST(enum_summer, F_(winter), F_(summer))
MAKE_PSTR_LIST(enum_operatingstate, F_(heating), F_(off), F_(cooling))
MAKE_PSTR_LIST(enum_mode, F_(manual), F_(auto)) // RC100, RC300, RC310
MAKE_PSTR_LIST(enum_mode2, F_(off), F_(manual), F_(auto)) // RC20
@@ -381,9 +394,12 @@ MAKE_PSTR_LIST(enum_modetype4, 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))
MAKE_PSTR_LIST(enum_reducemode1, F_(outdoor), F_(room), F_(reduce)) // RC310 values: 1-3
MAKE_PSTR_LIST(enum_nofrostmode, F_(off), F_(room), F_(outdoor))
MAKE_PSTR_LIST(enum_nofrostmode1, F_(room), F_(outdoor), F_(room_outdoor))
MAKE_PSTR_LIST(enum_controlmode, F_(off), F_(optimized), F_(simple), F_(mpc), F_(room), F_(power), F_(constant))
MAKE_PSTR_LIST(enum_controlmode1, F("weather-compensated"), F("outside-basepoint"), F("n/a"), F_(room)) // RC310 1-4
MAKE_PSTR_LIST(enum_controlmode2, F_(outdoor), F_(room))
// MAKE_PSTR_LIST(enum_controlmode3, F_(off), F_(room), F_(outdoor), F("room+outdoor"))
MAKE_PSTR_LIST(enum_control, F_(off), F_(rc20), F_(rc3x))
@@ -474,6 +490,8 @@ MAKE_PSTR_LIST(maintenanceMessage, F("maintenancemessage"), F("Wartungsmeldung")
MAKE_PSTR_LIST(maintenanceDate, F("maintenancedate"), F("Wartungsdatum"))
MAKE_PSTR_LIST(maintenanceType, F_(maintenance), F("Wartungsplan"))
MAKE_PSTR_LIST(maintenanceTime, F("maintenancetime"), F("Wartung in"))
MAKE_PSTR_LIST(emergencyOps, F("emergencyops"), F("emergency operation"))
MAKE_PSTR_LIST(emergencyTemp, F("emergencytemp"), F("emergency temperature"))
// heatpump/compress specific
MAKE_PSTR_LIST(upTimeControl, F("uptimecontrol"), F("Betriebszeit total heizen"))
@@ -538,6 +556,37 @@ MAKE_PSTR_LIST(electricFactor, F("electricfactor"), F("electric energy factor"))
MAKE_PSTR_LIST(delayBoiler, F("delayboiler"), F("delay boiler support"))
MAKE_PSTR_LIST(tempDiffBoiler, F("tempdiffboiler"), F("tempediff boiler support"))
// alternative heatsource AM200
MAKE_PSTR_LIST(aCylTopTemp, F("cyltoptemp"), F("Zylinder oben Temperatur"))
MAKE_PSTR_LIST(aCylCenterTemp, F("cylcentertemp"), F("Zylinder mitte Temperatur"))
MAKE_PSTR_LIST(aCylBottomTemp, F("cylbottomtemp"), F("Zylinder unten Temperatur"))
MAKE_PSTR_LIST(aFlowTemp, F("altflowtemp"), F("Alternativ hs Flusstemperatur"))
MAKE_PSTR_LIST(aRetTemp, F("altrettemp"), F("Alternativ hs Rücktemperatur"))
MAKE_PSTR_LIST(sysFlowTemp, F("sysflowtemp"), F("System Flusstemperature"))
MAKE_PSTR_LIST(sysRetTemp, F("sysrettemp"), F("System Rücktemperature"))
MAKE_PSTR_LIST(valveByPass, F("valvebypass"), F("bypass Ventil"))
MAKE_PSTR_LIST(valveBuffer, F("valvebuffer"), F("Puffer Ventil"))
MAKE_PSTR_LIST(valveReturn, F("valvereturn"), F("Rückfluss Ventil"))
MAKE_PSTR_LIST(aPumpMod, F("altpumpmod"), F("Alternativ hs Pumpenmodulation"))
MAKE_PSTR_LIST(heatSource, F("heatsource"), F("Alternativ Heizung"))
MAKE_PSTR_LIST(vr2Config, F("vr2config"), F("vr2 configuration"))
MAKE_PSTR_LIST(ahsActivated, F("ahsactivated"), F("alternate heat source activation"))
MAKE_PSTR_LIST(aPumpConfig, F("apumpconfig"), F("primary pump config"))
MAKE_PSTR_LIST(aPumpSignal, F("apumpsignal"), F("output for pr1 pump"))
MAKE_PSTR_LIST(aPumpMin, F("apumpmin"), F("min output pump pr1"))
MAKE_PSTR_LIST(tempRise, F("temprise"), F("ahs return temp rise"))
MAKE_PSTR_LIST(setReturnTemp, F("setreturntemp"), F("set temp return"))
MAKE_PSTR_LIST(mixRuntime, F("mixruntime"), F("mixer run time"))
// MAKE_PSTR_LIST(setFlowTemp, F("setflowtemp"), F("set flow temp"))
MAKE_PSTR_LIST(bufBypass, F("bufbypass"), F("buffer bypass config"))
MAKE_PSTR_LIST(bufMixRuntime, F("bufmixruntime"), F("bypass mixer run time"))
MAKE_PSTR_LIST(bufConfig, F("bufconfig"), F("dhw buffer config"))
MAKE_PSTR_LIST(blockMode, F("blockmode"), F("config htg. blocking mode"))
MAKE_PSTR_LIST(blockTerm, F("blockterm"), F("config of block terminal"))
MAKE_PSTR_LIST(blockHyst, F("blockhyst"), F("hyst. for bolier block"))
MAKE_PSTR_LIST(releaseWait, F("releasewait"), F("boiler release wait time"))
// the following are dhw for the boiler and automatically tagged with 'ww'
MAKE_PSTR_LIST(wWSelTemp, F("wwseltemp"), F("gewählte Temperatur"))
MAKE_PSTR_LIST(wwSelTempLow, F("wwseltemplow"), F("selected lower temperature"))
@@ -565,7 +614,9 @@ MAKE_PSTR_LIST(wWCharging, F("wwcharging"), F("Laden"))
MAKE_PSTR_LIST(wWRecharging, F("wwrecharging"), F("Nachladen"))
MAKE_PSTR_LIST(wWTempOK, F("wwtempok"), F("Temperatur ok"))
MAKE_PSTR_LIST(wWActive, F("wwactive"), F("aktiv"))
MAKE_PSTR_LIST(ww3wayValve, F("ww3wayvalve"), F("3way valve active"))
MAKE_PSTR_LIST(wwTempOK, F("wwtempok"), F("Temperatur ok"))
MAKE_PSTR_LIST(wwActive, F("wwactive"), F("aktiv"))
MAKE_PSTR_LIST(ww3wayValve, F("ww3wayvalve"), F("3-Wegeventil aktiv"))
MAKE_PSTR_LIST(wWSetPumpPower, F("wwsetpumppower"), F("Soll Pumpenleistung"))
MAKE_PSTR_LIST(mixerTemp, F("mixertemp"), F("Mischertemperatur"))
MAKE_PSTR_LIST(wwCylMiddleTemp, F("wwcylmiddletemp"), F("cylinder middle temperature (TS3)"))
@@ -580,11 +631,11 @@ MAKE_PSTR_LIST(wwMaxTemp, F("wwmaxtemp"), F("Maximale Temperatur"))
MAKE_PSTR_LIST(wwOneTimeKey, F("wwonetimekey"), F("Einmalladungstaste"))
// mqtt values / commands
MAKE_PSTR_LIST(switchtime, F("switchtime"), F("program switchtime"))
MAKE_PSTR_LIST(switchtime1, F("switchtime1"), F("own1 program switchtime"))
MAKE_PSTR_LIST(switchtime2, F("switchtime2"), F("own2 program switchtime"))
MAKE_PSTR_LIST(wwswitchtime, F("wwswitchtime"), F("program switchtime"))
MAKE_PSTR_LIST(wwcircswitchtime, F("wwcircswitchtime"), F("circulation program switchtime"))
MAKE_PSTR_LIST(switchtime, F("switchtime"), F("Program Schaltzeit"))
MAKE_PSTR_LIST(switchtime1, F("switchtime1"), F("Program 1 Schaltzeit"))
MAKE_PSTR_LIST(switchtime2, F("switchtime2"), F("Programm 2 Schaltzeit"))
MAKE_PSTR_LIST(wwswitchtime, F("wwswitchtime"), F("Programm Schaltzeit"))
MAKE_PSTR_LIST(wwcircswitchtime, F("wwcircswitchtime"), F("Zirculationsprogramm Schaltzeit"))
MAKE_PSTR_LIST(dateTime, F("datetime"), F("Datum/Zeit"))
MAKE_PSTR_LIST(errorCode, F("errorcode"), F("Fehlermeldung"))
MAKE_PSTR_LIST(ibaMainDisplay, F("display"), F("Anzeige"))
@@ -651,8 +702,11 @@ MAKE_PSTR_LIST(targetflowtemp, F("targetflowtemp"), F("berechnete Flusstemperatu
MAKE_PSTR_LIST(heatingtype, F("heatingtype"), F("Heizungstyp"))
MAKE_PSTR_LIST(summersetmode, F("summersetmode"), F("Einstellung Sommerbetrieb"))
MAKE_PSTR_LIST(hpoperatingmode, F("hpoperatingmode"), F("Wärmepumpe Betriebsmodus"))
MAKE_PSTR_LIST(hpoperatingstate, F("hpoperatingstate"), F("heatpump operating state"))
MAKE_PSTR_LIST(controlmode, F("controlmode"), F("Kontrollmodus"))
MAKE_PSTR_LIST(control, F("control"), F("Fernsteuerung"))
MAKE_PSTR_LIST(wwHolidays, F("wwholidays"), F("holiday dates"))
MAKE_PSTR_LIST(wwVacations, F("wwvacations"), F("vacation dates"))
MAKE_PSTR_LIST(holidays, F("holidays"), F("holiday dates"))
MAKE_PSTR_LIST(vacations, F("vacations"), F("vacation dates"))
MAKE_PSTR_LIST(program, F("program"), F("Programm"))
@@ -669,9 +723,11 @@ MAKE_PSTR_LIST(reducetemp, F("reducetemp"), F("Absenkmodus unter Temperatur"))
MAKE_PSTR_LIST(vacreducetemp, F("vacreducetemp"), F("Urlaub Absenkmodus unter Temperatur"))
MAKE_PSTR_LIST(vacreducemode, F("vacreducemode"), F("Urlaub Absenkmodus"))
MAKE_PSTR_LIST(nofrostmode, F("nofrostmode"), F("Frostschutz Modus"))
MAKE_PSTR_LIST(nofrostmode1, F("nofrostmode1"), F("nofrost mode")) // RC310
MAKE_PSTR_LIST(remotetemp, F("remotetemp"), F("Raumtemperatur der Fernsteuerung"))
MAKE_PSTR_LIST(reducehours, F("reducehours"), F("duration for nighttemp"))
MAKE_PSTR_LIST(reduceminutes, F("reduceminutes"), F("remaining time for nightmode"))
MAKE_PSTR_LIST(switchonoptimization, F("switchonoptimization"), F("switch-on optimization"))
// heatpump
MAKE_PSTR_LIST(airHumidity, F("airhumidity"), F("relative Luftfeuchte"))

View File

@@ -65,8 +65,6 @@ MAKE_PSTR_WORD(reconnect)
MAKE_PSTR_WORD(ssid)
MAKE_PSTR_WORD(heartbeat)
MAKE_PSTR_WORD(users)
MAKE_PSTR_WORD(master)
MAKE_PSTR_WORD(pin)
MAKE_PSTR_WORD(publish)
MAKE_PSTR_WORD(timeout)
MAKE_PSTR_WORD(board_profile)
@@ -105,7 +103,6 @@ MAKE_PSTR_WORD(unknown)
MAKE_PSTR_WORD(dallassensor)
// format strings
MAKE_PSTR(master_thermostat_fmt, "Master Thermostat device ID: %s")
MAKE_PSTR(host_fmt, "Host: %s")
MAKE_PSTR(port_fmt, "Port: %d")
MAKE_PSTR(hostname_fmt, "Hostname: %s")
@@ -206,9 +203,9 @@ MAKE_PSTR(l, "l")
// mqtt tags must not have spaces
MAKE_PSTR(tag_none, "")
MAKE_PSTR(tag_heartbeat, "")
MAKE_PSTR(tag_boiler_data, "")
MAKE_PSTR(tag_boiler_data_ww, "dhw")
MAKE_PSTR(tag_device_data, "")
MAKE_PSTR(tag_device_data_ww, "dhw")
MAKE_PSTR(tag_thermostat_data, "")
MAKE_PSTR(tag_hc1, "hc1")
MAKE_PSTR(tag_hc2, "hc2")
MAKE_PSTR(tag_hc3, "hc3")
@@ -227,6 +224,7 @@ MAKE_PSTR(tag_wwc7, "wwc7")
MAKE_PSTR(tag_wwc8, "wwc8")
MAKE_PSTR(tag_wwc9, "wwc9")
MAKE_PSTR(tag_wwc10, "wwc10")
MAKE_PSTR(tag_ahs, "ahs")
MAKE_PSTR(tag_hs1, "hs1")
MAKE_PSTR(tag_hs2, "hs2")
MAKE_PSTR(tag_hs3, "hs3")
@@ -246,8 +244,9 @@ MAKE_PSTR(tag_hs16, "hs16")
// MQTT topic names
// MAKE_PSTR(tag_heartbeat_mqtt, "heartbeat")
MAKE_PSTR(tag_boiler_data_mqtt, "")
MAKE_PSTR(tag_device_data_ww_mqtt, "ww")
// MAKE_PSTR(tag_boiler_data_mqtt, "")
MAKE_PSTR(tag_boiler_data_ww_mqtt, "ww")
MAKE_PSTR(tag_device_data_ww_mqtt, "")
// boiler
MAKE_PSTR_WORD(time)
@@ -271,6 +270,8 @@ MAKE_PSTR_WORD(buffer)
MAKE_PSTR(bufferedflow, "buffered flow")
MAKE_PSTR(layeredbuffer, "layered buffer")
MAKE_PSTR_WORD(maintenance)
MAKE_PSTR_WORD(heating)
MAKE_PSTR_WORD(cooling)
// boiler lists
MAKE_PSTR_LIST(tpl_date, F("Format: < dd.mm.yyyy >")) // template for text input
@@ -283,8 +284,16 @@ MAKE_PSTR_LIST(enum_flow, F_(off), F_(flow), F_(bufferedflow), F_(buffer), F_(la
MAKE_PSTR_LIST(enum_reset, F("-"), F_(maintenance), F_(error))
// MAKE_PSTR_LIST(enum_bool, F_(off), F_(on))
// AM200 lists
MAKE_PSTR_LIST(enum_vr2Config, F_(off), F("bypass"));
MAKE_PSTR_LIST(enum_aPumpSignal, F_(off), F("pwm"), F("pwm_invers"));
MAKE_PSTR_LIST(enum_bufBypass, F("no"), F_(mixer), F("valve"));
MAKE_PSTR_LIST(enum_bufConfig, F("monovalent"), F("bivalent"));
MAKE_PSTR_LIST(enum_blockMode, F_(off), F_(auto), F("blocking"));
MAKE_PSTR_LIST(enum_blockTerm, F("n_o"), F("n_c"));
//heatpump
MAKE_PSTR_LIST(enum_hpactivity, F("none"), F("heating"), F("cooling"), F("hot water"), F("pool"))
MAKE_PSTR_LIST(enum_hpactivity, F("none"), F_(heating), F_(cooling), F("hot_water"), F("pool"))
// mixer
MAKE_PSTR_LIST(enum_shunt, F("stopped"), F("opening"), F("closing"), F("open"), F("close"))
@@ -313,6 +322,7 @@ MAKE_PSTR_WORD(winter)
MAKE_PSTR_WORD(outdoor)
MAKE_PSTR_WORD(mpc)
MAKE_PSTR_WORD(room)
MAKE_PSTR_WORD(room_outdoor)
MAKE_PSTR_WORD(power)
MAKE_PSTR_WORD(constant)
MAKE_PSTR_WORD(simple)
@@ -341,7 +351,7 @@ MAKE_PSTR(functioning_mode, "functioning mode")
MAKE_PSTR(smoke_temperature, "smoke temperature")
// thermostat lists
MAKE_PSTR_LIST(tpl_datetime, F("Format: < NTP | dd.mm.yyyy-hh:mm:ss-dw-dst >"))
MAKE_PSTR_LIST(tpl_datetime, F("Format: < NTP | dd.mm.yyyy-hh:mm:ss-day(0-6)-dst(0/1) >"))
MAKE_PSTR_LIST(tpl_switchtime, F("Format: <nn> [ not_set | day hh:mm on|off ]"))
MAKE_PSTR_LIST(tpl_switchtime1, F("Format: <nn> [ not_set | day hh:mm Tn ]"))
MAKE_PSTR_LIST(tpl_holidays, F("format: < dd.mm.yyyy-dd.mm.yyyy >"))
@@ -360,14 +370,15 @@ MAKE_PSTR_LIST(enum_ibaLanguage_RC30, F_(german), F_(dutch))
MAKE_PSTR_LIST(enum_floordrystatus, F_(off), F_(start), F_(heat), F_(hold), F_(cool), F_(end))
MAKE_PSTR_LIST(enum_ibaBuildingType, F_(light), F_(medium), F_(heavy))
MAKE_PSTR_LIST(enum_PID, F("fast"), F_(medium), F("slow"))
MAKE_PSTR_LIST(enum_wwMode, F_(off), F_(low), F_(high), F_(auto), F_(own_prog))
MAKE_PSTR_LIST(enum_wwMode, F_(off), F("normal"), F_(comfort), F_(auto), F_(own_prog), F_(eco))
MAKE_PSTR_LIST(enum_wwCircMode, F_(off), F_(on), F_(auto), F_(own_prog))
MAKE_PSTR_LIST(enum_wwMode2, F_(off), F_(on), F_(auto))
MAKE_PSTR_LIST(enum_wwMode3, F_(on), F_(off), F_(auto))
MAKE_PSTR_LIST(enum_heatingtype, F_(off), F_(radiator), F_(convector), F_(floor))
MAKE_PSTR_LIST(enum_summermode, F_(summer), F_(auto), F_(winter))
MAKE_PSTR_LIST(enum_hpoperatingmode, F_(off), F_(auto), F("heating"), F("cooling"))
MAKE_PSTR_LIST(enum_hpoperatingmode, F_(off), F_(auto), F_(heating), F_(cooling))
MAKE_PSTR_LIST(enum_summer, F_(winter), F_(summer))
MAKE_PSTR_LIST(enum_operatingstate, F_(heating), F_(off), F_(cooling))
MAKE_PSTR_LIST(enum_mode, F_(manual), F_(auto)) // RC100, RC300, RC310
MAKE_PSTR_LIST(enum_mode2, F_(off), F_(manual), F_(auto)) // RC20
@@ -383,9 +394,12 @@ MAKE_PSTR_LIST(enum_modetype4, 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))
MAKE_PSTR_LIST(enum_reducemode1, F_(outdoor), F_(room), F_(reduce)) // RC310 values: 1-3
MAKE_PSTR_LIST(enum_nofrostmode, F_(off), F_(room), F_(outdoor))
MAKE_PSTR_LIST(enum_nofrostmode1, F_(room), F_(outdoor), F_(room_outdoor))
MAKE_PSTR_LIST(enum_controlmode, F_(off), F_(optimized), F_(simple), F_(mpc), F_(room), F_(power), F_(constant))
MAKE_PSTR_LIST(enum_controlmode1, F("weather-compensated"), F("outside-basepoint"), F("n/a"), F_(room)) // RC310 1-4
MAKE_PSTR_LIST(enum_controlmode2, F_(outdoor), F_(room))
// MAKE_PSTR_LIST(enum_controlmode3, F_(off), F_(room), F_(outdoor), F("room+outdoor"))
MAKE_PSTR_LIST(enum_control, F_(off), F_(rc20), F_(rc3x))
@@ -531,6 +545,37 @@ MAKE_PSTR_LIST(electricFactor, F("electricfactor"), F("electric energy factor"))
MAKE_PSTR_LIST(delayBoiler, F("delayboiler"), F("delay boiler support"))
MAKE_PSTR_LIST(tempDiffBoiler, F("tempdiffboiler"), F("tempediff boiler support"))
// alternative heatsource AM200
MAKE_PSTR_LIST(aCylTopTemp, F("cyltoptemp"), F("cylinder top temperature"))
MAKE_PSTR_LIST(aCylCenterTemp, F("cylcentertemp"), F("cylinder center temperature"))
MAKE_PSTR_LIST(aCylBottomTemp, F("cylbottomtemp"), F("cylinder bottom temperature"))
MAKE_PSTR_LIST(aFlowTemp, F("altflowtemp"), F("alternative hs flow temperature"))
MAKE_PSTR_LIST(aRetTemp, F("altrettemp"), F("alternative hs return temperature"))
MAKE_PSTR_LIST(sysFlowTemp, F("sysflowtemp"), F("system flow temperature"))
MAKE_PSTR_LIST(sysRetTemp, F("sysrettemp"), F("system return temperature"))
MAKE_PSTR_LIST(valveByPass, F("valvebypass"), F("bypass valve"))
MAKE_PSTR_LIST(valveBuffer, F("valvebuffer"), F("buffer valve"))
MAKE_PSTR_LIST(valveReturn, F("valvereturn"), F("return valve"))
MAKE_PSTR_LIST(aPumpMod, F("altpumpmod"), F("alternative hs pump modulation"))
MAKE_PSTR_LIST(heatSource, F("heatsource"), F("alternative heating active"))
MAKE_PSTR_LIST(vr2Config, F("vr2config"), F("vr2 configuration"))
MAKE_PSTR_LIST(ahsActivated, F("ahsactivated"), F("alternate heat source activation"))
MAKE_PSTR_LIST(aPumpConfig, F("apumpconfig"), F("primary pump config"))
MAKE_PSTR_LIST(aPumpSignal, F("apumpsignal"), F("output for pr1 pump"))
MAKE_PSTR_LIST(aPumpMin, F("apumpmin"), F("min output pump pr1"))
MAKE_PSTR_LIST(tempRise, F("temprise"), F("ahs return temp rise"))
MAKE_PSTR_LIST(setReturnTemp, F("setreturntemp"), F("set temp return"))
MAKE_PSTR_LIST(mixRuntime, F("mixruntime"), F("mixer run time"))
// MAKE_PSTR_LIST(setFlowTemp, F("setflowtemp"), F("set flow temp"))
MAKE_PSTR_LIST(bufBypass, F("bufbypass"), F("buffer bypass config"))
MAKE_PSTR_LIST(bufMixRuntime, F("bufmixruntime"), F("bypass mixer run time"))
MAKE_PSTR_LIST(bufConfig, F("bufconfig"), F("dhw buffer config"))
MAKE_PSTR_LIST(blockMode, F("blockmode"), F("config htg. blocking mode"))
MAKE_PSTR_LIST(blockTerm, F("blockterm"), F("config of block terminal"))
MAKE_PSTR_LIST(blockHyst, F("blockhyst"), F("hyst. for bolier block"))
MAKE_PSTR_LIST(releaseWait, F("releasewait"), F("boiler release wait time"))
// the following are dhw for the boiler and automatically tagged with 'ww'
MAKE_PSTR_LIST(wwSelTemp, F("wwseltemp"), F("selected temperature"))
MAKE_PSTR_LIST(wwSelTempLow, F("wwseltemplow"), F("selected lower temperature"))
@@ -632,6 +677,7 @@ MAKE_PSTR_LIST(nighttemp2, F("nighttemp"), F("night temperature T1"))
MAKE_PSTR_LIST(ecotemp, F("ecotemp"), F("eco temperature"))
MAKE_PSTR_LIST(manualtemp, F("manualtemp"), F("manual temperature"))
MAKE_PSTR_LIST(tempautotemp, F("tempautotemp"), F("temporary set temperature automode"))
MAKE_PSTR_LIST(remoteseltemp, F("remoteseltemp"), F("temporary set temperature from remote"))
MAKE_PSTR_LIST(comforttemp, F("comforttemp"), F("comfort temperature"))
MAKE_PSTR_LIST(summertemp, F("summertemp"), F("summer temperature"))
MAKE_PSTR_LIST(designtemp, F("designtemp"), F("design temperature"))
@@ -646,8 +692,11 @@ MAKE_PSTR_LIST(targetflowtemp, F("targetflowtemp"), F("target flow temperature")
MAKE_PSTR_LIST(heatingtype, F("heatingtype"), F("heating type"))
MAKE_PSTR_LIST(summersetmode, F("summersetmode"), F("set summer mode"))
MAKE_PSTR_LIST(hpoperatingmode, F("hpoperatingmode"), F("heatpump operating mode"))
MAKE_PSTR_LIST(hpoperatingstate, F("hpoperatingstate"), F("heatpump operating state"))
MAKE_PSTR_LIST(controlmode, F("controlmode"), F("control mode"))
MAKE_PSTR_LIST(control, F("control"), F("control device"))
MAKE_PSTR_LIST(wwHolidays, F("wwholidays"), F("holiday dates"))
MAKE_PSTR_LIST(wwVacations, F("wwvacations"), F("vacation dates"))
MAKE_PSTR_LIST(holidays, F("holidays"), F("holiday dates"))
MAKE_PSTR_LIST(vacations, F("vacations"), F("vacation dates"))
MAKE_PSTR_LIST(program, F("program"), F("program"))
@@ -664,9 +713,11 @@ MAKE_PSTR_LIST(reducetemp, F("reducetemp"), F("off/reduce switch temperature"))
MAKE_PSTR_LIST(vacreducetemp, F("vacreducetemp"), F("vacations off/reduce switch temperature"))
MAKE_PSTR_LIST(vacreducemode, F("vacreducemode"), F("vacations reduce mode"))
MAKE_PSTR_LIST(nofrostmode, F("nofrostmode"), F("nofrost mode"))
MAKE_PSTR_LIST(nofrostmode1, F("nofrostmode1"), F("nofrost mode")) // RC310
MAKE_PSTR_LIST(remotetemp, F("remotetemp"), F("room temperature from remote"))
MAKE_PSTR_LIST(reducehours, F("reducehours"), F("duration for nighttemp"))
MAKE_PSTR_LIST(reduceminutes, F("reduceminutes"), F("remaining time for nightmode"))
MAKE_PSTR_LIST(switchonoptimization, F("switchonoptimization"), F("switch-on optimization"))
// heatpump
MAKE_PSTR_LIST(airHumidity, F("airhumidity"), F("relative air humidity"))

View File

@@ -445,19 +445,17 @@ void Mqtt::start() {
}
connecting_ = false;
if (reason == AsyncMqttClientDisconnectReason::TCP_DISCONNECTED) {
LOG_INFO(F("MQTT disconnected: TCP"));
}
if (reason == AsyncMqttClientDisconnectReason::MQTT_IDENTIFIER_REJECTED) {
LOG_INFO(F("MQTT disconnected: Identifier Rejected"));
}
if (reason == AsyncMqttClientDisconnectReason::MQTT_SERVER_UNAVAILABLE) {
LOG_INFO(F("MQTT disconnected: Server unavailable"));
}
if (reason == AsyncMqttClientDisconnectReason::MQTT_MALFORMED_CREDENTIALS) {
LOG_INFO(F("MQTT disconnected: Malformed credentials"));
}
if (reason == AsyncMqttClientDisconnectReason::MQTT_NOT_AUTHORIZED) {
LOG_INFO(F("MQTT disconnected: Not authorized"));
LOG_WARNING(F("MQTT disconnected: TCP"));
} else if (reason == AsyncMqttClientDisconnectReason::MQTT_IDENTIFIER_REJECTED) {
LOG_WARNING(F("MQTT disconnected: Identifier Rejected"));
} else if (reason == AsyncMqttClientDisconnectReason::MQTT_SERVER_UNAVAILABLE) {
LOG_WARNING(F("MQTT disconnected: Server unavailable"));
} else if (reason == AsyncMqttClientDisconnectReason::MQTT_MALFORMED_CREDENTIALS) {
LOG_WARNING(F("MQTT disconnected: Malformed credentials"));
} else if (reason == AsyncMqttClientDisconnectReason::MQTT_NOT_AUTHORIZED) {
LOG_WARNING(F("MQTT disconnected: Not authorized"));
} else {
LOG_WARNING(F("MQTT disconnected: code %d"), reason);
}
});
@@ -628,10 +626,11 @@ void Mqtt::ha_status() {
doc["~"] = mqtt_base_; // default ems-esp
// doc["avty_t"] = FJSON("~/status"); // commented out, as it causes errors in HA sometimes
// doc["json_attr_t"] = FJSON("~/heartbeat"); // store also as HA attributes
doc["stat_t"] = FJSON("~/heartbeat");
doc["name"] = FJSON("EMS-ESP status");
doc["ic"] = F_(icondevice);
doc["val_tpl"] = FJSON("{{value_json['bus_status']}}");
doc["stat_t"] = FJSON("~/heartbeat");
doc["object_id"] = FJSON("ems_esp_status");
doc["name"] = FJSON("EMS-ESP status");
doc["ic"] = F_(icondevice);
doc["val_tpl"] = FJSON("{{value_json['bus_status']}}");
JsonObject dev = doc.createNestedObject("dev");
dev["name"] = F_(EMSESP); // "EMS-ESP"
@@ -1104,15 +1103,23 @@ void Mqtt::publish_ha_sensor_config(uint8_t type,
snprintf(stat_t, sizeof(stat_t), "~/%s", tag_to_topic(device_type, tag).c_str());
doc["stat_t"] = stat_t;
// name = <device> <tag> <name>
char new_name[80];
// friendly name = <tag> <name>
char short_name[70];
if (have_tag) {
snprintf(new_name, sizeof(new_name), "%s %s %s", device_name, EMSdevice::tag_to_string(tag).c_str(), read_flash_string(name).c_str());
snprintf(short_name, sizeof(short_name), "%s %s", EMSdevice::tag_to_string(tag).c_str(), read_flash_string(name).c_str());
} else {
snprintf(new_name, sizeof(new_name), "%s %s", device_name, read_flash_string(name).c_str());
snprintf(short_name, sizeof(short_name), "%s", read_flash_string(name).c_str());
}
new_name[0] = toupper(new_name[0]); // capitalize first letter
doc["name"] = new_name;
// entity id = emsesp_<device>_<tag>_<name>
char long_name[130];
snprintf(long_name, sizeof(long_name), "%s_%s", device_name, short_name);
// snprintf(long_name, sizeof(long_name), "emsesp_%s_%s", device_name, short_name); //wouldn't it be better?
doc["object_id"] = long_name;
// name (friendly name) = <tag> <name>
short_name[0] = toupper(short_name[0]); // capitalize first letter
doc["name"] = short_name;
// value template
// if its nested mqtt format then use the appended entity name, otherwise take the original
@@ -1240,7 +1247,8 @@ void Mqtt::publish_ha_climate_config(uint8_t tag, bool has_roomtemp, bool remove
char seltemp_s[30];
char currtemp_s[30];
char mode_str_tpl[400];
char name_s[30];
char name_s[10];
char id_s[20];
char uniq_id_s[30];
char temp_cmd_s[30];
char mode_cmd_s[30];
@@ -1279,7 +1287,8 @@ void Mqtt::publish_ha_climate_config(uint8_t tag, bool has_roomtemp, bool remove
hc_mode_s,
hc_mode_s);
snprintf(name_s, sizeof(name_s), "Thermostat hc%d", hc_num);
snprintf(id_s, sizeof(id_s), "thermostat_hc%d", hc_num);
snprintf(name_s, sizeof(name_s), "Hc%d", hc_num);
snprintf(uniq_id_s, sizeof(uniq_id_s), "thermostat_hc%d", hc_num);
snprintf(temp_cmd_s, sizeof(temp_cmd_s), "~/thermostat/hc%d/seltemp", hc_num);
snprintf(mode_cmd_s, sizeof(temp_cmd_s), "~/thermostat/hc%d/mode", hc_num);
@@ -1287,6 +1296,7 @@ void Mqtt::publish_ha_climate_config(uint8_t tag, bool has_roomtemp, bool remove
StaticJsonDocument<EMSESP_JSON_SIZE_HA_CONFIG> doc;
doc["~"] = base();
doc["object_id"] = id_s;
doc["name"] = name_s;
doc["uniq_id"] = uniq_id_s;
doc["mode_stat_t"] = topic_t;
@@ -1329,8 +1339,7 @@ std::string Mqtt::tag_to_topic(uint8_t device_type, uint8_t tag) {
}
// if there is a tag add it
if (!EMSdevice::tag_to_mqtt(tag).empty()
&& ((device_type == EMSdevice::DeviceType::BOILER && tag == DeviceValueTAG::TAG_DEVICE_DATA_WW) || (!is_nested() && tag >= DeviceValueTAG::TAG_HC1))) {
if (!EMSdevice::tag_to_mqtt(tag).empty() && ((tag == DeviceValueTAG::TAG_BOILER_DATA_WW) || (!is_nested() && tag >= DeviceValueTAG::TAG_HC1))) {
return EMSdevice::device_type_2_device_name(device_type) + "_data_" + EMSdevice::tag_to_mqtt(tag);
} else {
return EMSdevice::device_type_2_device_name(device_type) + "_data";

View File

@@ -57,7 +57,6 @@ void Shower::loop() {
// first check to see if hot water has been on long enough to be recognized as a Shower/Bath
if (!shower_state_ && (time_now - timer_start_) > SHOWER_MIN_DURATION) {
set_shower_state(true);
publish_shower_data();
LOG_DEBUG(F("[Shower] hot water still running, starting shower timer"));
}
// check if the shower has been on too long
@@ -78,7 +77,12 @@ void Shower::loop() {
if ((timer_pause_ - timer_start_) > SHOWER_OFFSET_TIME) {
duration_ = (timer_pause_ - timer_start_ - SHOWER_OFFSET_TIME);
if (duration_ > SHOWER_MIN_DURATION) {
publish_shower_data();
StaticJsonDocument<EMSESP_JSON_SIZE_SMALL> doc;
char s[50];
snprintf(s, 50, "%d minutes and %d seconds", (uint8_t)(duration_ / 60000), (uint8_t)((duration_ / 1000) % 60));
doc["duration"] = s;
Mqtt::publish(F("shower_data"), doc.as<JsonObject>());
LOG_DEBUG(F("[Shower] finished with duration %d"), duration_);
}
}
@@ -120,34 +124,6 @@ void Shower::shower_alert_start() {
}
}
// Publish to the shower_data topic
// showing whether the shower timer and alert are enabled or disabled
// and the duration of the last shower
void Shower::publish_shower_data() const {
StaticJsonDocument<EMSESP_JSON_SIZE_SMALL> doc;
if (EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE) {
doc["shower_timer"] = shower_timer_;
doc["shower_alert"] = shower_alert_;
} else if (EMSESP::system_.bool_format() == BOOL_FORMAT_10) {
doc["shower_timer"] = shower_timer_ ? 1 : 0;
doc["shower_alert"] = shower_alert_ ? 1 : 0;
} else {
char result[10];
doc["shower_timer"] = Helpers::render_boolean(result, shower_timer_);
doc["shower_alert"] = Helpers::render_boolean(result, shower_alert_);
}
// only publish shower duration if there is a value
if (duration_ > SHOWER_MIN_DURATION) {
char s[50];
snprintf(s, 50, "%d minutes and %d seconds", (uint8_t)(duration_ / 60000), (uint8_t)((duration_ / 1000) % 60));
doc["duration"] = s;
}
Mqtt::publish(F("shower_data"), doc.as<JsonObject>());
}
// send status of shower to MQTT topic called shower_active - which is determined by the state parameter
// and creates the HA config topic if HA enabled
// force is used by EMSESP::publish_all_loop()

View File

@@ -30,25 +30,6 @@ class Shower {
void set_shower_state(bool state, bool force = false);
/* unused header
*
bool shower_alert() const {
return shower_alert_;
}
void shower_alert(const bool shower_alert) {
shower_alert_ = shower_alert;
}
bool shower_timer() const {
return shower_timer_;
}
void shower_timer(const bool shower_timer) {
shower_timer_ = shower_timer;
}
*/
private:
static uuid::log::Logger logger_;
@@ -56,7 +37,6 @@ class Shower {
static constexpr uint32_t SHOWER_MIN_DURATION = 120000; // in ms. 2 minutes, before recognizing its a shower
static constexpr uint32_t SHOWER_OFFSET_TIME = 5000; // in ms. 5 seconds grace time, to calibrate actual time under the shower
void publish_shower_data() const;
void shower_alert_start();
void shower_alert_stop();

View File

@@ -245,7 +245,7 @@ void System::format(uuid::console::Shell & shell) {
EMSuart::stop();
#ifndef EMSESP_STANDALONE
LITTLEFS.format();
LittleFS.format();
#endif
System::system_restart();
@@ -433,7 +433,7 @@ void System::button_OnVLongPress(PButton & b) {
EMSESP::console_.loop();
#ifdef EMSESP_DEBUG
Test::listDir(LITTLEFS, FS_CONFIG_DIRECTORY, 3);
Test::listDir(LittleFS, FS_CONFIG_DIRECTORY, 3);
#endif
EMSESP::esp8266React.factoryReset();
@@ -895,7 +895,7 @@ bool System::check_upgrade() {
#ifndef EMSESP_STANDALONE
// see if we have a temp file, if so try and read it
File new_file = LITTLEFS.open(TEMP_FILENAME_PATH);
File new_file = LittleFS.open(TEMP_FILENAME_PATH);
if (new_file) {
DynamicJsonDocument jsonDocument = DynamicJsonDocument(FS_BUFFER_SIZE);
DeserializationError error = deserializeJson(jsonDocument, new_file);
@@ -923,7 +923,7 @@ bool System::check_upgrade() {
// close (just in case) and remove the temp file
new_file.close();
LITTLEFS.remove(TEMP_FILENAME_PATH);
LittleFS.remove(TEMP_FILENAME_PATH);
}
#endif
@@ -938,9 +938,9 @@ bool System::command_commands(const char * value, const int8_t id, JsonObject &
// convert settings file into json object
void System::extractSettings(const char * filename, const char * section, JsonObject & output) {
#ifndef EMSESP_STANDALONE
File settingsFile = LITTLEFS.open(filename);
File settingsFile = LittleFS.open(filename);
if (settingsFile) {
DynamicJsonDocument jsonDocument = DynamicJsonDocument(EMSESP_JSON_SIZE_XLARGE_DYN);
DynamicJsonDocument jsonDocument = DynamicJsonDocument(FS_BUFFER_SIZE);
DeserializationError error = deserializeJson(jsonDocument, settingsFile);
if (error == DeserializationError::Ok && jsonDocument.is<JsonObject>()) {
JsonObject jsonObject = jsonDocument.as<JsonObject>();
@@ -959,7 +959,7 @@ bool System::saveSettings(const char * filename, const char * section, JsonObjec
#ifndef EMSESP_STANDALONE
JsonObject section_json = input[section];
if (section_json) {
File section_file = LITTLEFS.open(filename, "w");
File section_file = LittleFS.open(filename, "w");
if (section_file) {
LOG_INFO(F("Applying new %s settings"), section);
serializeJson(section_json, section_file);

View File

@@ -77,6 +77,20 @@ class System {
bool heartbeat_json(JsonObject & output);
void send_heartbeat();
bool syslog_enabled() {
return syslog_enabled_;
}
#ifndef EMSESP_STANDALONE
unsigned long syslog_count() {
return syslog_.message_count();
}
unsigned long syslog_fails() {
return syslog_.message_fails();
}
#endif
void led_init(bool refresh);
void network_init(bool refresh);
void button_init(bool refresh);

View File

@@ -221,9 +221,6 @@ void RxService::add(uint8_t * data, uint8_t length) {
return;
}
// if we receive a hc2.. telegram from 0x19.. match it to master_thermostat if master is 0x18
src = EMSESP::check_master_device(src, type_id, true);
// create the telegram
auto telegram = std::make_shared<Telegram>(operation, src, dest, type_id, offset, message_data, message_length);
@@ -236,8 +233,8 @@ void RxService::add(uint8_t * data, uint8_t length) {
}
// add empty telegram to rx-queue
void RxService::add_empty(const uint8_t src, const uint8_t dest, const uint16_t type_id) {
auto telegram = std::make_shared<Telegram>(Telegram::Operation::RX, src, dest, type_id, 0, nullptr, 0);
void RxService::add_empty(const uint8_t src, const uint8_t dest, const uint16_t type_id, uint8_t offset) {
auto telegram = std::make_shared<Telegram>(Telegram::Operation::RX, src, dest, type_id, offset, nullptr, 0);
// only if queue is not full
if (rx_telegrams_.size() < MAX_RX_TELEGRAMS) {
rx_telegrams_.emplace_back(rx_telegram_id_++, std::move(telegram)); // add to queue
@@ -312,9 +309,6 @@ void TxService::send_telegram(const QueuedTxTelegram & tx_telegram) {
// fix the READ or WRITE depending on the operation
uint8_t dest = telegram->dest;
// check if we have to manipulate the id for thermostats > 0x18
dest = EMSESP::check_master_device(dest, telegram->type_id, false);
if (telegram->operation == Telegram::Operation::TX_READ) {
dest |= 0x80; // read has 8th bit set for the destination
}
@@ -591,20 +585,23 @@ void TxService::send_raw(const char * telegram_data) {
void TxService::retry_tx(const uint8_t operation, const uint8_t * data, const uint8_t length) {
// have we reached the limit? if so, reset count and give up
if (++retry_count_ > MAXIMUM_TX_RETRIES) {
reset_retry_count(); // give up
reset_retry_count(); // give up
EMSESP::wait_validate(0); // do not wait for validation
if (operation == Telegram::Operation::TX_READ) {
if (telegram_last_->offset > 0) { // ignore errors for higher offsets
LOG_DEBUG(F("Last Tx Read operation failed after %d retries. Ignoring request: %s"), MAXIMUM_TX_RETRIES, telegram_last_->to_string().c_str());
return;
}
increment_telegram_read_fail_count(); // another Tx fail
} else {
increment_telegram_write_fail_count(); // another Tx fail
}
EMSESP::wait_validate(0); // do not wait for validation
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,
telegram_last_->to_string().c_str());
if (operation == Telegram::Operation::TX_READ) {
EMSESP::rxservice_.add_empty(telegram_last_->dest, telegram_last_->src, telegram_last_->type_id);
EMSESP::rxservice_.add_empty(telegram_last_->dest, telegram_last_->src, telegram_last_->type_id, telegram_last_->offset);
}
return;
}

View File

@@ -231,7 +231,7 @@ class RxService : public EMSbus {
void loop();
void add(uint8_t * data, uint8_t length);
void add_empty(const uint8_t src, const uint8_t dst, const uint16_t type_id);
void add_empty(const uint8_t src, const uint8_t dst, const uint16_t type_id, uint8_t offset);
uint32_t telegram_count() const {
return telegram_count_;

View File

@@ -692,6 +692,27 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
EMSESP::mqtt_.incoming("ems-esp/boiler/wwseltemp", "59");
}
#if defined(EMSESP_STANDALONE)
// https://github.com/emsesp/EMS-ESP32/issues/541
if (command == "api_wwmode") {
shell.printfln(F("Testing API wwmode"));
Mqtt::ha_enabled(false);
Mqtt::nested_format(1);
run_test("310");
AsyncWebServerRequest request;
request.method(HTTP_POST);
DynamicJsonDocument doc(2000);
JsonVariant json;
char data[] = "{\"value\":\"off\"}";
deserializeJson(doc, data);
json = doc.as<JsonVariant>();
request.url("/api/thermostat/wwmode");
EMSESP::webAPIService.webAPIService_post(&request, json);
}
#endif
if (command == "api") {
shell.printfln(F("Testing API with MQTT and REST, standalone"));
@@ -1638,7 +1659,7 @@ void Test::debug(uuid::console::Shell & shell, const std::string & cmd) {
#ifndef EMSESP_STANDALONE
if (command == "ls") {
listDir(LITTLEFS, "/", 3);
listDir(LittleFS, "/", 3);
Serial.println();
}
#endif

View File

@@ -32,7 +32,7 @@ namespace emsesp {
// #define EMSESP_DEBUG_DEFAULT "web"
// #define EMSESP_DEBUG_DEFAULT "mqtt"
// #define EMSESP_DEBUG_DEFAULT "general"
// #define EMSESP_DEBUG_DEFAULT "boiler"
#define EMSESP_DEBUG_DEFAULT "boiler"
// #define EMSESP_DEBUG_DEFAULT "mqtt2"
// #define EMSESP_DEBUG_DEFAULT "mqtt_nested"
// #define EMSESP_DEBUG_DEFAULT "ha"
@@ -48,8 +48,9 @@ namespace emsesp {
// #define EMSESP_DEBUG_DEFAULT "2thermostats"
// #define EMSESP_DEBUG_DEFAULT "dallas"
// #define EMSESP_DEBUG_DEFAULT "analog"
#define EMSESP_DEBUG_DEFAULT "api_values"
// #define EMSESP_DEBUG_DEFAULT "api_values"
// #define EMSESP_DEBUG_DEFAULT "mqtt_post"
// #define EMSESP_DEBUG_DEFAULT "api_wwmode"
class Test {
public:

View File

@@ -20,127 +20,87 @@
* ESP32 UART port by @ArwedL and improved by @MichaelDvP. See https://github.com/emsesp/EMS-ESP/issues/380
*/
#if defined(ESP32)
#ifndef EMSESP_STANDALONE
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/uart.h"
#include "soc/uart_reg.h"
#include "uart/emsuart_esp32.h"
#include "emsesp.h"
namespace emsesp {
RingbufHandle_t buf_handle_ = NULL;
portMUX_TYPE mux_ = portMUX_INITIALIZER_UNLOCKED;
bool drop_next_rx_ = true;
uint8_t tx_mode_ = 0xFF;
static QueueHandle_t uart_queue;
uint8_t tx_mode_ = 0xFF;
/*
* Task to handle the incoming data
* receive task, wait for break and call incoming_telegram
*/
void EMSuart::emsuart_recvTask(void * para) {
while (1) {
size_t item_size;
uint8_t * telegram = (uint8_t *)xRingbufferReceive(buf_handle_, &item_size, portMAX_DELAY);
uint8_t telegramSize = item_size;
if (telegram) {
EMSESP::incoming_telegram(telegram, telegramSize);
vRingbufferReturnItem(buf_handle_, (void *)telegram);
}
}
}
void EMSuart::uart_event_task(void * pvParameters) {
uart_event_t event;
uint8_t telegram[EMS_MAXBUFFERSIZE];
uint8_t length = 0;
/*
* UART interrupt, on break read the fifo and put the whole telegram to ringbuffer
*/
void IRAM_ATTR EMSuart::emsuart_rx_intr_handler(void * para) {
portENTER_CRITICAL(&mux_);
if (EMS_UART.int_st.brk_det) {
EMS_UART.int_clr.brk_det = 1; // clear flag
uint8_t rxbuf[EMS_MAXBUFFERSIZE];
uint8_t length = 0;
while (EMS_UART.status.rxfifo_cnt) {
uint8_t rx = EMS_UART.fifo.rw_byte; // read all bytes from fifo
if (length < EMS_MAXBUFFERSIZE) {
if (length || rx) { // skip leading zero
rxbuf[length++] = rx;
while (1) {
//Waiting for UART event.
if (xQueueReceive(uart_queue, (void *)&event, portMAX_DELAY)) {
if (event.type == UART_DATA) {
length += event.size;
} else if (event.type == UART_BREAK) {
if (length == 2 || (length >= 6 && length <= EMS_MAXBUFFERSIZE)) {
uart_read_bytes(EMSUART_NUM, telegram, length, portMAX_DELAY);
// if (telegram[0] && !telegram[length - 1]) {
EMSESP::incoming_telegram(telegram, (uint8_t)(length - 1));
// }
} else {
// flush buffer up to break
uint8_t buf[length];
uart_read_bytes(EMSUART_NUM, buf, length, portMAX_DELAY);
}
} else {
drop_next_rx_ = true; // we have a overflow
length = 0;
} else if (event.type == UART_BUFFER_FULL) {
uart_flush_input(EMSUART_NUM);
length = 0;
}
}
if (length > 0 && length < EMS_MAXBUFFERSIZE) {
if (rxbuf[length - 1]) { // check if last byte is break
length++;
}
}
if ((!drop_next_rx_) && ((length == 2) || (length > 4))) {
int baseType = 0;
xRingbufferSendFromISR(buf_handle_, rxbuf, length - 1, &baseType);
}
drop_next_rx_ = false;
}
portEXIT_CRITICAL(&mux_);
vTaskDelete(NULL);
}
/*
* init UART driver
*/
void EMSuart::start(const uint8_t tx_mode, const uint8_t rx_gpio, const uint8_t tx_gpio) {
if (tx_mode_ != 0xFF) { // uart already initialized
tx_mode_ = tx_mode;
restart();
return;
if (tx_mode_ == 0xFF) {
uart_config_t uart_config = {
.baud_rate = EMSUART_BAUD,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.source_clk = UART_SCLK_APB,
};
uart_driver_install(EMSUART_NUM, 129, 0, (EMS_MAXBUFFERSIZE + 1) * 2, &uart_queue, 0); // buffer must be > fifo
uart_param_config(EMSUART_NUM, &uart_config);
uart_set_pin(EMSUART_NUM, tx_gpio, rx_gpio, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
uart_set_rx_full_threshold(EMSUART_NUM, 1);
uart_set_rx_timeout(EMSUART_NUM, 0); // disable
xTaskCreate(uart_event_task, "uart_event_task", 2048, NULL, configMAX_PRIORITIES - 1, NULL);
}
tx_mode_ = tx_mode;
portENTER_CRITICAL(&mux_);
uart_config_t uart_config = {
.baud_rate = EMSUART_BAUD,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
};
uart_param_config(EMSUART_UART, &uart_config);
uart_set_pin(EMSUART_UART, tx_gpio, rx_gpio, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
EMS_UART.int_ena.val = 0; // disable all intr.
EMS_UART.int_clr.val = 0xFFFFFFFF; // clear all intr. flags
EMS_UART.idle_conf.tx_brk_num = 10; // breaklength 10 bit
drop_next_rx_ = true;
// EMS_UART.idle_conf.rx_idle_thrhd = 256;
// EMS_UART.auto_baud.glitch_filt = 192;
#if (EMSUART_UART != UART_NUM_2)
EMS_UART.conf0.rxfifo_rst = 1; // flush fifos, remove for UART2
EMS_UART.conf0.txfifo_rst = 1;
#endif
buf_handle_ = xRingbufferCreate(128, RINGBUF_TYPE_NOSPLIT);
uart_isr_register(EMSUART_UART, emsuart_rx_intr_handler, NULL, ESP_INTR_FLAG_IRAM, NULL);
xTaskCreate(emsuart_recvTask, "emsuart_recvTask", 2048, NULL, configMAX_PRIORITIES - 3, NULL);
portEXIT_CRITICAL(&mux_);
restart();
uart_enable_intr_mask(EMSUART_NUM, UART_BRK_DET_INT_ENA | UART_RXFIFO_FULL_INT_ENA);
}
/*
* Stop, disable interrupt
*/
void EMSuart::stop() {
portENTER_CRITICAL(&mux_);
EMS_UART.int_ena.val = 0; // disable all intr.
portEXIT_CRITICAL(&mux_);
};
/*
* Restart uart and make mode dependent configs.
*/
void EMSuart::restart() {
portENTER_CRITICAL(&mux_);
if (EMS_UART.int_raw.brk_det) { // we received a break in the meantime
EMS_UART.int_clr.brk_det = 1; // clear flag
drop_next_rx_ = true; // and drop first frame
if (tx_mode_ != 0xFF) { // only call after driver initialisation
uart_disable_intr_mask(EMSUART_NUM, UART_BRK_DET_INT_ENA | UART_RXFIFO_FULL_INT_ENA);
}
EMS_UART.int_ena.brk_det = 1; // activate only break
EMS_UART.conf0.txd_brk = (tx_mode_ == EMS_TXMODE_HW) ? 1 : 0;
portEXIT_CRITICAL(&mux_);
}
};
/*
* Sends a 1-byte poll, ending with a <BRK>
@@ -164,52 +124,49 @@ uint16_t EMSuart::transmit(const uint8_t * buf, const uint8_t len) {
}
if (tx_mode_ == EMS_TXMODE_HW) { // hardware controlled mode
for (uint8_t i = 0; i < len; i++) {
EMS_UART.fifo.rw_byte = buf[i];
}
uart_write_bytes_with_break(EMSUART_NUM, buf, len, 10);
return EMS_TX_STATUS_OK;
}
if (tx_mode_ == EMS_TXMODE_EMSPLUS) { // EMS+ with long delay
for (uint8_t i = 0; i < len; i++) {
EMS_UART.fifo.rw_byte = buf[i];
uart_write_bytes(EMSUART_NUM, &buf[i], 1);
delayMicroseconds(EMSUART_TX_WAIT_PLUS);
}
EMS_UART.conf0.txd_inv = 1; // send <brk>
uart_set_line_inverse(EMSUART_NUM, UART_SIGNAL_TXD_INV);
delayMicroseconds(EMSUART_TX_BRK_PLUS);
EMS_UART.conf0.txd_inv = 0;
uart_set_line_inverse(EMSUART_NUM, 0);
return EMS_TX_STATUS_OK;
}
if (tx_mode_ == EMS_TXMODE_HT3) { // HT3 with 7 bittimes delay
for (uint8_t i = 0; i < len; i++) {
EMS_UART.fifo.rw_byte = buf[i];
uart_write_bytes(EMSUART_NUM, &buf[i], 1);
delayMicroseconds(EMSUART_TX_WAIT_HT3);
}
EMS_UART.conf0.txd_inv = 1; // send <brk>
uart_set_line_inverse(EMSUART_NUM, UART_SIGNAL_TXD_INV);
delayMicroseconds(EMSUART_TX_BRK_HT3);
EMS_UART.conf0.txd_inv = 0;
uart_set_line_inverse(EMSUART_NUM, 0);
return EMS_TX_STATUS_OK;
}
// mode 1: wait for echo after each byte
// flush fifos -- not supported in ESP32 uart #2!
// EMS_UART.conf0.rxfifo_rst = 1;
// EMS_UART.conf0.txfifo_rst = 1;
for (uint8_t i = 0; i < len; i++) {
volatile uint8_t _usrxc = EMS_UART.status.rxfifo_cnt;
EMS_UART.fifo.rw_byte = buf[i]; // send each Tx byte
uint16_t timeoutcnt = EMSUART_TX_TIMEOUT;
while ((EMS_UART.status.rxfifo_cnt == _usrxc) && (--timeoutcnt > 0)) {
size_t rx0, rx1;
uart_get_buffered_data_len(EMSUART_NUM, &rx0);
uart_write_bytes(EMSUART_NUM, &buf[i], 1);
uint16_t timeoutcnt = EMSUART_TX_TIMEOUT;
do {
delayMicroseconds(EMSUART_TX_BUSY_WAIT); // burn CPU cycles...
}
uart_get_buffered_data_len(EMSUART_NUM, &rx1);
} while ((rx1 == rx0) && (--timeoutcnt));
}
EMS_UART.conf0.txd_inv = 1;
uart_set_line_inverse(EMSUART_NUM, UART_SIGNAL_TXD_INV);
delayMicroseconds(EMSUART_TX_BRK_EMS);
EMS_UART.conf0.txd_inv = 0;
uart_set_line_inverse(EMSUART_NUM, 0);
return EMS_TX_STATUS_OK;
}
} // namespace emsesp
#endif
#endif

View File

@@ -20,25 +20,15 @@
/*
* ESP32 UART port by @ArwedL and improved by @MichaelDvP. See https://github.com/emsesp/EMS-ESP/issues/380
*/
#if defined(ESP32)
#ifndef EMSESP_EMSUART_H
#define EMSESP_EMSUART_H
#include <Arduino.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/ringbuf.h"
#include "freertos/queue.h"
#include <driver/uart.h>
#include <driver/timer.h>
#define EMS_MAXBUFFERSIZE 33 // max size of the buffer. EMS packets are max 32 bytes, plus extra for BRK
#define EMSUART_UART UART_NUM_2 // on the ESP32 we're using UART2
#define EMS_UART UART2 // for intr setting
#define EMSUART_BAUD 9600 // uart baud rate for the EMS circuit
#define EMSUART_NUM UART_NUM_2 // on the ESP32 we're using UART2
#define EMSUART UART2 // for intr setting
#define EMSUART_BAUD 9600 // uart baud rate for the EMS circuit
#define EMS_TXMODE_DEFAULT 1
#define EMS_TXMODE_EMSPLUS 2
@@ -78,12 +68,9 @@ class EMSuart {
static uint16_t transmit(const uint8_t * buf, const uint8_t len);
private:
static void emsuart_recvTask(void * para);
static void IRAM_ATTR emsuart_rx_intr_handler(void * para);
static void restart();
static void uart_event_task(void * pvParameters);
};
} // namespace emsesp
#endif
#endif

View File

@@ -1 +1 @@
#define EMSESP_APP_VERSION "3.4.1"
#define EMSESP_APP_VERSION "3.4.2"

View File

@@ -16,8 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// SUrlParser from https://github.com/Mad-ness/simple-url-parser
#include "emsesp.h"
using namespace std::placeholders; // for `_1` etc
@@ -158,7 +156,7 @@ void WebAPIService::parse(AsyncWebServerRequest * request, JsonObject & input) {
}
void WebAPIService::getSettings(AsyncWebServerRequest * request) {
auto * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_XLARGE_DYN);
auto * response = new AsyncJsonResponse(false, FS_BUFFER_SIZE);
JsonObject root = response->getRoot();
root["type"] = "settings";
@@ -179,7 +177,7 @@ void WebAPIService::getSettings(AsyncWebServerRequest * request) {
}
void WebAPIService::getCustomizations(AsyncWebServerRequest * request) {
auto * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_XLARGE_DYN);
auto * response = new AsyncJsonResponse(false, FS_BUFFER_SIZE);
JsonObject root = response->getRoot();
root["type"] = "customizations";

View File

@@ -148,7 +148,7 @@ StateUpdateResult WebCustomization::update(JsonObject & root, WebCustomization &
// deletes the customization file
void WebCustomizationService::reset_customization(AsyncWebServerRequest * request) {
#ifndef EMSESP_STANDALONE
if (LITTLEFS.remove(EMSESP_CUSTOMIZATION_FILE)) {
if (LittleFS.remove(EMSESP_CUSTOMIZATION_FILE)) {
AsyncWebServerResponse * response = request->beginResponse(200); // OK
request->send(response);
EMSESP::system_.restart_requested(true);
@@ -165,22 +165,27 @@ void WebCustomizationService::devices(AsyncWebServerRequest * request) {
auto * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_LARGE_DYN);
JsonObject root = response->getRoot();
// list is already sorted by device type
// controller is ignored since it doesn't have any associated entities
JsonArray devices = root.createNestedArray("devices");
for (const auto & emsdevice : EMSESP::emsdevices) {
if (emsdevice->has_entities()) {
JsonObject obj = devices.createNestedObject();
obj["i"] = emsdevice->unique_id(); // a unique id
obj["i"] = emsdevice->unique_id(); // its unique id
obj["s"] = emsdevice->device_type_name() + " (" + emsdevice->name() + ")"; // shortname
// device type name. We may have one than one (e.g. multiple thermostats) so postfix name with index
// code block not needed - see https://github.com/emsesp/EMS-ESP32/pull/586#issuecomment-1193779668
/*
uint8_t device_index = EMSESP::device_index(emsdevice->device_type(), emsdevice->unique_id());
if (device_index) {
char s[10];
obj["s"] = emsdevice->device_type_name() + Helpers::smallitoa(s, device_index) + " (" + emsdevice->name() + ")"; // shortname - we prefix the count to make it unique
obj["t"] = Helpers::toLower(emsdevice->device_type_name()) + Helpers::smallitoa(s, device_index);
} else {
obj["s"] = emsdevice->device_type_name() + " (" + emsdevice->name() + ")";
obj["t"] = Helpers::toLower(emsdevice->device_type_name());
}
*/
obj["s"] = emsdevice->device_type_name() + " (" + emsdevice->name() + ")";
obj["t"] = Helpers::toLower(emsdevice->device_type_name());
}
}

View File

@@ -74,10 +74,10 @@ void WebDataService::core_data(AsyncWebServerRequest * request) {
JsonObject root = response->getRoot();
// list is already sorted by device type
// Ignore Contoller
JsonArray devices = root.createNestedArray("devices");
char buffer[3];
for (const auto & emsdevice : EMSESP::emsdevices) {
// ignore controller
if (emsdevice && (emsdevice->device_type() != EMSdevice::DeviceType::CONTROLLER || emsdevice->count_entities() > 0)) {
JsonObject obj = devices.createNestedObject();
obj["id"] = Helpers::smallitoa(buffer, emsdevice->unique_id()); // a unique id as a string
@@ -94,6 +94,7 @@ void WebDataService::core_data(AsyncWebServerRequest * request) {
// sensors stuff
root["active_sensors"] = EMSESP::dallassensor_.no_sensors() + (EMSESP::analogsensor_.analog_enabled() ? EMSESP::analogsensor_.no_sensors() : 0);
root["analog_enabled"] = EMSESP::analogsensor_.analog_enabled();
root["connected"] = EMSESP::bus_status() != 2;
response->setLength();
request->send(response);

View File

@@ -45,7 +45,6 @@ void WebSettings::read(WebSettings & settings, JsonObject & root) {
root["syslog_mark_interval"] = settings.syslog_mark_interval;
root["syslog_host"] = settings.syslog_host;
root["syslog_port"] = settings.syslog_port;
root["master_thermostat"] = settings.master_thermostat;
root["shower_timer"] = settings.shower_timer;
root["shower_alert"] = settings.shower_alert;
root["shower_alert_coldshot"] = settings.shower_alert_coldshot;
@@ -108,10 +107,10 @@ StateUpdateResult WebSettings::update(JsonObject & root, WebSettings & settings)
check_flag(prev, settings.tx_mode, ChangeFlags::UART);
prev = settings.rx_gpio;
settings.rx_gpio = root["rx_gpio"] | default_rx_gpio;
check_flag(prev, settings.rx_gpio, ChangeFlags::UART);
check_flag(prev, settings.rx_gpio, ChangeFlags::RESTART);
prev = settings.tx_gpio;
settings.tx_gpio = root["tx_gpio"] | default_tx_gpio;
check_flag(prev, settings.tx_gpio, ChangeFlags::UART);
check_flag(prev, settings.tx_gpio, ChangeFlags::RESTART);
// syslog
prev = settings.syslog_enabled;
@@ -204,10 +203,6 @@ StateUpdateResult WebSettings::update(JsonObject & root, WebSettings & settings)
settings.low_clock = root["low_clock"] | false;
check_flag(prev, settings.low_clock, ChangeFlags::RESTART);
prev = settings.master_thermostat;
settings.master_thermostat = root["master_thermostat"] | EMSESP_DEFAULT_MASTER_THERMOSTAT;
check_flag(prev, settings.master_thermostat, ChangeFlags::RESTART);
//
// without checks...
//
@@ -279,6 +274,7 @@ void WebSettingsService::onUpdate() {
void WebSettingsService::begin() {
_fsPersistence.readFromFS();
WebSettings::reset_flags();
}
void WebSettingsService::save() {

View File

@@ -31,7 +31,6 @@ class WebSettings {
public:
uint8_t tx_mode;
uint8_t ems_bus_id;
uint8_t master_thermostat;
bool shower_timer;
bool shower_alert;
uint8_t shower_alert_trigger;

View File

@@ -33,25 +33,21 @@ WebStatusService::WebStatusService(AsyncWebServer * server, SecurityManager * se
// handles both WiFI and Ethernet
void WebStatusService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
switch (event) {
case SYSTEM_EVENT_STA_DISCONNECTED:
EMSESP::logger().info(F("WiFi disconnected. Reason code=%d"), info.disconnected.reason);
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
EMSESP::logger().warning(F("WiFi disconnected. Reason code=%d"), info.wifi_sta_disconnected.reason); // IDF 4.0
WiFi.disconnect(true);
break;
case SYSTEM_EVENT_STA_GOT_IP:
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
#ifndef EMSESP_STANDALONE
EMSESP::logger().info(F("WiFi connected with IP=%s, hostname=%s"), WiFi.localIP().toString().c_str(), WiFi.getHostname());
#endif
EMSESP::esp8266React.getNetworkSettingsService()->read([&](NetworkSettings & networkSettings) {
if (!networkSettings.enableIPv6) {
EMSESP::system_.send_heartbeat();
EMSESP::system_.syslog_init();
}
});
// EMSESP::system_.send_heartbeat(); // send from mqtt start
EMSESP::system_.syslog_init();
mDNS_start();
break;
case SYSTEM_EVENT_ETH_START:
case ARDUINO_EVENT_ETH_START:
// EMSESP::logger().info(F("Ethernet initialized"));
ETH.setHostname(EMSESP::system_.hostname().c_str());
@@ -64,35 +60,31 @@ void WebStatusService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
break;
case SYSTEM_EVENT_ETH_GOT_IP:
case ARDUINO_EVENT_ETH_GOT_IP:
// prevent double calls
if (!EMSESP::system_.ethernet_connected()) {
#ifndef EMSESP_STANDALONE
EMSESP::logger().info(F("Ethernet connected with IP=%s, speed %d Mbps"), ETH.localIP().toString().c_str(), ETH.linkSpeed());
#endif
EMSESP::esp8266React.getNetworkSettingsService()->read([&](NetworkSettings & networkSettings) {
if (!networkSettings.enableIPv6) {
EMSESP::system_.send_heartbeat();
EMSESP::system_.syslog_init();
}
});
// EMSESP::system_.send_heartbeat(); // send from mqtt start
EMSESP::system_.syslog_init();
EMSESP::system_.ethernet_connected(true);
mDNS_start();
}
break;
case SYSTEM_EVENT_ETH_DISCONNECTED:
EMSESP::logger().info(F("Ethernet disconnected"));
case ARDUINO_EVENT_ETH_DISCONNECTED:
EMSESP::logger().warning(F("Ethernet disconnected"));
EMSESP::system_.ethernet_connected(false);
break;
case SYSTEM_EVENT_ETH_STOP:
case ARDUINO_EVENT_ETH_STOP:
EMSESP::logger().info(F("Ethernet stopped"));
EMSESP::system_.ethernet_connected(false);
break;
#ifndef EMSESP_STANDALONE
case SYSTEM_EVENT_STA_CONNECTED:
case ARDUINO_EVENT_WIFI_STA_CONNECTED:
EMSESP::esp8266React.getNetworkSettingsService()->read([&](NetworkSettings & networkSettings) {
if (networkSettings.enableIPv6) {
WiFi.enableIpV6();
@@ -100,7 +92,7 @@ void WebStatusService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
});
break;
case SYSTEM_EVENT_ETH_CONNECTED:
case ARDUINO_EVENT_ETH_CONNECTED:
EMSESP::esp8266React.getNetworkSettingsService()->read([&](NetworkSettings & networkSettings) {
if (networkSettings.enableIPv6) {
ETH.enableIpV6();
@@ -108,13 +100,14 @@ void WebStatusService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
});
break;
case SYSTEM_EVENT_GOT_IP6:
case ARDUINO_EVENT_WIFI_STA_GOT_IP6:
case ARDUINO_EVENT_ETH_GOT_IP6:
if (EMSESP::system_.ethernet_connected()) {
EMSESP::logger().info(F("Ethernet connected with IP=%s, speed %d Mbps"), ETH.localIPv6().toString().c_str(), ETH.linkSpeed());
EMSESP::logger().info(F("Ethernet connected with IPv6=%s, speed %d Mbps"), ETH.localIPv6().toString().c_str(), ETH.linkSpeed());
} else {
EMSESP::logger().info(F("WiFi connected with IP=%s, hostname=%s"), WiFi.localIPv6().toString().c_str(), WiFi.getHostname());
EMSESP::logger().info(F("WiFi connected with IPv6=%s, hostname=%s"), WiFi.localIPv6().toString().c_str(), WiFi.getHostname());
}
EMSESP::system_.send_heartbeat();
// EMSESP::system_.send_heartbeat(); // send from mqtt start
EMSESP::system_.syslog_init();
mDNS_start();
break;
@@ -157,29 +150,46 @@ void WebStatusService::webStatusService(AsyncWebServerRequest * request) {
statJson["f"] = EMSESP::txservice_.telegram_write_fail_count();
statJson["q"] = EMSESP::txservice_.write_quality();
statJson = statsJson.createNestedObject();
statJson["id"] = "Temperature Sensor Reads";
statJson["s"] = EMSESP::dallassensor_.reads();
statJson["f"] = EMSESP::dallassensor_.fails();
statJson["q"] = EMSESP::dallassensor_.reads() == 0 ? 100 : 100 - (uint8_t)((100 * EMSESP::dallassensor_.fails()) / EMSESP::dallassensor_.reads());
statJson = statsJson.createNestedObject();
statJson["id"] = "Analog Sensor Reads";
statJson["s"] = EMSESP::analogsensor_.reads();
statJson["f"] = EMSESP::analogsensor_.fails();
statJson["q"] = EMSESP::analogsensor_.reads() == 0 ? 100 : 100 - (uint8_t)((100 * EMSESP::analogsensor_.fails()) / EMSESP::analogsensor_.reads());
statJson = statsJson.createNestedObject();
statJson["id"] = "MQTT Publishes";
statJson["s"] = Mqtt::publish_count();
statJson["f"] = Mqtt::publish_fails();
statJson["q"] = Mqtt::publish_count() == 0 ? 100 : 100 - (Mqtt::publish_fails() * 100) / (Mqtt::publish_count() + Mqtt::publish_fails());
if (EMSESP::dallassensor_.dallas_enabled()) {
statJson = statsJson.createNestedObject();
statJson["id"] = "Temperature Sensor Reads";
statJson["s"] = EMSESP::dallassensor_.reads();
statJson["f"] = EMSESP::dallassensor_.fails();
statJson["q"] = EMSESP::dallassensor_.reads() == 0 ? 100 : 100 - (uint8_t)((100 * EMSESP::dallassensor_.fails()) / EMSESP::dallassensor_.reads());
}
if (EMSESP::analog_enabled()) {
statJson = statsJson.createNestedObject();
statJson["id"] = "Analog Sensor Reads";
statJson["s"] = EMSESP::analogsensor_.reads();
statJson["f"] = EMSESP::analogsensor_.fails();
statJson["q"] = EMSESP::analogsensor_.reads() == 0 ? 100 : 100 - (uint8_t)((100 * EMSESP::analogsensor_.fails()) / EMSESP::analogsensor_.reads());
}
if (Mqtt::enabled()) {
statJson = statsJson.createNestedObject();
statJson["id"] = "MQTT Publishes";
statJson["s"] = Mqtt::publish_count();
statJson["f"] = Mqtt::publish_fails();
statJson["q"] = Mqtt::publish_count() == 0 ? 100 : 100 - (uint8_t)((100 * Mqtt::publish_fails()) / (Mqtt::publish_count() + Mqtt::publish_fails()));
}
statJson = statsJson.createNestedObject();
statJson["id"] = "API Calls";
statJson["s"] = WebAPIService::api_count(); // + WebAPIService::api_fails();
statJson["f"] = WebAPIService::api_fails();
statJson["q"] = WebAPIService::api_count() == 0 ? 100 : 100 - (WebAPIService::api_fails() * 100) / (WebAPIService::api_count() + WebAPIService::api_fails());
statJson["q"] =
WebAPIService::api_count() == 0 ? 100 : 100 - (uint8_t)((100 * WebAPIService::api_fails()) / (WebAPIService::api_count() + WebAPIService::api_fails()));
#ifndef EMSESP_STANDALONE
if (EMSESP::system_.syslog_enabled()) {
statJson = statsJson.createNestedObject();
statJson["id"] = "Syslog Messages";
statJson["s"] = EMSESP::system_.syslog_count();
statJson["f"] = EMSESP::system_.syslog_fails();
statJson["q"] = EMSESP::system_.syslog_count() == 0
? 100
: 100 - (uint8_t)((100 * EMSESP::system_.syslog_fails()) / (EMSESP::system_.syslog_count() + EMSESP::system_.syslog_fails()));
}
#endif
response->setLength();
request->send(response);