diff --git a/src/command.cpp b/src/command.cpp index 5d2b163c9..4fe8496ed 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -302,8 +302,19 @@ uint8_t Command::call(const uint8_t device_type, const char * cmd, const char * auto dname = EMSdevice::device_type_2_device_name(device_type); uint8_t device_id = EMSESP::device_id_from_cmd(device_type, cmd, id); + uint8_t flag = 0; + uint8_t tag = id - 1 + DeviceValueTAG::TAG_HC1; + if (tag >= DeviceValueTAG::TAG_HC1 && tag <= DeviceValueTAG::TAG_HC8) { + flag = CommandFlag::MQTT_SUB_FLAG_HC; + } else if (tag >= DeviceValueTAG::TAG_DHW1 && tag <= DeviceValueTAG::TAG_DHW10) { + flag = CommandFlag::MQTT_SUB_FLAG_DHW; + } else if (tag >= DeviceValueTAG::TAG_HS1 && tag <= DeviceValueTAG::TAG_HS16) { + flag = CommandFlag::MQTT_SUB_FLAG_HS; + } else if (tag >= DeviceValueTAG::TAG_AHS1 && tag <= DeviceValueTAG::TAG_AHS1) { + flag = CommandFlag::MQTT_SUB_FLAG_AHS; + } // see if there is a command registered - auto cf = find_command(device_type, device_id, cmd); + auto cf = find_command(device_type, device_id, cmd, flag); // check if its a call to an end-point of a device // this is used to fetch the attributes of the device entity, or call a command directly @@ -370,9 +381,9 @@ uint8_t Command::call(const uint8_t device_type, const char * cmd, const char * // report back. If not OK show output from error, other return the HTTP code if (return_code != CommandRet::OK) { if ((value == nullptr) || (strlen(value) == 0)) { - LOG_ERROR("Command '%s' failed with error code %d", cmd, return_code); + LOG_ERROR("Command '%s' failed with error code %d", cmd, FL_(cmdRet)[return_code]); } else { - LOG_ERROR("Command '%s/%s' failed with error code %d", cmd, value, return_code); + LOG_ERROR("Command '%s/%s' failed with error code %c", cmd, value, return_code); } return message(return_code, "callback function failed", output); } @@ -382,7 +393,7 @@ uint8_t Command::call(const uint8_t device_type, const char * cmd, const char * // add a command to the list, which does not return json void Command::add(const uint8_t device_type, const uint8_t device_id, const char * cmd, const cmd_function_p cb, const char * const * description, uint8_t flags) { // if the command already exists for that device type don't add it - if (find_command(device_type, device_id, cmd) != nullptr) { + if (find_command(device_type, device_id, cmd, flags) != nullptr) { return; } @@ -403,7 +414,7 @@ void Command::add(const uint8_t device_type, const char * cmd, const cmd_functio // add a command to the list, which does return a json object as output void Command::add(const uint8_t device_type, const char * cmd, const cmd_json_function_p cb, const char * const * description, uint8_t flags) { // if the command already exists for that device type don't add it - if (find_command(device_type, 0, cmd) != nullptr) { + if (find_command(device_type, 0, cmd, flags) != nullptr) { return; } @@ -412,13 +423,14 @@ void Command::add(const uint8_t device_type, const char * cmd, const cmd_json_fu // see if a command exists for that device type // is not case sensitive -Command::CmdFunction * Command::find_command(const uint8_t device_type, const uint8_t device_id, const char * cmd) { +Command::CmdFunction * Command::find_command(const uint8_t device_type, const uint8_t device_id, const char * cmd, const uint8_t flag) { if ((cmd == nullptr) || (strlen(cmd) == 0) || (cmdfunctions_.empty())) { return nullptr; } for (auto & cf : cmdfunctions_) { - if (Helpers::toLower(cmd) == Helpers::toLower(cf.cmd_) && (cf.device_type_ == device_type) && (!device_id || cf.device_id_ == device_id)) { + if (Helpers::toLower(cmd) == Helpers::toLower(cf.cmd_) && (cf.device_type_ == device_type) && (!device_id || cf.device_id_ == device_id) + && (!(flag & 0x3F) || (flag & 0x3F) == (cf.flags_ & 0x3F))) { return &cf; } } @@ -536,6 +548,12 @@ void Command::show(uuid::console::Shell & shell, uint8_t device_type, bool verbo } else if (cf.has_flags(MQTT_SUB_FLAG_DHW)) { shell.print("[dhw.]"); i += 9; + } else if (cf.has_flags(MQTT_SUB_FLAG_AHS)) { + shell.print("[ahs.]"); + i += 9; + } else if (cf.has_flags(MQTT_SUB_FLAG_HS)) { + shell.print("[hs.]"); + i += 8; } shell.print(cl); // pad with spaces diff --git a/src/command.h b/src/command.h index 337179efc..7f6191ff2 100644 --- a/src/command.h +++ b/src/command.h @@ -34,8 +34,10 @@ enum CommandFlag : uint8_t { MQTT_SUB_FLAG_DEFAULT = 0, // 0 no flags set, always subscribe to MQTT MQTT_SUB_FLAG_HC = (1 << 0), // 1 TAG_HC1 - TAG_HC8 MQTT_SUB_FLAG_DHW = (1 << 1), // 2 TAG_DHW1 - TAG_DHW4 - HIDDEN = (1 << 3), // 8 do not show in API or Web - ADMIN_ONLY = (1 << 4) // 16 requires authentication + MQTT_SUB_FLAG_AHS = (1 << 2), // 4 TAG_DEVICE_DATA_AHS + MQTT_SUB_FLAG_HS = (1 << 3), // 8 TAG_DEVICE_DATA_HS + HIDDEN = (1 << 6), // 64 do not show in API or Web + ADMIN_ONLY = (1 << 7) // 128 requires authentication }; @@ -49,6 +51,8 @@ enum CommandRet : uint8_t { INVALID // 5 - invalid (tag) }; +MAKE_ENUM_FIXED(cmdRet, "fail", "ok", "not found", "error", "not allowed", "invalid") + using cmd_function_p = std::function; using cmd_json_function_p = std::function; @@ -123,7 +127,7 @@ class Command { uint8_t flags = CommandFlag::MQTT_SUB_FLAG_DEFAULT); static void show_all(uuid::console::Shell & shell); - static Command::CmdFunction * find_command(const uint8_t device_type, const uint8_t device_id, const char * cmd); + static Command::CmdFunction * find_command(const uint8_t device_type, const uint8_t device_id, const char * cmd, const uint8_t flag); static void erase_command(const uint8_t device_type, const char * cmd); static void show(uuid::console::Shell & shell, uint8_t device_type, bool verbose); diff --git a/src/devices/thermostat.cpp b/src/devices/thermostat.cpp index c85710b95..2658d4899 100644 --- a/src/devices/thermostat.cpp +++ b/src/devices/thermostat.cpp @@ -123,6 +123,7 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i register_telegram_type(curve_typeids[i], "RC30Temp", false, MAKE_PF_CB(process_RC30Temp)); register_telegram_type(timer_typeids[i], "RC30Timer", false, MAKE_PF_CB(process_RC35Timer)); } + register_telegram_type(0xA9, "RC30Vacation", true, MAKE_PF_CB(process_RC30Vacation)); register_telegram_type(EMS_TYPE_RC30wwSettings, "RC30WWSettings", true, MAKE_PF_CB(process_RC30wwSettings)); register_telegram_type(0x38, "WWTimer", true, MAKE_PF_CB(process_RC35wwTimer)); register_telegram_type(0x39, "WWCircTimer", true, MAKE_PF_CB(process_RC35wwTimer)); @@ -1514,7 +1515,29 @@ void Thermostat::process_RC35Timer(std::shared_ptr telegram) { } } -// process_RCTime - type 0x06 - date and time from a thermostat - 14 bytes long +// type 0x9A (HC1) +void Thermostat::process_RC30Vacation(std::shared_ptr telegram) { + auto hc = heating_circuit(0x9A - telegram->type_id + 1); + if (hc == nullptr) { + return; + } + + if (telegram->message_length + telegram->offset >= 7 && telegram->offset <= 1) { + char data[sizeof(hc->vacation)]; + snprintf(data, + sizeof(data), + "%02d.%02d.%04d-%02d.%02d.%04d", + telegram->message_data[1 - telegram->offset], + telegram->message_data[2 - telegram->offset], + telegram->message_data[3 - telegram->offset] + 2000, + telegram->message_data[4 - telegram->offset], + telegram->message_data[5 - telegram->offset], + telegram->message_data[7 - telegram->offset] + 2000); + has_update(hc->vacation, data, sizeof(hc->vacation)); + } +} + +// process_RCTime - type 0x06 - date and time from a thermostat - 12 or 15 bytes long void Thermostat::process_RCTime(std::shared_ptr telegram) { if (telegram->offset > 0 || telegram->message_length < 8) { return; @@ -1912,6 +1935,7 @@ bool Thermostat::set_remotehum(const char * value, const int8_t id) { Roomctrl::set_remotehum(Roomctrl::RC100H, hc->hc(), hc->remotehum); // RC100H return true; } + Roomctrl::set_remotehum(Roomctrl::RC100H, hc->hc(), EMS_VALUE_UINT8_NOTSET); // RC100H return false; } @@ -2044,7 +2068,7 @@ bool Thermostat::set_roomsensor(const char * value, const int8_t id) { // sets the thermostat ww working mode, where mode is a string, ems and ems+ bool Thermostat::set_wwmode(const char * value, const int8_t id) { - uint8_t dhw = id - DeviceValueTAG::TAG_DHW1; + uint8_t dhw = id2dhw(id); uint8_t set; if (model() == EMSdevice::EMS_DEVICE_FLAG_RC10) { @@ -2122,7 +2146,7 @@ bool Thermostat::set_wwtemplow(const char * value, const int8_t id) { // Set ww charge RC300, ems+ bool Thermostat::set_wwcharge(const char * value, const int8_t id) { - uint8_t dhw = id - DeviceValueTAG::TAG_DHW1; + uint8_t dhw = id2dhw(id); bool b; if (!Helpers::value2bool(value, b)) { return false; @@ -2139,7 +2163,7 @@ bool Thermostat::set_wwcharge(const char * value, const int8_t id) { // Set ww charge duration in steps of 15 min, ems+ bool Thermostat::set_wwchargeduration(const char * value, const int8_t id) { - uint8_t dhw = id - DeviceValueTAG::TAG_DHW1; + uint8_t dhw = id2dhw(id); int t; if (!Helpers::value2number(value, t)) { return false; @@ -2187,7 +2211,7 @@ bool Thermostat::set_cooling(const char * value, const int8_t id) { // sets the thermostat ww circulation working mode, where mode is a string bool Thermostat::set_wwcircmode(const char * value, const int8_t id) { - uint8_t dhw = id - DeviceValueTAG::TAG_DHW1; + uint8_t dhw = id2dhw(id); uint8_t set; if (isRC300() || (model() == EMSdevice::EMS_DEVICE_FLAG_RC100)) { @@ -2207,7 +2231,7 @@ bool Thermostat::set_wwcircmode(const char * value, const int8_t id) { } bool Thermostat::set_wwDailyHeating(const char * value, const int8_t id) { - uint8_t dhw = id - DeviceValueTAG::TAG_DHW1; + uint8_t dhw = id2dhw(id); bool b; if (!Helpers::value2bool(value, b)) { return false; @@ -2218,7 +2242,7 @@ bool Thermostat::set_wwDailyHeating(const char * value, const int8_t id) { } bool Thermostat::set_wwDailyHeatTime(const char * value, const int8_t id) { - uint8_t dhw = id - DeviceValueTAG::TAG_DHW1; + uint8_t dhw = id2dhw(id); int set; if (!Helpers::value2number(value, set)) { return false; @@ -2236,7 +2260,7 @@ bool Thermostat::set_wwDailyHeatTime(const char * value, const int8_t id) { } bool Thermostat::set_wwDisinfect(const char * value, const int8_t id) { - uint8_t dhw = id - DeviceValueTAG::TAG_DHW1; + uint8_t dhw = id2dhw(id); bool b; if (!Helpers::value2bool(value, b)) { return false; @@ -2254,7 +2278,7 @@ bool Thermostat::set_wwDisinfect(const char * value, const int8_t id) { } bool Thermostat::set_wwDisinfectDay(const char * value, const int8_t id) { - uint8_t dhw = id - DeviceValueTAG::TAG_DHW1; + uint8_t dhw = id2dhw(id); uint8_t set; if (!Helpers::value2enum(value, set, FL_(enum_dayOfWeek))) { return false; @@ -2272,7 +2296,7 @@ bool Thermostat::set_wwDisinfectDay(const char * value, const int8_t id) { } bool Thermostat::set_wwDisinfectHour(const char * value, const int8_t id) { - uint8_t dhw = id - DeviceValueTAG::TAG_DHW1; + uint8_t dhw = id2dhw(id); int set; if (isRC300() || (model() == EMSdevice::EMS_DEVICE_FLAG_RC100)) { if (!Helpers::value2number(value, set, 0, 1431)) { @@ -2410,6 +2434,10 @@ bool Thermostat::set_holiday(const char * value, const int8_t id, const bool vac if (data[0] > 31 || data[1] > 12 || data[3] > 31 || data[4] > 12) { return false; } + if (model() == EMSdevice::EMS_DEVICE_FLAG_RC30) { + write_command(0xA9 + hc->hc(), 1, data, 6, 0x9A + hc->hc()); + return true; + } if (!vacation || value[10] == '+') { // + for compatibility if (hc) { @@ -3241,7 +3269,7 @@ bool Thermostat::set_switchtime2(const char * value, const int8_t id) { } // sets a single switchtime in the thermostat dhw program for RC35 bool Thermostat::set_wwCircSwitchTime(const char * value, const int8_t id) { - auto dhw = dhw_circuit(255, id - DeviceValueTAG::TAG_DHW1 + 1); + auto dhw = dhw_circuit(255, id2dhw(id)); if (dhw == nullptr) { return false; } @@ -3258,7 +3286,7 @@ bool Thermostat::set_wwCircSwitchTime(const char * value, const int8_t id) { // sets a single switchtime in the thermostat circulation program for RC35 bool Thermostat::set_wwSwitchTime(const char * value, const int8_t id) { - auto dhw = dhw_circuit(255, id - DeviceValueTAG::TAG_DHW1 + 1); + auto dhw = dhw_circuit(255, id2dhw(id)); if (dhw != nullptr) { return false; } diff --git a/src/devices/thermostat.h b/src/devices/thermostat.h index 7f254d6c4..9ddf11b1e 100644 --- a/src/devices/thermostat.h +++ b/src/devices/thermostat.h @@ -213,9 +213,9 @@ class Thermostat : public EMSdevice { void register_device_values(); void register_device_values(uint8_t hc_num); - // specific thermostat characteristics, stripping the top 4 bits + // specific thermostat characteristics, stripping the top 2 bits inline uint8_t model() const { - return (flags() & 0x0F); + return (flags() & 0x3F); } // check to see if the thermostat is a hybrid of the R300 @@ -223,6 +223,10 @@ class Thermostat : public EMSdevice { return ((model() == EMSdevice::EMS_DEVICE_FLAG_RC300) || (model() == EMSdevice::EMS_DEVICE_FLAG_R3000) || (model() == EMSdevice::EMS_DEVICE_FLAG_BC400)); } + inline uint8_t id2dhw(const int8_t id) const { + return id - DeviceValueTAG::TAG_DHW1 + DeviceValueTAG::TAG_HC1 - 1; + } + // each thermostat has a list of heating controller type IDs for reading and writing std::vector monitor_typeids; std::vector set_typeids; @@ -398,6 +402,7 @@ class Thermostat : public EMSdevice { void process_RC35Monitor(std::shared_ptr telegram); void process_RC35Set(std::shared_ptr telegram); void process_RC35Timer(std::shared_ptr telegram); + void process_RC30Vacation(std::shared_ptr telegram); void process_RC30Monitor(std::shared_ptr telegram); void process_RC30Set(std::shared_ptr telegram); void process_RC30Temp(std::shared_ptr telegram); diff --git a/src/emsdevice.cpp b/src/emsdevice.cpp index 042e38170..ac57eaa62 100644 --- a/src/emsdevice.cpp +++ b/src/emsdevice.cpp @@ -600,6 +600,10 @@ void EMSdevice::add_device_value(uint8_t tag, // to b flags |= CommandFlag::MQTT_SUB_FLAG_HC; } else if (tag >= DeviceValueTAG::TAG_DHW1 && tag <= DeviceValueTAG::TAG_DHW10) { flags |= CommandFlag::MQTT_SUB_FLAG_DHW; + } else if (tag >= DeviceValueTAG::TAG_HS1 && tag <= DeviceValueTAG::TAG_HS16) { + flags |= CommandFlag::MQTT_SUB_FLAG_HS; + } else if (tag >= DeviceValueTAG::TAG_AHS1 && tag <= DeviceValueTAG::TAG_AHS1) { + flags |= CommandFlag::MQTT_SUB_FLAG_AHS; } // add the command to our library diff --git a/src/system.cpp b/src/system.cpp index c9d3aec35..2e5804b2e 100644 --- a/src/system.cpp +++ b/src/system.cpp @@ -256,7 +256,7 @@ bool System::command_watch(const char * value, const int8_t id) { } void System::store_nvs_values() { - if (Command::find_command(EMSdevice::DeviceType::BOILER, 0, "nompower") != nullptr) { + if (Command::find_command(EMSdevice::DeviceType::BOILER, 0, "nompower", 0) != nullptr) { Command::call(EMSdevice::DeviceType::BOILER, "nompower", "-1"); // trigger a write } EMSESP::analogsensor_.store_counters(); diff --git a/src/version.h b/src/version.h index 7c094b4f1..6af7173fc 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define EMSESP_APP_VERSION "3.7.0-dev.6" +#define EMSESP_APP_VERSION "3.7.0-dev.7"