diff --git a/components/tc_bus/__init__.py b/components/tc_bus/__init__.py index ac42c5fb..d7ce985b 100644 --- a/components/tc_bus/__init__.py +++ b/components/tc_bus/__init__.py @@ -1,10 +1,10 @@ import esphome.codegen as cg import esphome.config_validation as cv -from esphome.components import text_sensor, binary_sensor +from esphome.components import text_sensor, binary_sensor, select from esphome import pins, automation -from esphome.const import CONF_ID, ENTITY_CATEGORY_DIAGNOSTIC, CONF_TRIGGER_ID, CONF_TYPE, CONF_VALUE +from esphome.const import CONF_ID, ENTITY_CATEGORY_DIAGNOSTIC, ENTITY_CATEGORY_CONFIG, CONF_TRIGGER_ID, CONF_TYPE, CONF_VALUE -AUTO_LOAD = ["binary_sensor", "text_sensor"] +AUTO_LOAD = ["binary_sensor", "text_sensor", "select"] CODEOWNERS = ["@azoninc"] tc_bus_ns = cg.esphome_ns.namespace("tc_bus") @@ -29,6 +29,8 @@ CommandData = tc_bus_ns.struct(f"CommandData") SettingData = tc_bus_ns.struct(f"SettingData") +ModelSelect = tc_bus_ns.class_("ModelSelect", select.Select, cg.Component) + ReadMemoryCompleteTrigger = tc_bus_ns.class_("ReadMemoryCompleteTrigger", automation.Trigger.template()) ReadMemoryTimeoutTrigger = tc_bus_ns.class_("ReadMemoryTimeoutTrigger", automation.Trigger.template()) ReceivedCommandTrigger = tc_bus_ns.class_("ReceivedCommandTrigger", automation.Trigger.template()) @@ -128,10 +130,13 @@ def validate_config(config): cv.GenerateID(): cv.declare_id(TCBus), cv.Optional(CONF_RX_PIN, default=9): pins.internal_gpio_input_pin_schema, cv.Optional(CONF_TX_PIN, default=8): pins.internal_gpio_output_pin_schema, - cv.Optional(CONF_MODEL, default="NONE"): cv.enum(MODELS, upper=True), cv.Optional(CONF_EVENT, default="tc"): cv.string, cv.Optional(CONF_SERIAL_NUMBER, default=0): cv.hex_uint32_t, cv.Optional(CONF_SERIAL_NUMBER_LAMBDA): cv.returning_lambda, + cv.Optional(CONF_MODEL): select.select_schema( + ModelSelect, + entity_category=ENTITY_CATEGORY_CONFIG, + ), cv.Optional(CONF_BUS_COMMAND): text_sensor.text_sensor_schema( entity_category=ENTITY_CATEGORY_DIAGNOSTIC, icon="mdi:console-network", @@ -176,11 +181,16 @@ async def to_code(config): pin = await cg.gpio_pin_expression(config[CONF_TX_PIN]) cg.add(var.set_tx_pin(pin)) - if CONF_MODEL in config: - cg.add(var.set_model(config[CONF_MODEL])) - cg.add(var.set_event("esphome." + config[CONF_EVENT])) + if model := config.get(CONF_MODEL): + sel = await select.new_select( + model, + options=[MODELS], + ) + await cg.register_parented(sel, config[CONF_ID]) + cg.add(var.set_model_select(sel)) + if CONF_SERIAL_NUMBER in config: cg.add(var.set_sn(config[CONF_SERIAL_NUMBER])) @@ -192,15 +202,15 @@ async def to_code(config): if CONF_BUS_COMMAND in config: sens = await text_sensor.new_text_sensor(config[CONF_BUS_COMMAND]) - cg.add(var.set_bus_command_sensor(sens)) + cg.add(var.set_bus_command_text_sensor(sens)) if CONF_HARDWARE_VERSION in config: sens = await text_sensor.new_text_sensor(config[CONF_HARDWARE_VERSION]) - cg.add(var.set_hardware_version_sensor(sens)) + cg.add(var.set_hardware_version_text_sensor(sens)) if CONF_DOOR_READINESS in config: sens = await binary_sensor.new_binary_sensor(config[CONF_DOOR_READINESS]) - cg.add(var.set_door_readiness_sensor(sens)) + cg.add(var.set_door_readiness_binary_sensor(sens)) for conf in config.get(CONF_ON_COMMAND, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) diff --git a/components/tc_bus/tc_bus.cpp b/components/tc_bus/tc_bus.cpp index 61a4f2ef..639c1cb7 100644 --- a/components/tc_bus/tc_bus.cpp +++ b/components/tc_bus/tc_bus.cpp @@ -42,6 +42,19 @@ namespace esphome { ESP_LOGCONFIG(TAG, "Setting up TC:BUS Intercom..."); + this->pref_ = global_preferences->make_preference(this->get_object_id_hash()); + + Model saved_model; + if (this->pref_.load(&saved_model)) + { + this->model_ = saved_model; + } + else + { + this->model_ = MODEL_NONE; + this->pref_.save(this->model_); + } + #if defined(USE_ESP_IDF) || (defined(USE_ARDUINO) && defined(ESP32)) ESP_LOGD(TAG, "Check for Doorman Hardware"); @@ -81,9 +94,9 @@ namespace esphome } #endif - if (this->hardware_version_ != nullptr) + if (this->hardware_version_text_sensor_ != nullptr) { - this->hardware_version_->publish_state(this->hardware_version_str_); + this->hardware_version_text_sensor_->publish_state(this->hardware_version_str_); } this->rx_pin_->setup(); @@ -96,14 +109,14 @@ namespace esphome this->rx_pin_->attach_interrupt(TCBusComponentStore::gpio_intr, &this->store_, gpio::INTERRUPT_ANY_EDGE); // Reset Sensors - if (this->bus_command_ != nullptr) + if (this->bus_command_text_sensor_ != nullptr) { - this->bus_command_->publish_state(""); + this->bus_command_text_sensor_->publish_state(""); } - if (this->door_readiness_ != nullptr) + if (this->door_readiness_binary_sensor_ != nullptr) { - this->door_readiness_->publish_initial_state(false); + this->door_readiness_binary_sensor_->publish_initial_state(false); } for (auto &listener : listeners_) @@ -131,13 +144,13 @@ namespace esphome #ifdef USE_BINARY_SENSOR ESP_LOGCONFIG(TAG, "Binary Sensors:"); - LOG_BINARY_SENSOR(" ", "Door readiness", this->door_readiness_); + LOG_BINARY_SENSOR(" ", "Door readiness", this->door_readiness_binary_sensor_); #endif #ifdef USE_TEXT_SENSOR ESP_LOGCONFIG(TAG, "Text Sensors:"); - LOG_TEXT_SENSOR(" ", "Last Bus Command", this->bus_command_); - LOG_TEXT_SENSOR(" ", "Hardware Version", this->hardware_version_); + LOG_TEXT_SENSOR(" ", "Last Bus Command", this->bus_command_text_sensor_); + LOG_TEXT_SENSOR(" ", "Hardware Version", this->hardware_version_text_sensor_); #endif } @@ -390,15 +403,15 @@ namespace esphome { bool door_readiness_state = cmd_data.payload == 1; ESP_LOGD(TAG, "Door readiness: %s", YESNO(door_readiness_state)); - if (this->door_readiness_ != nullptr) { - this->door_readiness_->publish_state(door_readiness_state); + if (this->door_readiness_binary_sensor_ != nullptr) { + this->door_readiness_binary_sensor_->publish_state(door_readiness_state); } } else if (cmd_data.type == COMMAND_TYPE_END_OF_DOOR_READINESS) { ESP_LOGD(TAG, "Door readiness: %s", YESNO(false)); - if (this->door_readiness_ != nullptr) { - this->door_readiness_->publish_state(false); + if (this->door_readiness_binary_sensor_ != nullptr) { + this->door_readiness_binary_sensor_->publish_state(false); } } else if (cmd_data.type == COMMAND_TYPE_PROGRAMMING_MODE) @@ -431,9 +444,9 @@ namespace esphome } // Publish Command to Last Bus Command Sensor - if (this->bus_command_ != nullptr) + if (this->bus_command_text_sensor_ != nullptr) { - this->bus_command_->publish_state(cmd_data.command_hex); + this->bus_command_text_sensor_->publish_state(cmd_data.command_hex); } // If the command was received, notify the listeners @@ -651,6 +664,17 @@ namespace esphome send_command(COMMAND_TYPE_PROGRAMMING_MODE, 0, enabled ? 1 : 0); } + #ifdef USE_SELECT + void ModelSelect::control(const std::string &value) + { + this->model_select_->publish_state(value); + + Model model = string_to_model(&value); + this->model_ = model; + this->pref_.save(model); + } + #endif + void TCBusComponent::read_memory(uint32_t serial_number) { if(serial_number == 0) diff --git a/components/tc_bus/tc_bus.h b/components/tc_bus/tc_bus.h index a024dda7..52a271c3 100644 --- a/components/tc_bus/tc_bus.h +++ b/components/tc_bus/tc_bus.h @@ -4,6 +4,7 @@ #include #include +#include "esphome/core/preferences.h" #include "esphome/core/component.h" #include "esphome/core/hal.h" #include "esphome/core/helpers.h" @@ -65,6 +66,17 @@ namespace esphome class TCBusComponent : public Component { + #ifdef USE_SELECT + SUB_SELECT(model) + #endif + #ifdef USE_TEXT_SENSOR + SUB_TEXT_SENSOR(bus_command) + SUB_TEXT_SENSOR(hardware_version) + #endif + #ifdef USE_BINARY_SENSOR + SUB_BINARY_SENSOR(door_readiness) + #endif + public: void set_rx_pin(InternalGPIOPin *pin) { this->rx_pin_ = pin; } void set_tx_pin(InternalGPIOPin *pin) { this->tx_pin_ = pin; } @@ -82,10 +94,6 @@ namespace esphome void set_sn(uint32_t serial_number) { this->serial_number_ = serial_number; } void set_sn_lambda(std::function()> &&serial_number_lambda) { this->serial_number_lambda_ = serial_number_lambda; } - void set_bus_command_sensor(text_sensor::TextSensor *bus_command) { this->bus_command_ = bus_command; } - void set_hardware_version_sensor(text_sensor::TextSensor *hardware_version) { this->hardware_version_ = hardware_version; } - void set_door_readiness_sensor(binary_sensor::BinarySensor *door_readiness) { this->door_readiness_ = door_readiness; } - void send_command(uint32_t command); void send_command(CommandType type, uint8_t address = 0, uint32_t payload = 0, uint32_t serial_number = 0); void set_programming_mode(bool enabled); @@ -122,9 +130,6 @@ namespace esphome uint32_t serial_number_; optional()>> serial_number_lambda_; - text_sensor::TextSensor *bus_command_{nullptr}; - text_sensor::TextSensor *hardware_version_{nullptr}; - binary_sensor::BinarySensor *door_readiness_{nullptr}; std::string hardware_version_str_ = "Generic"; bool programming_mode_ = false; @@ -133,6 +138,15 @@ namespace esphome uint8_t reading_memory_count_ = 0; uint32_t reading_memory_timer_ = 0; std::vector memory_buffer_; + + ESPPreferenceObject pref_; + }; + + class ModelSelect : public select::Select, public Parented { + public: + ModelSelect() = default; + protected: + void control(const std::string &value) override; }; } // namespace tc_bus diff --git a/firmware/addons/memory-utils.yaml b/firmware/addons/memory-utils.yaml index 70939943..1a55a77e 100644 --- a/firmware/addons/memory-utils.yaml +++ b/firmware/addons/memory-utils.yaml @@ -11,6 +11,16 @@ tc_bus: on_read_memory_timeout: - logger.log: "Failed to read Memory" + model: + id: intercom_model + name: "Intercom Model" + icon: "mdi:doorbell-video" + initial_option: "NONE" + entity_category: CONFIG + disabled_by_default: true + web_server: + sorting_group_id: sorting_group_intercom_settings + # Read Memory before reading and writing button: - platform: template @@ -64,33 +74,6 @@ number: sorting_group_id: sorting_group_intercom_settings select: - - platform: template - id: intercom_model - name: "Intercom Model" - icon: "mdi:doorbell-video" - options: - - "NONE" - - "TCS_ISH1030" - - "TCS_ISH3030" - - "TCS_ISH3230" - - "TCS_ISH3340" - - "TCS_ISW3030" - - "TCS_ISW3230" - - "TCS_ISW3340" - - "TCS_IVH3222" - - "KOCH_TC50" - - "KOCH_TCH50" - - "KOCH_TCH50P" - initial_option: "NONE" - on_value: - - lambda: "id(tc_bus_intercom)->set_model(string_to_model(x));" - optimistic: true - restore_value: true - entity_category: CONFIG - disabled_by_default: true - web_server: - sorting_group_id: sorting_group_intercom_settings - - platform: template id: intercom_ringtone_door_call name: "Ringtone: Door Call"