diff --git a/esphome/components/duco/select/__init__.py b/esphome/components/duco/select/__init__.py index 3c14703cca47..d904b28302c0 100644 --- a/esphome/components/duco/select/__init__.py +++ b/esphome/components/duco/select/__init__.py @@ -25,23 +25,48 @@ "MAN3x3", ] +CONF_BYPASS_MODE = "bypass_mode" + +DUCO_BYPASS_MODE_OPTIONS = [ + "AUTO", + "CLOSED", + "OPEN", +] + duco_ns = cg.esphome_ns.namespace("duco") DucoSelect = duco_ns.class_("DucoSelect", cg.PollingComponent, select.Select) +DucoBypassModeSelect = duco_ns.class_( + "DucoBypassModeSelect", cg.PollingComponent, select.Select +) CONFIG_SCHEMA = cv.All( select.select_schema(DucoSelect) .extend(cv.COMPONENT_SCHEMA) .extend(cv.polling_component_schema("3s")) .extend(DUCO_COMPONENT_SCHEMA) - .extend({cv.GenerateID(): cv.declare_id(DucoSelect)}) + .extend( + { + cv.GenerateID(): cv.declare_id(DucoSelect), + cv.Optional(CONF_BYPASS_MODE): select.select_schema(DucoBypassModeSelect) + .extend(cv.COMPONENT_SCHEMA) + .extend(cv.polling_component_schema("60s")) + .extend({cv.GenerateID(): cv.declare_id(DucoBypassModeSelect)}), + } + ) ) async def to_code(config): + parent = await cg.get_variable(config[CONF_DUCO_ID]) + var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) - await select.register_select(var, config, options=DUCO_MODE_OPTIONS) - - parent = await cg.get_variable(config[CONF_DUCO_ID]) cg.add(var.set_parent(parent)) + + if CONF_BYPASS_MODE in config: + bypass_mode_config = config[CONF_BYPASS_MODE] + var = cg.new_Pvariable(bypass_mode_config[CONF_ID]) + await cg.register_component(var, bypass_mode_config) + await select.register_select(var, bypass_mode_config, options=DUCO_BYPASS_MODE_OPTIONS) + cg.add(var.set_parent(parent)) diff --git a/esphome/components/duco/select/select.cpp b/esphome/components/duco/select/select.cpp index 1d08b95f5291..4773e8b03b9d 100644 --- a/esphome/components/duco/select/select.cpp +++ b/esphome/components/duco/select/select.cpp @@ -156,5 +156,64 @@ void DucoSelect::control(const std::string &value) { this->parent_->send(message, this); } +const std::string DucoBypassModeSelect::MODE_AUTO = "AUTO"; +const std::string DucoBypassModeSelect::MODE_CLOSED = "CLOSED"; +const std::string DucoBypassModeSelect::MODE_OPEN = "OPEN"; + +void DucoBypassModeSelect::setup() {} + +void DucoBypassModeSelect::update() { + DucoMessage message; + message.function = 0x24; + message.data = {0x00, 0x10, 0x0a}; + this->parent_->send(message, this); +} + +float DucoBypassModeSelect::get_setup_priority() const { + // After DUCO + return setup_priority::BUS - 2.0f; +} + +std::string bypass_mode_code_to_string(uint8_t mode) { + switch (mode) { + case DucoBypassModeSelect::MODE_CODE_CLOSED: + return DucoBypassModeSelect::MODE_CLOSED; + case DucoBypassModeSelect::MODE_CODE_OPEN: + return DucoBypassModeSelect::MODE_OPEN; + case DucoBypassModeSelect::MODE_CODE_AUTO: + default: + return DucoBypassModeSelect::MODE_AUTO; + } +} + +uint8_t bypass_mode_string_to_code(const std::string &mode) { + if (mode == DucoBypassModeSelect::MODE_CLOSED) { + return DucoBypassModeSelect::MODE_CODE_CLOSED; + } + if (mode == DucoBypassModeSelect::MODE_OPEN) { + return DucoBypassModeSelect::MODE_CODE_OPEN; + } + return DucoBypassModeSelect::MODE_CODE_AUTO; +} + +void DucoBypassModeSelect::receive_response(const DucoMessage &message) { + if (message.function == 0x26 && message.data.size() >= 4) { + uint8_t mode = message.data[3]; + if (mode <= MODE_CODE_OPEN) { + publish_state(bypass_mode_code_to_string(mode)); + ESP_LOGD(TAG, "Current bypass mode: %s", bypass_mode_code_to_string(mode).c_str()); + } + + this->parent_->stop_waiting(message.id); + } +} + +void DucoBypassModeSelect::control(const std::string &value) { + DucoMessage message; + message.function = 0x24; + message.data = {0x01, 0x10, 0x0a, bypass_mode_string_to_code(value), 0x00, 0x00, 0x00}; + this->parent_->send(message, this); +} + } // namespace duco } // namespace esphome diff --git a/esphome/components/duco/select/select.h b/esphome/components/duco/select/select.h index 5ef6395352e5..c51baf205ac8 100644 --- a/esphome/components/duco/select/select.h +++ b/esphome/components/duco/select/select.h @@ -50,5 +50,25 @@ class DucoSelect : public DucoDevice, public PollingComponent, public select::Se void control(const std::string &value) override; }; +class DucoBypassModeSelect : public DucoDevice, public PollingComponent, public select::Select { + public: + static const std::string MODE_AUTO; + static const std::string MODE_CLOSED; + static const std::string MODE_OPEN; + + static const uint8_t MODE_CODE_AUTO = 0x00; + static const uint8_t MODE_CODE_CLOSED = 0x01; + static const uint8_t MODE_CODE_OPEN = 0x02; + + void setup() override; + void update() override; + + float get_setup_priority() const override; + + void receive_response(const DucoMessage &message) override; + + void control(const std::string &value) override; +}; + } // namespace duco } // namespace esphome