v3.2.1 merged from dev

This commit is contained in:
proddy
2021-08-08 14:46:14 +02:00
16 changed files with 309 additions and 237 deletions

View File

@@ -5,6 +5,25 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
# [3.2.1] August 8 2021
## Added
- json body in API can now take device, name, cmd, hc and id
- added example of how to use API directly to control values from Home Assistant
- API calls are shown in debug log (For troubleshooting)
## Fixed
- fixed issue with Home Assistant entity naming where boiler's ww was duplicated in entity name
- fixed issue where wwSetTemp was written too instead of wwSelTemp
## Changed
- fixed case on mqtt names, like 'wwtankmiddletemp'
- renamed Product ID to 'EMS Product ID' in Home Assistant
- removed brackets around tags, e.g. (hc1) selected room temperature" is now just "hc1 selected room temperature"
# [3.2.0] August 6 2021
## Added

View File

@@ -109,7 +109,7 @@ uint8_t Command::call(const uint8_t device_type, const char * cmd, const char *
// strip prefixes, check, and find command
Command::CmdFunction * Command::find_command(const uint8_t device_type, char * cmd, int8_t & id) {
// TODO special cases for id=0 and id=-1 will be removed in V3 API
// special cases for id=0 and id=-1 will be removed in V3 API
// no command for id0
if (id == 0) {
return nullptr;
@@ -126,7 +126,7 @@ Command::CmdFunction * Command::find_command(const uint8_t device_type, char * c
*p = tolower(*p);
}
// TODO hack for commands that could have hc or wwc prefixed. will be removed in new API V3 eventually
// hack for commands that could have hc or wwc prefixed. will be removed in new API V3 eventually
// scan for prefix hc.
for (uint8_t i = DeviceValueTAG::TAG_HC1; i <= DeviceValueTAG::TAG_HC4; i++) {
const char * tag = EMSdevice::tag_to_string(i).c_str();

View File

@@ -46,9 +46,11 @@ using uuid::log::Level;
// clang-format off
// strings stored 32 bit aligned on ESP8266/ESP32
#define MAKE_STR(string_name, string_literal) static constexpr const char * __str__##string_name = string_literal;
#define MAKE_PSTR(string_name, string_literal) static const char __pstr__##string_name[] __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = string_literal;
#define MAKE_PSTR_WORD(string_name) MAKE_PSTR(string_name, #string_name)
#define F_(string_name) FPSTR(__pstr__##string_name)
#define FSTR_(string_name) __str__##string_name
#define MAKE_PSTR_LIST(list_name, ...) static const __FlashStringHelper * const __pstr__##list_name[] PROGMEM = {__VA_ARGS__, nullptr};
#define FL_(list_name) (__pstr__##list_name)
// clang-format on

View File

@@ -142,7 +142,6 @@ void DallasSensor::loop() {
if (sensor.id() == get_id(addr)) {
t += sensor.offset();
if (t != sensor.temperature_c) {
sensor.temperature_c = t;
changed_ |= true;
}
sensor.temperature_c = t;

View File

@@ -92,7 +92,7 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
// first commands
register_device_value(TAG_BOILER_DATA,
&wWTapActivated_,
&wwTapActivated_,
DeviceValueType::CMD,
FL_(enum_bool),
FL_(wwtapactivated),
@@ -187,55 +187,55 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
}
// warm water - boiler_data_ww topic
register_device_value(TAG_BOILER_DATA_WW, &wWSelTemp_, DeviceValueType::UINT, nullptr, FL_(wWSelTemp), DeviceValueUOM::DEGREES);
register_device_value(TAG_BOILER_DATA_WW, &wWSetTemp_, DeviceValueType::UINT, nullptr, FL_(wWSetTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_warmwater_temp));
register_device_value(TAG_BOILER_DATA_WW, &wWType_, DeviceValueType::ENUM, FL_(enum_flow), FL_(wWType), DeviceValueUOM::NONE);
register_device_value(TAG_BOILER_DATA_WW, &wwSelTemp_, DeviceValueType::UINT, nullptr, FL_(wwSelTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_warmwater_temp));
register_device_value(TAG_BOILER_DATA_WW, &wwSetTemp_, DeviceValueType::UINT, nullptr, FL_(wwSetTemp), DeviceValueUOM::DEGREES);
register_device_value(TAG_BOILER_DATA_WW, &wwType_, DeviceValueType::ENUM, FL_(enum_flow), FL_(wwType), DeviceValueUOM::NONE);
register_device_value(
TAG_BOILER_DATA_WW, &wWComfort_, DeviceValueType::ENUM, FL_(enum_comfort), FL_(wWComfort), DeviceValueUOM::LIST, MAKE_CF_CB(set_warmwater_mode));
TAG_BOILER_DATA_WW, &wwComfort_, DeviceValueType::ENUM, FL_(enum_comfort), FL_(wwComfort), DeviceValueUOM::LIST, MAKE_CF_CB(set_warmwater_mode));
register_device_value(
TAG_BOILER_DATA_WW, &wWFlowTempOffset_, DeviceValueType::UINT, nullptr, FL_(wWFlowTempOffset), DeviceValueUOM::NONE, MAKE_CF_CB(set_wWFlowTempOffset));
TAG_BOILER_DATA_WW, &wwFlowTempOffset_, DeviceValueType::UINT, nullptr, FL_(wwFlowTempOffset), DeviceValueUOM::NONE, MAKE_CF_CB(set_wWFlowTempOffset));
register_device_value(
TAG_BOILER_DATA_WW, &wWMaxPower_, DeviceValueType::UINT, nullptr, FL_(wWMaxPower), DeviceValueUOM::PERCENT, MAKE_CF_CB(set_warmwater_maxpower));
TAG_BOILER_DATA_WW, &wwMaxPower_, DeviceValueType::UINT, nullptr, FL_(wwMaxPower), DeviceValueUOM::PERCENT, MAKE_CF_CB(set_warmwater_maxpower));
register_device_value(
TAG_BOILER_DATA_WW, &wWCircPump_, DeviceValueType::BOOL, nullptr, FL_(wWCircPump), DeviceValueUOM::BOOLEAN, MAKE_CF_CB(set_warmwater_circulation_pump));
register_device_value(TAG_BOILER_DATA_WW, &wWChargeType_, DeviceValueType::ENUM, FL_(enum_charge), FL_(wWChargeType), DeviceValueUOM::LIST);
register_device_value(TAG_BOILER_DATA_WW, &wWHystOn_, DeviceValueType::INT, nullptr, FL_(wWHystOn), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_ww_hyst_on));
register_device_value(TAG_BOILER_DATA_WW, &wWHystOff_, DeviceValueType::INT, nullptr, FL_(wWHystOff), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_ww_hyst_off));
TAG_BOILER_DATA_WW, &wwCircPump_, DeviceValueType::BOOL, nullptr, FL_(wwCircPump), DeviceValueUOM::BOOLEAN, MAKE_CF_CB(set_warmwater_circulation_pump));
register_device_value(TAG_BOILER_DATA_WW, &wWChargeType_, DeviceValueType::ENUM, FL_(enum_charge), FL_(wwChargeType), DeviceValueUOM::LIST);
register_device_value(TAG_BOILER_DATA_WW, &wwHystOn_, DeviceValueType::INT, nullptr, FL_(wwHystOn), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_ww_hyst_on));
register_device_value(TAG_BOILER_DATA_WW, &wwHystOff_, DeviceValueType::INT, nullptr, FL_(wwHystOff), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_ww_hyst_off));
register_device_value(TAG_BOILER_DATA_WW,
&wWDisinfectionTemp_,
&wwDisinfectionTemp_,
DeviceValueType::UINT,
nullptr,
FL_(wWDisinfectionTemp),
FL_(wwDisinfectionTemp),
DeviceValueUOM::DEGREES,
MAKE_CF_CB(set_disinfect_temp));
register_device_value(TAG_BOILER_DATA_WW,
&wWCircMode_,
&wwCircMode_,
DeviceValueType::ENUM,
FL_(enum_freq),
FL_(wWCircMode),
FL_(wwCircMode),
DeviceValueUOM::LIST,
MAKE_CF_CB(set_warmwater_circulation_mode));
register_device_value(TAG_BOILER_DATA_WW, &wWCirc_, DeviceValueType::BOOL, nullptr, FL_(wWCirc), DeviceValueUOM::BOOLEAN, MAKE_CF_CB(set_warmwater_circulation));
register_device_value(TAG_BOILER_DATA_WW, &wWCurTemp_, DeviceValueType::USHORT, FL_(div10), FL_(wWCurTemp), DeviceValueUOM::DEGREES);
register_device_value(TAG_BOILER_DATA_WW, &wWCurTemp2_, DeviceValueType::USHORT, FL_(div10), FL_(wWCurTemp2), DeviceValueUOM::DEGREES);
register_device_value(TAG_BOILER_DATA_WW, &wWCurFlow_, DeviceValueType::UINT, FL_(div10), FL_(wWCurFlow), DeviceValueUOM::LMIN);
register_device_value(TAG_BOILER_DATA_WW, &wWStorageTemp1_, DeviceValueType::USHORT, FL_(div10), FL_(wWStorageTemp1), DeviceValueUOM::DEGREES);
register_device_value(TAG_BOILER_DATA_WW, &wWStorageTemp2_, DeviceValueType::USHORT, FL_(div10), FL_(wWStorageTemp2), DeviceValueUOM::DEGREES);
register_device_value(TAG_BOILER_DATA_WW, &wwCirc_, DeviceValueType::BOOL, nullptr, FL_(wwCirc), DeviceValueUOM::BOOLEAN, MAKE_CF_CB(set_warmwater_circulation));
register_device_value(TAG_BOILER_DATA_WW, &wwCurTemp_, DeviceValueType::USHORT, FL_(div10), FL_(wwCurTemp), DeviceValueUOM::DEGREES);
register_device_value(TAG_BOILER_DATA_WW, &wwCurTemp2_, DeviceValueType::USHORT, FL_(div10), FL_(wwCurTemp2), DeviceValueUOM::DEGREES);
register_device_value(TAG_BOILER_DATA_WW, &wwCurFlow_, DeviceValueType::UINT, FL_(div10), FL_(wwCurFlow), DeviceValueUOM::LMIN);
register_device_value(TAG_BOILER_DATA_WW, &wwStorageTemp1_, DeviceValueType::USHORT, FL_(div10), FL_(wwStorageTemp1), DeviceValueUOM::DEGREES);
register_device_value(TAG_BOILER_DATA_WW, &wwStorageTemp2_, DeviceValueType::USHORT, FL_(div10), FL_(wwStorageTemp2), DeviceValueUOM::DEGREES);
register_device_value(
TAG_BOILER_DATA_WW, &wWActivated_, DeviceValueType::BOOL, nullptr, FL_(wWActivated), DeviceValueUOM::BOOLEAN, MAKE_CF_CB(set_warmwater_activated));
register_device_value(TAG_BOILER_DATA_WW, &wWOneTime_, DeviceValueType::BOOL, nullptr, FL_(wWOneTime), DeviceValueUOM::BOOLEAN, MAKE_CF_CB(set_warmwater_onetime));
register_device_value(TAG_BOILER_DATA_WW, &wWDisinfecting_, DeviceValueType::BOOL, nullptr, FL_(wWDisinfecting), DeviceValueUOM::BOOLEAN);
register_device_value(TAG_BOILER_DATA_WW, &wWCharging_, DeviceValueType::BOOL, nullptr, FL_(wWCharging), DeviceValueUOM::BOOLEAN);
register_device_value(TAG_BOILER_DATA_WW, &wWRecharging_, DeviceValueType::BOOL, nullptr, FL_(wWRecharging), DeviceValueUOM::BOOLEAN);
register_device_value(TAG_BOILER_DATA_WW, &wWTempOK_, DeviceValueType::BOOL, nullptr, FL_(wWTempOK), DeviceValueUOM::BOOLEAN);
register_device_value(TAG_BOILER_DATA_WW, &wWActive_, DeviceValueType::BOOL, nullptr, FL_(wWActive), DeviceValueUOM::BOOLEAN);
register_device_value(TAG_BOILER_DATA_WW, &wWHeat_, DeviceValueType::BOOL, nullptr, FL_(wWHeat), DeviceValueUOM::BOOLEAN);
register_device_value(TAG_BOILER_DATA_WW, &wWSetPumpPower_, DeviceValueType::UINT, nullptr, FL_(wWSetPumpPower), DeviceValueUOM::PERCENT);
register_device_value(TAG_BOILER_DATA_WW, &mixerTemp_, DeviceValueType::USHORT, FL_(div10), FL_(mixerTemp), DeviceValueUOM::DEGREES);
register_device_value(TAG_BOILER_DATA_WW, &tankMiddleTemp_, DeviceValueType::USHORT, FL_(div10), FL_(tankMiddleTemp), DeviceValueUOM::DEGREES);
register_device_value(TAG_BOILER_DATA_WW, &wWStarts_, DeviceValueType::ULONG, nullptr, FL_(wWStarts), DeviceValueUOM::NUM);
register_device_value(TAG_BOILER_DATA_WW, &wWStarts2_, DeviceValueType::ULONG, nullptr, FL_(wWStarts2), DeviceValueUOM::NUM);
register_device_value(TAG_BOILER_DATA_WW, &wWWorkM_, DeviceValueType::TIME, nullptr, FL_(wWWorkM), DeviceValueUOM::MINUTES);
TAG_BOILER_DATA_WW, &wwActivated_, DeviceValueType::BOOL, nullptr, FL_(wwActivated), DeviceValueUOM::BOOLEAN, MAKE_CF_CB(set_warmwater_activated));
register_device_value(TAG_BOILER_DATA_WW, &wwOneTime_, DeviceValueType::BOOL, nullptr, FL_(wwOneTime), DeviceValueUOM::BOOLEAN, MAKE_CF_CB(set_warmwater_onetime));
register_device_value(TAG_BOILER_DATA_WW, &wwDisinfecting_, DeviceValueType::BOOL, nullptr, FL_(wwDisinfecting), DeviceValueUOM::BOOLEAN);
register_device_value(TAG_BOILER_DATA_WW, &wwCharging_, DeviceValueType::BOOL, nullptr, FL_(wwCharging), DeviceValueUOM::BOOLEAN);
register_device_value(TAG_BOILER_DATA_WW, &wwRecharging_, DeviceValueType::BOOL, nullptr, FL_(wwRecharging), DeviceValueUOM::BOOLEAN);
register_device_value(TAG_BOILER_DATA_WW, &wwTempOK_, DeviceValueType::BOOL, nullptr, FL_(wwTempOK), DeviceValueUOM::BOOLEAN);
register_device_value(TAG_BOILER_DATA_WW, &wwActive_, DeviceValueType::BOOL, nullptr, FL_(wwActive), DeviceValueUOM::BOOLEAN);
register_device_value(TAG_BOILER_DATA_WW, &wwHeat_, DeviceValueType::BOOL, nullptr, FL_(wwHeat), DeviceValueUOM::BOOLEAN);
register_device_value(TAG_BOILER_DATA_WW, &wwSetPumpPower_, DeviceValueType::UINT, nullptr, FL_(wwSetPumpPower), DeviceValueUOM::PERCENT);
register_device_value(TAG_BOILER_DATA_WW, &wwMixerTemp_, DeviceValueType::USHORT, FL_(div10), FL_(wwMixerTemp), DeviceValueUOM::DEGREES);
register_device_value(TAG_BOILER_DATA_WW, &wwTankMiddleTemp_, DeviceValueType::USHORT, FL_(div10), FL_(wwTankMiddleTemp), DeviceValueUOM::DEGREES);
register_device_value(TAG_BOILER_DATA_WW, &wWStarts_, DeviceValueType::ULONG, nullptr, FL_(wwStarts), DeviceValueUOM::NUM);
register_device_value(TAG_BOILER_DATA_WW, &wwStarts2_, DeviceValueType::ULONG, nullptr, FL_(wwStarts2), DeviceValueUOM::NUM);
register_device_value(TAG_BOILER_DATA_WW, &wwWorkM_, DeviceValueType::TIME, nullptr, FL_(wwWorkM), DeviceValueUOM::MINUTES);
// fetch some initial data
EMSESP::send_read_request(0x10,
@@ -259,7 +259,7 @@ bool Boiler::publish_ha_config() {
doc["stat_t"] = stat_t;
char name_s[40];
snprintf_P(name_s, sizeof(name_s), PSTR("* %s Product ID"), device_type_name().c_str());
snprintf(name_s, sizeof(name_s), FSTR_(productid_fmt), device_type_name().c_str());
doc["name"] = name_s;
doc["val_tpl"] = FJSON("{{value_json.id}}");
@@ -299,18 +299,18 @@ void Boiler::check_active(const bool force) {
}
// check if we can use tapactivated in flow systems
if ((wWType_ == 1) && !Helpers::hasValue(wWTapActivated_, EMS_VALUE_BOOL)) {
wWTapActivated_ = 1;
if ((wwType_ == 1) && !Helpers::hasValue(wwTapActivated_, EMS_VALUE_BOOL)) {
wwTapActivated_ = 1;
}
// check if tap water is active, bits 1 and 4 must be set
// also check if there is a flowsensor and flow-type
static bool flowsensor = false;
if (Helpers::hasValue(wWCurFlow_) && (wWCurFlow_ > 0) && (wWType_ == 1)) {
if (Helpers::hasValue(wwCurFlow_) && (wwCurFlow_ > 0) && (wwType_ == 1)) {
flowsensor = true;
}
if (flowsensor) {
b = ((wWCurFlow_ > 0) && ((boilerState_ & 0x0A) == 0x0A));
b = ((wwCurFlow_ > 0) && ((boilerState_ & 0x0A) == 0x0A));
} else {
b = ((boilerState_ & 0x0A) == 0x0A);
}
@@ -327,25 +327,25 @@ void Boiler::check_active(const bool force) {
// 0x33
void Boiler::process_UBAParameterWW(std::shared_ptr<const Telegram> telegram) {
// has_update(telegram->read_bitvalue(wwEquipt_,0,3)); // 8=boiler has ww
has_update(telegram->read_value(wWActivated_, 1)); // 0xFF means on
has_update(telegram->read_value(wWSelTemp_, 2));
has_update(telegram->read_value(wWHystOn_, 3)); // Hyst on (default -5)
has_update(telegram->read_value(wWHystOff_, 4)); // Hyst off (default -1)
has_update(telegram->read_value(wWFlowTempOffset_, 5)); // default 40
has_update(telegram->read_value(wWCircPump_, 6)); // 0xFF means on
has_update(telegram->read_value(wWCircMode_, 7)); // 1=1x3min 6=6x3min 7=continuous
has_update(telegram->read_value(wWDisinfectionTemp_, 8));
has_update(telegram->read_value(wwActivated_, 1)); // 0xFF means on
has_update(telegram->read_value(wwSelTemp_, 2));
has_update(telegram->read_value(wwHystOn_, 3)); // Hyst on (default -5)
has_update(telegram->read_value(wwHystOff_, 4)); // Hyst off (default -1)
has_update(telegram->read_value(wwFlowTempOffset_, 5)); // default 40
has_update(telegram->read_value(wwCircPump_, 6)); // 0xFF means on
has_update(telegram->read_value(wwCircMode_, 7)); // 1=1x3min 6=6x3min 7=continuous
has_update(telegram->read_value(wwDisinfectionTemp_, 8));
has_update(telegram->read_bitvalue(wWChargeType_, 10, 0)); // 0 = charge pump, 0xff = 3-way valve
telegram->read_value(wWComfort_, 9);
if (wWComfort_ == 0x00) {
wWComfort_ = 0; // Hot
} else if (wWComfort_ == 0xD8) {
wWComfort_ = 1; // Eco
} else if (wWComfort_ == 0xEC) {
wWComfort_ = 2; // Intelligent
telegram->read_value(wwComfort_, 9);
if (wwComfort_ == 0x00) {
wwComfort_ = 0; // Hot
} else if (wwComfort_ == 0xD8) {
wwComfort_ = 1; // Eco
} else if (wwComfort_ == 0xEC) {
wwComfort_ = 2; // Intelligent
} else {
wWComfort_ = EMS_VALUE_UINT_NOTSET;
wwComfort_ = EMS_VALUE_UINT_NOTSET;
}
}
@@ -361,13 +361,13 @@ void Boiler::process_UBAMonitorFast(std::shared_ptr<const Telegram> telegram) {
has_update(telegram->read_bitvalue(fanWork_, 7, 2));
has_update(telegram->read_bitvalue(ignWork_, 7, 3));
has_update(telegram->read_bitvalue(heatingPump_, 7, 5));
has_update(telegram->read_bitvalue(wWHeat_, 7, 6));
has_update(telegram->read_bitvalue(wWCirc_, 7, 7));
has_update(telegram->read_bitvalue(wwHeat_, 7, 6));
has_update(telegram->read_bitvalue(wwCirc_, 7, 7));
// warm water storage sensors (if present)
// wWStorageTemp2 is also used by some brands as the boiler temperature - see https://github.com/emsesp/EMS-ESP/issues/206
has_update(telegram->read_value(wWStorageTemp1_, 9)); // 0x8300 if not available
has_update(telegram->read_value(wWStorageTemp2_,
has_update(telegram->read_value(wwStorageTemp1_, 9)); // 0x8300 if not available
has_update(telegram->read_value(wwStorageTemp2_,
11)); // 0x8000 if not available - this is boiler temp
has_update(telegram->read_value(retTemp_, 13));
@@ -421,7 +421,7 @@ void Boiler::process_UBAParameters(std::shared_ptr<const Telegram> telegram) {
* Boiler(0x08) -> Me(0x0B), ?(0x26), data: 01 05 00 0F 00 1E 58 5A
*/
void Boiler::process_UBASettingsWW(std::shared_ptr<const Telegram> telegram) {
has_update(telegram->read_value(wWMaxPower_, 7));
has_update(telegram->read_value(wwMaxPower_, 7));
}
/*
@@ -430,21 +430,21 @@ void Boiler::process_UBASettingsWW(std::shared_ptr<const Telegram> telegram) {
* Boiler(0x08) -> Me(0x0B), UBAMonitorWW(0x34), data: 30 01 BA 7D 00 21 00 00 03 00 01 22 2B 00 19 5B
*/
void Boiler::process_UBAMonitorWW(std::shared_ptr<const Telegram> telegram) {
has_update(telegram->read_value(wWSetTemp_, 0));
has_update(telegram->read_value(wWCurTemp_, 1));
has_update(telegram->read_value(wWCurTemp2_, 3));
has_update(telegram->read_value(wwSetTemp_, 0)); // hot water temperature target
has_update(telegram->read_value(wwCurTemp_, 1));
has_update(telegram->read_value(wwCurTemp2_, 3));
has_update(telegram->read_value(wWType_, 8));
has_update(telegram->read_value(wWCurFlow_, 9));
has_update(telegram->read_value(wWWorkM_, 10, 3)); // force to 3 bytes
has_update(telegram->read_value(wwType_, 8));
has_update(telegram->read_value(wwCurFlow_, 9));
has_update(telegram->read_value(wwWorkM_, 10, 3)); // force to 3 bytes
has_update(telegram->read_value(wWStarts_, 13, 3)); // force to 3 bytes
has_update(telegram->read_bitvalue(wWOneTime_, 5, 1));
has_update(telegram->read_bitvalue(wWDisinfecting_, 5, 2));
has_update(telegram->read_bitvalue(wWCharging_, 5, 3));
has_update(telegram->read_bitvalue(wWRecharging_, 5, 4));
has_update(telegram->read_bitvalue(wWTempOK_, 5, 5));
has_update(telegram->read_bitvalue(wWActive_, 5, 6));
has_update(telegram->read_bitvalue(wwOneTime_, 5, 1));
has_update(telegram->read_bitvalue(wwDisinfecting_, 5, 2));
has_update(telegram->read_bitvalue(wwCharging_, 5, 3));
has_update(telegram->read_bitvalue(wwRecharging_, 5, 4));
has_update(telegram->read_bitvalue(wwTempOK_, 5, 5));
has_update(telegram->read_bitvalue(wwActive_, 5, 6));
}
/*
@@ -459,7 +459,7 @@ void Boiler::process_UBAMonitorFastPlus(std::shared_ptr<const Telegram> telegram
has_update(telegram->read_value(selFlowTemp_, 6));
has_update(telegram->read_bitvalue(burnGas_, 11, 0));
// has_update(telegram->read_bitvalue(heatingPump_, 11, 1)); // heating active? see SlowPlus
has_update(telegram->read_bitvalue(wWHeat_, 11, 2));
has_update(telegram->read_bitvalue(wwHeat_, 11, 2));
has_update(telegram->read_value(curBurnPow_, 10));
has_update(telegram->read_value(selBurnPow_, 9));
has_update(telegram->read_value(curFlowTemp_, 7));
@@ -526,7 +526,7 @@ void Boiler::process_UBAMonitorSlowPlus(std::shared_ptr<const Telegram> telegram
has_update(telegram->read_bitvalue(fanWork_, 2, 2));
has_update(telegram->read_bitvalue(ignWork_, 2, 3));
has_update(telegram->read_bitvalue(heatingPump_, 2, 5));
has_update(telegram->read_bitvalue(wWCirc_, 2, 7));
has_update(telegram->read_bitvalue(wwCirc_, 2, 7));
has_update(telegram->read_value(exhaustTemp_, 6));
has_update(telegram->read_value(burnStarts_, 10, 3)); // force to 3 bytes
has_update(telegram->read_value(burnWorkMin_, 13, 3)); // force to 3 bytes
@@ -559,36 +559,36 @@ void Boiler::process_UBAParametersPlus(std::shared_ptr<const Telegram> telegram)
// 0xEA
void Boiler::process_UBAParameterWWPlus(std::shared_ptr<const Telegram> telegram) {
has_update(telegram->read_value(wWActivated_, 5)); // 0x01 means on
has_update(telegram->read_value(wWCircPump_, 10)); // 0x01 means yes
has_update(telegram->read_value(wWCircMode_,
has_update(telegram->read_value(wwActivated_, 5)); // 0x01 means on
has_update(telegram->read_value(wwCircPump_, 10)); // 0x01 means yes
has_update(telegram->read_value(wwCircMode_,
11)); // 1=1x3min... 6=6x3min, 7=continuous
// has_update(telegram->read_value(wWDisinfectTemp_, 12)); // settings, status in E9
// has_update(telegram->read_value(wWSelTemp_, 6)); // settings, status in E9
has_update(telegram->read_value(wWHystOn_, 7));
has_update(telegram->read_value(wWHystOff_, 8));
has_update(telegram->read_value(wwHystOn_, 7));
has_update(telegram->read_value(wwHystOff_, 8));
}
// 0xE9 - WW monitor ems+
// e.g. 08 00 E9 00 37 01 F6 01 ED 00 00 00 00 41 3C 00 00 00 00 00 00 00 00 00 00 00 00 37 00 00 00 (CRC=77) #data=27
void Boiler::process_UBAMonitorWWPlus(std::shared_ptr<const Telegram> telegram) {
has_update(telegram->read_value(wWSetTemp_, 0));
has_update(telegram->read_value(wWCurTemp_, 1));
has_update(telegram->read_value(wWCurTemp2_, 3));
has_update(telegram->read_value(wwSetTemp_, 0));
has_update(telegram->read_value(wwCurTemp_, 1));
has_update(telegram->read_value(wwCurTemp2_, 3));
has_update(telegram->read_value(wWWorkM_, 14, 3)); // force to 3 bytes
has_update(telegram->read_value(wwWorkM_, 14, 3)); // force to 3 bytes
has_update(telegram->read_value(wWStarts_, 17, 3)); // force to 3 bytes
has_update(telegram->read_bitvalue(wWOneTime_, 12, 2));
has_update(telegram->read_bitvalue(wWDisinfecting_, 12, 3));
has_update(telegram->read_bitvalue(wWCharging_, 12, 4));
has_update(telegram->read_bitvalue(wWRecharging_, 13, 4));
has_update(telegram->read_bitvalue(wWTempOK_, 13, 5));
has_update(telegram->read_bitvalue(wWCirc_, 13, 2));
has_update(telegram->read_bitvalue(wwOneTime_, 12, 2));
has_update(telegram->read_bitvalue(wwDisinfecting_, 12, 3));
has_update(telegram->read_bitvalue(wwCharging_, 12, 4));
has_update(telegram->read_bitvalue(wwRecharging_, 13, 4));
has_update(telegram->read_bitvalue(wwTempOK_, 13, 5));
has_update(telegram->read_bitvalue(wwCirc_, 13, 2));
// has_update(telegram->read_value(wWActivated_, 20)); // Activated is in 0xEA, this is something other 0/100%
has_update(telegram->read_value(wWSelTemp_, 10));
has_update(telegram->read_value(wWDisinfectionTemp_, 9));
has_update(telegram->read_value(wwSelTemp_, 10));
has_update(telegram->read_value(wwDisinfectionTemp_, 9));
}
/*
@@ -608,7 +608,7 @@ void Boiler::process_UBAInformation(std::shared_ptr<const Telegram> telegram) {
has_update(telegram->read_value(heatingStarts_, 28));
has_update(telegram->read_value(coolingStarts_, 36));
has_update(telegram->read_value(wWStarts2_, 24));
has_update(telegram->read_value(wwStarts2_, 24));
has_update(telegram->read_value(nrgConsTotal_, 64));
@@ -660,8 +660,8 @@ void Boiler::process_HpOutdoor(std::shared_ptr<const Telegram> telegram) {
// e.g. 88 00 2A 00 00 00 00 00 00 00 00 00 D2 00 00 80 00 00 01 08 80 00 02 47 00
// see https://github.com/emsesp/EMS-ESP/issues/397
void Boiler::process_MC110Status(std::shared_ptr<const Telegram> telegram) {
has_update(telegram->read_value(mixerTemp_, 14));
has_update(telegram->read_value(tankMiddleTemp_, 18));
has_update(telegram->read_value(wwMixerTemp_, 14));
has_update(telegram->read_value(wwTankMiddleTemp_, 18));
}
/*
@@ -676,7 +676,7 @@ void Boiler::process_UBASetPoints(std::shared_ptr<const Telegram> telegram) {
has_update(telegram->read_value(setFlowTemp_,
0)); // boiler set temp from thermostat
has_update(telegram->read_value(setBurnPow_, 1)); // max json power in %
has_update(telegram->read_value(wWSetPumpPower_, 2)); // ww pump speed/power?
has_update(telegram->read_value(wwSetPumpPower_, 2)); // ww pump speed/power?
}
// 0x6DC, ff for cascaded heatsources (hs)
@@ -763,7 +763,7 @@ void Boiler::process_UBAMaintenanceData(std::shared_ptr<const Telegram> telegram
}
}
// Set the warm water temperature 0x33
// Set the warm water temperature 0x33/0x35 or 0xEA
bool Boiler::set_warmwater_temp(const char * value, const int8_t id) {
int v = 0;
if (!Helpers::value2number(value, v)) {
@@ -776,9 +776,8 @@ bool Boiler::set_warmwater_temp(const char * value, const int8_t id) {
write_command(EMS_TYPE_UBAParameterWWPlus, 6, v, EMS_TYPE_UBAParameterWWPlus);
} else {
// some boiler have it in 0x33, some in 0x35
write_command(EMS_TYPE_UBAFlags, 3, v, 0x34); // for i9000, see #397
write_command(EMS_TYPE_UBAParameterWW, 2, v,
EMS_TYPE_UBAParameterWW); // read seltemp back
write_command(EMS_TYPE_UBAFlags, 3, v, 0x34); // for i9000, see #397
write_command(EMS_TYPE_UBAParameterWW, 2, v, EMS_TYPE_UBAParameterWW); // read seltemp back
}
return true;
@@ -1147,11 +1146,11 @@ bool Boiler::set_tapwarmwater_activated(const char * value, const int8_t id) {
message_data[1] = 0x00; // burner output 0%
message_data[3] = 0x64; // boiler pump capacity 100%
message_data[4] = 0xFF; // 3-way valve hot water only
wWTapActivated_ = 0;
wwTapActivated_ = 0;
} else {
// get out of test mode. Send all zeros.
// telegram: 0B 08 1D 00 00
wWTapActivated_ = 1;
wwTapActivated_ = 1;
}
write_command(EMS_TYPE_UBAFunctionTest, 0, message_data, sizeof(message_data), 0);

View File

@@ -55,40 +55,39 @@ class Boiler : public EMSdevice {
static constexpr uint8_t EMS_BOILER_SELFLOWTEMP_HEATING = 20; // was originally 70, changed to 30 for issue #193, then to 20 with issue #344
// ww
uint8_t wWSetTemp_; // Warm Water set temperature
uint8_t wWSelTemp_; // Warm Water selected temperature
uint8_t wWType_; // 0-off, 1-flow, 2-flowbuffer, 3-buffer, 4-layered buffer
uint8_t wWComfort_; // WW comfort mode
uint8_t wWCircPump_; // Warm Water circulation pump available
uint8_t wwSetTemp_; // Warm Water set temperature
uint8_t wwSelTemp_; // Warm Water selected temperature
uint8_t wwType_; // 0-off, 1-flow, 2-flowbuffer, 3-buffer, 4-layered buffer
uint8_t wwComfort_; // WW comfort mode
uint8_t wwCircPump_; // Warm Water circulation pump available
uint8_t wWChargeType_; // Warm Water charge type (pump or 3-way-valve)
uint8_t wWDisinfectionTemp_; // Warm Water disinfection temperature to prevent infection
uint8_t wWCircMode_; // Warm Water circulation pump mode
uint8_t wWCirc_; // Circulation on/off
uint16_t wWCurTemp_; // Warm Water current temperature
uint16_t wWCurTemp2_; // Warm Water current temperature storage
uint8_t wWCurFlow_; // Warm Water current flow temp in l/min
uint16_t wWStorageTemp1_; // warm water storage temp 1
uint16_t wWStorageTemp2_; // warm water storage temp 2
uint8_t wWActivated_; // Warm Water activated
uint8_t wWOneTime_; // Warm Water one time function on/off
uint8_t wWDisinfecting_; // Warm Water disinfection on/off
uint8_t wWCharging_; // Warm Water charging on/off
uint8_t wWRecharging_; // Warm Water recharge on/off
uint8_t wWTempOK_; // Warm Water temperature ok on/off
uint8_t wWActive_; //
uint8_t wWHeat_; // 3-way valve on WW
uint8_t wWSetPumpPower_; // ww pump speed/power?
uint8_t wWFlowTempOffset_; // Boiler offset for ww heating
uint8_t wWMaxPower_; // Warm Water maximum power
uint8_t wwDisinfectionTemp_; // Warm Water disinfection temperature to prevent infection
uint8_t wwCircMode_; // Warm Water circulation pump mode
uint8_t wwCirc_; // Circulation on/off
uint16_t wwCurTemp_; // Warm Water current temperature
uint16_t wwCurTemp2_; // Warm Water current temperature storage
uint8_t wwCurFlow_; // Warm Water current flow temp in l/min
uint16_t wwStorageTemp1_; // warm water storage temp 1
uint16_t wwStorageTemp2_; // warm water storage temp 2
uint8_t wwActivated_; // Warm Water activated
uint8_t wwOneTime_; // Warm Water one time function on/off
uint8_t wwDisinfecting_; // Warm Water disinfection on/off
uint8_t wwCharging_; // Warm Water charging on/off
uint8_t wwRecharging_; // Warm Water recharge on/off
uint8_t wwTempOK_; // Warm Water temperature ok on/off
uint8_t wwActive_; //
uint8_t wwHeat_; // 3-way valve on WW
uint8_t wwSetPumpPower_; // ww pump speed/power?
uint8_t wwFlowTempOffset_; // Boiler offset for ww heating
uint8_t wwMaxPower_; // Warm Water maximum power
uint32_t wWStarts_; // Warm Water # starts
uint32_t wWStarts2_; // Warm water control starts
uint32_t wWWorkM_; // Warm Water # minutes
int8_t wWHystOn_;
int8_t wWHystOff_;
uint8_t wWTapActivated_; // maintenance-mode to switch DHW off
uint16_t mixerTemp_; // mixing temperature
uint16_t tankMiddleTemp_; // Tank middle temperature (TS3)
uint32_t wwStarts2_; // Warm water control starts
uint32_t wwWorkM_; // Warm Water # minutes
int8_t wwHystOn_;
int8_t wwHystOff_;
uint8_t wwTapActivated_; // maintenance-mode to switch DHW off
uint16_t wwMixerTemp_; // mixing temperature
uint16_t wwTankMiddleTemp_; // Tank middle temperature (TS3)
// main
uint8_t id_; // product id

View File

@@ -51,7 +51,7 @@ bool Heatpump::publish_ha_config() {
doc["stat_t"] = stat_t;
char name_s[40];
snprintf_P(name_s, sizeof(name_s), PSTR("* %s Product ID"), device_type_name().c_str());
snprintf(name_s, sizeof(name_s), FSTR_(productid_fmt), device_type_name().c_str());
doc["name"] = name_s;
doc["val_tpl"] = FJSON("{{value_json.id}}");

View File

@@ -193,7 +193,7 @@ bool Solar::publish_ha_config() {
doc["stat_t"] = stat_t;
char name_s[40];
snprintf_P(name_s, sizeof(name_s), PSTR("* %s Product ID"), device_type_name().c_str());
snprintf(name_s, sizeof(name_s), FSTR_(productid_fmt), device_type_name().c_str());
doc["name"] = name_s;
doc["val_tpl"] = FJSON("{{value_json.id}}");

View File

@@ -57,7 +57,7 @@ bool Switch::publish_ha_config() {
doc["stat_t"] = stat_t;
char name_s[40];
snprintf_P(name_s, sizeof(name_s), PSTR("* %s Product ID"), device_type_name().c_str());
snprintf_P(name_s, sizeof(name_s), FSTR_(productid_fmt), device_type_name().c_str());
doc["name"] = name_s;
doc["val_tpl"] = FJSON("{{value_json.id}}");

View File

@@ -204,7 +204,7 @@ bool Thermostat::publish_ha_config() {
doc["stat_t"] = stat_t;
char name_s[40];
snprintf_P(name_s, sizeof(name_s), PSTR("* %s Product ID"), device_type_name().c_str());
snprintf(name_s, sizeof(name_s), FSTR_(productid_fmt), device_type_name().c_str());
doc["name"] = name_s;
doc["val_tpl"] = FJSON("{{value_json.id}}");
@@ -2185,7 +2185,7 @@ void Thermostat::register_device_values() {
register_device_value(
TAG_THERMOSTAT_DATA, &wwSetTempLow_, DeviceValueType::UINT, nullptr, FL_(wwSetTempLow), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_wwtemplow));
register_device_value(
TAG_THERMOSTAT_DATA, &wwCircMode_, DeviceValueType::ENUM, FL_(enum_wwCircMode), FL_(wWCircMode), DeviceValueUOM::LIST, MAKE_CF_CB(set_wwcircmode));
TAG_THERMOSTAT_DATA, &wwCircMode_, DeviceValueType::ENUM, FL_(enum_wwCircMode), FL_(wwCircMode), DeviceValueUOM::LIST, MAKE_CF_CB(set_wwcircmode));
register_device_value(TAG_THERMOSTAT_DATA, &wwExtra1_, DeviceValueType::UINT, nullptr, FL_(wwExtra1), DeviceValueUOM::DEGREES);
register_device_value(TAG_THERMOSTAT_DATA, &wwExtra2_, DeviceValueType::UINT, nullptr, FL_(wwExtra2), DeviceValueUOM::DEGREES);
break;
@@ -2227,7 +2227,7 @@ void Thermostat::register_device_values() {
MAKE_CF_CB(set_building));
register_device_value(TAG_THERMOSTAT_DATA, &wwMode_, DeviceValueType::ENUM, FL_(enum_wwMode2), FL_(wwMode), DeviceValueUOM::LIST, MAKE_CF_CB(set_wwmode));
register_device_value(
TAG_THERMOSTAT_DATA, &wwCircMode_, DeviceValueType::ENUM, FL_(enum_wwCircMode2), FL_(wWCircMode), DeviceValueUOM::LIST, MAKE_CF_CB(set_wwcircmode));
TAG_THERMOSTAT_DATA, &wwCircMode_, DeviceValueType::ENUM, FL_(enum_wwCircMode2), FL_(wwCircMode), DeviceValueUOM::LIST, MAKE_CF_CB(set_wwcircmode));
break;
case EMS_DEVICE_FLAG_RC35:
register_device_value(TAG_THERMOSTAT_DATA, &dateTime_, DeviceValueType::TEXT, nullptr, FL_(dateTime), DeviceValueUOM::NONE, MAKE_CF_CB(set_datetime));
@@ -2257,7 +2257,7 @@ void Thermostat::register_device_values() {
MAKE_CF_CB(set_building));
register_device_value(TAG_THERMOSTAT_DATA, &wwMode_, DeviceValueType::ENUM, FL_(enum_wwMode2), FL_(wwMode), DeviceValueUOM::LIST, MAKE_CF_CB(set_wwmode));
register_device_value(
TAG_THERMOSTAT_DATA, &wwCircMode_, DeviceValueType::ENUM, FL_(enum_wwCircMode2), FL_(wWCircMode), DeviceValueUOM::LIST, MAKE_CF_CB(set_wwcircmode));
TAG_THERMOSTAT_DATA, &wwCircMode_, DeviceValueType::ENUM, FL_(enum_wwCircMode2), FL_(wwCircMode), DeviceValueUOM::LIST, MAKE_CF_CB(set_wwcircmode));
break;
case EMS_DEVICE_FLAG_JUNKERS:
register_device_value(TAG_THERMOSTAT_DATA, &dateTime_, DeviceValueType::TEXT, nullptr, FL_(dateTime), DeviceValueUOM::NONE, MAKE_CF_CB(set_datetime));

View File

@@ -627,12 +627,11 @@ void EMSdevice::generate_values_json_web(JsonObject & json) {
obj["u"] = dv.uom;
// add name, prefixing the tag if it exists
// except if it's a BOILER which uses a tag to split the MQTT topics
if ((dv.tag == DeviceValueTAG::TAG_NONE) || tag_to_string(dv.tag).empty() || device_type_ == DeviceType::BOILER) {
if ((dv.tag == DeviceValueTAG::TAG_NONE) || tag_to_string(dv.tag).empty()) {
obj["n"] = dv.full_name;
} else {
char name[50];
snprintf_P(name, sizeof(name), "(%s) %s", tag_to_string(dv.tag).c_str(), uuid::read_flash_string(dv.full_name).c_str());
snprintf_P(name, sizeof(name), "%s %s", tag_to_string(dv.tag).c_str(), uuid::read_flash_string(dv.full_name).c_str());
obj["n"] = name;
}
@@ -688,10 +687,10 @@ bool EMSdevice::get_value_info(JsonObject & root, const char * cmd, const int8_t
json["name"] = dv.short_name;
// prefix tag if it's included
if (dv.full_name != nullptr) {
if (dv.tag >= DeviceValueTAG::TAG_HC1) {
json["fullname"] = tag_to_string(dv.tag) + " " + uuid::read_flash_string(dv.full_name);
} else {
if ((dv.tag == DeviceValueTAG::TAG_NONE) || tag_to_string(dv.tag).empty()) {
json["fullname"] = dv.full_name;
} else {
json["fullname"] = tag_to_string(dv.tag) + " " + uuid::read_flash_string(dv.full_name);
}
}
@@ -850,13 +849,13 @@ bool EMSdevice::generate_values_json(JsonObject & root, const uint8_t tag_filter
if (((nested) || tag_filter == DeviceValueTAG::TAG_NONE || (tag_filter == dv.tag)) && (dv.full_name != nullptr || !console)
&& !(dv.full_name == nullptr && dv.has_cmd)) {
// we have a tag if it matches the filter given, and that the tag name is not empty/""
bool have_tag = ((dv.tag != tag_filter) && !tag_to_string(dv.tag).empty()) && (device_type_ != DeviceType::BOILER);
bool have_tag = ((dv.tag != tag_filter) && !tag_to_string(dv.tag).empty());
char name[80];
if (console) {
// prefix the tag in brackets, unless it's Boiler because we're naughty and use tag for the MQTT topic
if (have_tag) {
snprintf_P(name, 80, "(%s) %s", tag_to_string(dv.tag).c_str(), uuid::read_flash_string(dv.full_name).c_str());
snprintf_P(name, 80, "%s %s", tag_to_string(dv.tag).c_str(), uuid::read_flash_string(dv.full_name).c_str());
} else {
strcpy(name, uuid::read_flash_string(dv.full_name).c_str()); // use full name
}

View File

@@ -18,8 +18,6 @@
#pragma once
/* spell-checker: disable */
// common words
MAKE_PSTR_WORD(debug)
MAKE_PSTR_WORD(exit)
@@ -101,7 +99,6 @@ MAKE_PSTR_WORD(unknown)
MAKE_PSTR_WORD(Dallassensor)
// format strings
MAKE_PSTR(EMSESP, "EMS-ESP")
MAKE_PSTR(master_thermostat_fmt, "Master Thermostat Device ID: %s")
MAKE_PSTR(host_fmt, "Host: %s")
MAKE_PSTR(port_fmt, "Port: %d")
@@ -115,7 +112,10 @@ MAKE_PSTR(tx_mode_fmt, "Tx mode: %d")
MAKE_PSTR(bus_id_fmt, "Bus ID: %02X")
MAKE_PSTR(log_level_fmt, "Log level: %s")
MAKE_STR(productid_fmt, "%s EMS Product ID")
// strings
MAKE_PSTR(EMSESP, "EMS-ESP")
MAKE_PSTR(cmd_optional, "[cmd]")
MAKE_PSTR(ha_optional, "[ha]")
MAKE_PSTR(deep_optional, "[deep]")
@@ -437,38 +437,39 @@ MAKE_PSTR_LIST(hpTl2, F("hptl2"), F("air inlet temperature (TL2)"))
MAKE_PSTR_LIST(hpPl1, F("hppl1"), F("low pressure side temperature (PL1)"))
MAKE_PSTR_LIST(hpPh1, F("hpph1"), F("high pressure side temperature (PH1)"))
MAKE_PSTR_LIST(wWSelTemp, F("wwseltemp"), F("ww selected temperature"))
MAKE_PSTR_LIST(wWSetTemp, F("wwsettemp"), F("ww set temperature"))
MAKE_PSTR_LIST(wWType, F("wwtype"), F("ww type"))
MAKE_PSTR_LIST(wWComfort, F("wwcomfort"), F("ww comfort"))
MAKE_PSTR_LIST(wWFlowTempOffset, F("wwflowtempoffset"), F("ww flow temperature offset"))
MAKE_PSTR_LIST(wWMaxPower, F("wwmaxpower"), F("ww max power"))
MAKE_PSTR_LIST(wWCircPump, F("wwcircpump"), F("ww circulation pump available"))
MAKE_PSTR_LIST(wWChargeType, F("wwchargetype"), F("ww charging type"))
MAKE_PSTR_LIST(wWDisinfectionTemp, F("wwdisinfectiontemp"), F("ww disinfection temperature"))
MAKE_PSTR_LIST(wWCircMode, F("wwcircmode"), F("ww circulation pump frequency"))
MAKE_PSTR_LIST(wWCirc, F("wwcirc"), F("ww circulation active"))
MAKE_PSTR_LIST(wWCurTemp, F("wwcurtemp"), F("ww current intern temperature"))
MAKE_PSTR_LIST(wWCurTemp2, F("wwcurtemp2"), F("ww current extern temperature"))
MAKE_PSTR_LIST(wWCurFlow, F("wwcurflow"), F("ww current tap water flow"))
MAKE_PSTR_LIST(wWStorageTemp1, F("wwstoragetemp1"), F("ww storage intern temperature"))
MAKE_PSTR_LIST(wWStorageTemp2, F("wwstoragetemp2"), F("ww storage extern temperature"))
MAKE_PSTR_LIST(wWActivated, F("wwactivated"), F("ww activated"))
MAKE_PSTR_LIST(wWOneTime, F("wwonetime"), F("ww one time charging"))
MAKE_PSTR_LIST(wWDisinfecting, F("wwdisinfecting"), F("ww disinfecting"))
MAKE_PSTR_LIST(wWCharging, F("wwcharging"), F("ww charging"))
MAKE_PSTR_LIST(wWRecharging, F("wwrecharging"), F("ww recharging"))
MAKE_PSTR_LIST(wWTempOK, F("wwtempok"), F("ww temperature ok"))
MAKE_PSTR_LIST(wWActive, F("wwactive"), F("ww active"))
MAKE_PSTR_LIST(wWHeat, F("wwheat"), F("ww heating"))
MAKE_PSTR_LIST(wWSetPumpPower, F("wwsetpumppower"), F("ww set pump power"))
MAKE_PSTR_LIST(mixerTemp, F("mixertemp"), F("ww mixer temperature"))
MAKE_PSTR_LIST(tankMiddleTemp, F("tankmiddletemp"), F("ww tank middle temperature (TS3)"))
MAKE_PSTR_LIST(wWStarts, F("wwstarts"), F("ww # starts"))
MAKE_PSTR_LIST(wWStarts2, F("wwstarts2"), F("ww # control starts"))
MAKE_PSTR_LIST(wWWorkM, F("wwworkm"), F("ww active time"))
MAKE_PSTR_LIST(wWHystOn, F("wwhyston"), F("ww hysteresis on temperature"))
MAKE_PSTR_LIST(wWHystOff, F("wwhystoff"), F("ww hysteresis off temperature"))
// the following are warm water for the boiler and automatically tagged with 'ww'
MAKE_PSTR_LIST(wwSelTemp, F("wwseltemp"), F("selected temperature"))
MAKE_PSTR_LIST(wwSetTemp, F("wwsettemp"), F("set temperature"))
MAKE_PSTR_LIST(wwType, F("wwtype"), F("type"))
MAKE_PSTR_LIST(wwComfort, F("wwcomfort"), F("comfort"))
MAKE_PSTR_LIST(wwFlowTempOffset, F("wwflowtempoffset"), F("flow temperature offset"))
MAKE_PSTR_LIST(wwMaxPower, F("wwmaxpower"), F("max power"))
MAKE_PSTR_LIST(wwCircPump, F("wwcircpump"), F("circulation pump available"))
MAKE_PSTR_LIST(wwChargeType, F("wwchargetype"), F("charging type"))
MAKE_PSTR_LIST(wwDisinfectionTemp, F("wwdisinfectiontemp"), F("disinfection temperature"))
MAKE_PSTR_LIST(wwCircMode, F("wwcircmode"), F("circulation pump frequency"))
MAKE_PSTR_LIST(wwCirc, F("wwcirc"), F("circulation active"))
MAKE_PSTR_LIST(wwCurTemp, F("wwcurtemp"), F("current intern temperature"))
MAKE_PSTR_LIST(wwCurTemp2, F("wwcurtemp2"), F("current extern temperature"))
MAKE_PSTR_LIST(wwCurFlow, F("wwcurflow"), F("current tap water flow"))
MAKE_PSTR_LIST(wwStorageTemp1, F("wwstoragetemp1"), F("storage intern temperature"))
MAKE_PSTR_LIST(wwStorageTemp2, F("wwstoragetemp2"), F("storage extern temperature"))
MAKE_PSTR_LIST(wwActivated, F("wwactivated"), F("activated"))
MAKE_PSTR_LIST(wwOneTime, F("wwonetime"), F("one time charging"))
MAKE_PSTR_LIST(wwDisinfecting, F("wwdisinfecting"), F("disinfecting"))
MAKE_PSTR_LIST(wwCharging, F("wwcharging"), F("charging"))
MAKE_PSTR_LIST(wwRecharging, F("wwrecharging"), F("recharging"))
MAKE_PSTR_LIST(wwTempOK, F("wwtempok"), F("temperature ok"))
MAKE_PSTR_LIST(wwActive, F("wwactive"), F("active"))
MAKE_PSTR_LIST(wwHeat, F("wwheat"), F("heating"))
MAKE_PSTR_LIST(wwSetPumpPower, F("wwsetpumppower"), F("set pump power"))
MAKE_PSTR_LIST(wwMixerTemp, F("wwMixerTemp"), F("mixer temperature"))
MAKE_PSTR_LIST(wwTankMiddleTemp, F("wwtankmiddletemp"), F("tank middle temperature (TS3)"))
MAKE_PSTR_LIST(wwStarts, F("wwstarts"), F("# starts"))
MAKE_PSTR_LIST(wwStarts2, F("wwstarts2"), F("# control starts"))
MAKE_PSTR_LIST(wwWorkM, F("wwworkm"), F("active time"))
MAKE_PSTR_LIST(wwHystOn, F("wwhyston"), F("hysteresis on temperature"))
MAKE_PSTR_LIST(wwHystOff, F("wwhystoff"), F("hysteresis off temperature"))
// thermostat
// extra commands
@@ -493,11 +494,10 @@ MAKE_PSTR_LIST(dampedoutdoortemp, F("dampedoutdoortemp"), F("damped outdoor temp
MAKE_PSTR_LIST(floordrystatus, F("floordry"), F("floor drying"))
MAKE_PSTR_LIST(dampedoutdoortemp2, F("dampedoutdoortemp"), F("damped outdoor temperature"))
MAKE_PSTR_LIST(floordrytemp, F("floordrytemp"), F("floor drying temperature"))
MAKE_PSTR_LIST(wwMode, F("wwmode"), F("ww mode"))
MAKE_PSTR_LIST(wwSetTemp, F("wwsettemp"), F("ww set temperature"))
MAKE_PSTR_LIST(wwSetTempLow, F("wwsettemplow"), F("ww set low temperature"))
MAKE_PSTR_LIST(wwExtra1, F("wwextra1"), F("ww circuit 1 extra"))
MAKE_PSTR_LIST(wwExtra2, F("wwextra2"), F("ww circuit 2 extra"))
MAKE_PSTR_LIST(wwMode, F("wwmode"), F("mode"))
MAKE_PSTR_LIST(wwSetTempLow, F("wwsettemplow"), F("set low temperature"))
MAKE_PSTR_LIST(wwExtra1, F("wwextra1"), F("circuit 1 extra"))
MAKE_PSTR_LIST(wwExtra2, F("wwextra2"), F("circuit 2 extra"))
MAKE_PSTR_LIST(setpoint_roomTemp, F("seltemp"), F("selected room temperature"))
MAKE_PSTR_LIST(curr_roomTemp, F("currtemp"), F("current room temperature"))
MAKE_PSTR_LIST(mode, F("mode"), F("mode"))
@@ -545,7 +545,7 @@ MAKE_PSTR_LIST(mixerStatus, F("valvestatus"), F("mixing valve actuator in assign
MAKE_PSTR_LIST(flowTempVf, F("flowtempvf"), F("flow temperature in header (T0/Vf)"))
MAKE_PSTR_LIST(wwPumpStatus, F("pumpstatus"), F("pump status in assigned wwc (PC1)"))
MAKE_PSTR_LIST(wwTempStatus, F("wwtempstatus"), F("temperature switch in assigned wwc (MC1)"))
MAKE_PSTR_LIST(wwTemp, F("wwtemp"), F("ww current temperature"))
MAKE_PSTR_LIST(wwTemp, F("wwtemp"), F("current temperature"))
// solar
MAKE_PSTR_LIST(type, F("type"), F("type"))
@@ -566,13 +566,13 @@ MAKE_PSTR_LIST(pumpWorkTime, F("pumpworktime"), F("pump working time"))
MAKE_PSTR_LIST(energyLastHour, F("energylasthour"), F("energy last hour"))
MAKE_PSTR_LIST(energyTotal, F("energytotal"), F("energy total"))
MAKE_PSTR_LIST(energyToday, F("energytoday"), F("energy today"))
MAKE_PSTR_LIST(wwTemp1, F("wwtemp1"), F("ww temperature 1"))
MAKE_PSTR_LIST(wwTemp3, F("wwtemp3"), F("ww temperature 3"))
MAKE_PSTR_LIST(wwTemp4, F("wwtemp4"), F("ww temperature 4"))
MAKE_PSTR_LIST(wwTemp5, F("wwtemp5"), F("ww temperature 5"))
MAKE_PSTR_LIST(wwTemp7, F("wwtemp7"), F("ww temperature 7"))
MAKE_PSTR_LIST(wwPump, F("wwpump"), F("ww pump"))
MAKE_PSTR_LIST(wwMinTemp, F("wwmintemp"), F("ww minimum temperature"))
MAKE_PSTR_LIST(wwTemp1, F("wwtemp1"), F("temperature 1"))
MAKE_PSTR_LIST(wwTemp3, F("wwtemp3"), F("temperature 3"))
MAKE_PSTR_LIST(wwTemp4, F("wwtemp4"), F("temperature 4"))
MAKE_PSTR_LIST(wwTemp5, F("wwtemp5"), F("temperature 5"))
MAKE_PSTR_LIST(wwTemp7, F("wwtemp7"), F("temperature 7"))
MAKE_PSTR_LIST(wwPump, F("wwpump"), F("pump"))
MAKE_PSTR_LIST(wwMinTemp, F("wwmintemp"), F("minimum temperature"))
MAKE_PSTR_LIST(pumpMinMod, F("pumpminmod"), F("minimum pump modulation"))
MAKE_PSTR_LIST(maxFlow, F("maxflow"), F("maximum solar flow"))
MAKE_PSTR_LIST(solarPower, F("solarpower"), F("actual solar power"))

View File

@@ -151,6 +151,10 @@ class Mqtt {
return mqtt_enabled_;
}
static void enabled(bool mqtt_enabled) {
mqtt_enabled_ = mqtt_enabled;
}
static std::string base() {
return mqtt_base_;
}

View File

@@ -445,7 +445,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd) {
// Mqtt::nested_format(1);
Mqtt::nested_format(2);
// run_test("boiler");
run_test("boiler");
run_test("thermostat");
// run_test("solar");
// run_test("mixer");
@@ -933,6 +933,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd) {
#if defined(EMSESP_STANDALONE)
shell.printfln(F("Testing RESTful API..."));
Mqtt::ha_enabled(false);
Mqtt::enabled(false);
run_test("general");
AsyncWebServerRequest request;
@@ -950,11 +951,39 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd) {
request.url("/api/boiler/info");
EMSESP::webAPIService.webAPIService_get(&request);
request.url("/api/boiler/wwcurflow");
EMSESP::webAPIService.webAPIService_get(&request);
// POST
request.method(HTTP_POST);
request.url("/api/system/commands");
EMSESP::webAPIService.webAPIService_get(&request);
DynamicJsonDocument doc(2000);
JsonVariant json;
// 1
char data1[] = "{\"name\":\"temp\",\"value\":11}";
deserializeJson(doc, data1);
json = doc.as<JsonVariant>();
request.url("/api/thermostat");
EMSESP::webAPIService.webAPIService_post(&request, json);
// 2
char data2[] = "{\"value\":12}";
deserializeJson(doc, data2);
json = doc.as<JsonVariant>();
request.url("/api/thermostat/temp");
EMSESP::webAPIService.webAPIService_post(&request, json);
// 3
char data3[] = "{\"device\":\"thermostat\", \"name\":\"temp\",\"value\":11}";
deserializeJson(doc, data3);
json = doc.as<JsonVariant>();
request.url("/api");
EMSESP::webAPIService.webAPIService_post(&request, json);
#endif
}

View File

@@ -1 +1 @@
#define EMSESP_APP_VERSION "3.2.0"
#define EMSESP_APP_VERSION "3.2.1"

View File

@@ -33,19 +33,21 @@ WebAPIService::WebAPIService(AsyncWebServer * server, SecurityManager * security
// GET /{device}
// GET /{device}/{name}
// GET /device={device}?cmd={name}?data={value}[?id={hc}
// GET /device={device}?cmd={name}?data={value}[?id={hc}]
void WebAPIService::webAPIService_get(AsyncWebServerRequest * request) {
std::string device("");
std::string cmd("");
// initialize parameters. These will be extracted from the URL
std::string device_s("");
std::string cmd_s("");
std::string value_s("");
int id = -1;
std::string value("");
parse(request, device, cmd, id, value); // pass it defaults
parse(request, device_s, cmd_s, id, value_s);
}
// For POSTS with an optional JSON body
// HTTP_POST | HTTP_PUT | HTTP_PATCH
// POST/PUT /{device}[/{hc}][/{name}]
// POST /{device}[/{hc|id}][/{name}]
// the body must have 'value'. Optional are device, name, hc and id
void WebAPIService::webAPIService_post(AsyncWebServerRequest * request, JsonVariant & json) {
// if no body then treat it as a secure GET
if (not json.is<JsonObject>()) {
@@ -53,13 +55,34 @@ void WebAPIService::webAPIService_post(AsyncWebServerRequest * request, JsonVari
return;
}
// extract values from the json
// these will be used as default values
// extract values from the json. these will be used as default values
auto && body = json.as<JsonObject>();
std::string device = body["name"].as<std::string>(); // note this was called device in the v2
std::string cmd = body["cmd"].as<std::string>();
int id = -1;
#if defined(EMSESP_STANDALONE)
Serial.println("webAPIService_post: ");
serializeJson(body, Serial);
Serial.println();
#endif
// make sure we have a value. There must always be a value
if (!body.containsKey(F_(value))) {
send_message_response(request, 400, "Problems parsing JSON, missing value"); // Bad Request
return;
}
std::string value_s = body["value"].as<std::string>(); // always convert value to string
std::string device_s = body["device"].as<std::string>();
// get the command. It can be either 'name' or 'cmd'
std::string cmd_s("");
if (body.containsKey("name")) {
cmd_s = body["name"].as<std::string>();
} else if (body.containsKey("cmd")) {
cmd_s = body["cmd"].as<std::string>();
}
// for id, it can be part of the hc or id keys in the json body
int id = -1;
if (body.containsKey("id")) {
id = body["id"];
} else if (body.containsKey("hc")) {
@@ -68,15 +91,8 @@ void WebAPIService::webAPIService_post(AsyncWebServerRequest * request, JsonVari
id = -1;
}
// make sure we have a value. There must always be a value
if (!body.containsKey(F_(value))) {
send_message_response(request, 400, "Problems parsing JSON"); // Bad Request
return;
}
std::string value = body["value"].as<std::string>(); // always convert value to string
// now parse the URL. The URL is always leading and will overwrite anything provided in the json body
parse(request, device, cmd, id, value); // pass it defaults
parse(request, device_s, cmd_s, id, value_s); // pass it defaults
}
// parse the URL looking for query or path parameters
@@ -97,7 +113,7 @@ void WebAPIService::parse(AsyncWebServerRequest * request, std::string & device_
uint8_t device_type;
int8_t id_n = -1; // default hc
// check for query parameters first
// check for query parameters first, the old style from v2
// /device={device}?cmd={name}?data={value}[?id={hc}
if (p.paths().size() == 0) {
// get the device
@@ -126,27 +142,31 @@ void WebAPIService::parse(AsyncWebServerRequest * request, std::string & device_
id_n = Helpers::atoint(request->getParam("hc")->value().c_str());
}
} else {
// parse paths and json data from the OpenAPI standard
// /{device}[/{hc}][/{name}]
// first param must be a valid device, which includes "system"
device_s = p.paths().front();
// parse paths and json data from the newer OpenAPI standard
// [/{device}][/{hc}][/{name}]
// all paths are optional. If not set then take the values from the json body (if available)
auto num_paths = p.paths().size();
if (num_paths == 1) {
// if there are no more paths parameters, default to 'info'
// cmd_s = "info_short";
// check empty command in Command::find_command and set the default there!
} else if (num_paths == 2) {
cmd_s = p.paths()[1];
} else if (num_paths > 2) {
// check in Command::find_command makes prefix to TAG
cmd_s = p.paths()[1] + "/" + p.paths()[2];
// see if we have a device in the path
size_t num_paths = p.paths().size();
if (num_paths) {
// assume the next path is the 'device'. Note this could also have the value of system.
device_s = p.paths().front();
if (num_paths == 2) {
// next path is the name or cmd
cmd_s = p.paths()[1];
} else if (num_paths > 2) {
// check in Command::find_command makes prefix to TAG
cmd_s = p.paths()[1] + "/" + p.paths()[2];
}
}
}
// now go and validate everything
// now go and verify the values
// device check
if (device_s.empty()) {
// see if we have a device embedded in the json body, then use that
send_message_response(request, 422, "Missing device"); // Unprocessable Entity
return;
}
@@ -231,6 +251,8 @@ void WebAPIService::send_message_response(AsyncWebServerRequest * request, uint1
response->setContentType("application/json");
request->send(response);
}
EMSESP::logger().debug(F("API returns, code: %d, message: %s"), error_code, error_message);
}
/**