diff --git a/esphome/components/template/alarm_control_panel/__init__.py b/esphome/components/template/alarm_control_panel/__init__.py index a406c626ee..5d2421fcbc 100644 --- a/esphome/components/template/alarm_control_panel/__init__.py +++ b/esphome/components/template/alarm_control_panel/__init__.py @@ -10,6 +10,7 @@ CODEOWNERS = ["@grahambrown11", "@hwstar"] CONF_CODES = "codes" CONF_BYPASS_ARMED_HOME = "bypass_armed_home" CONF_BYPASS_ARMED_NIGHT = "bypass_armed_night" +CONF_BYPASS_AUTO = "bypass_auto" CONF_CHIME = "chime" CONF_TRIGGER_MODE = "trigger_mode" CONF_REQUIRES_CODE_TO_ARM = "requires_code_to_arm" @@ -23,6 +24,7 @@ CONF_TRIGGER_TIME = "trigger_time" FLAG_NORMAL = "normal" FLAG_BYPASS_ARMED_HOME = "bypass_armed_home" FLAG_BYPASS_ARMED_NIGHT = "bypass_armed_night" +FLAG_BYPASS_AUTO = "bypass_auto" FLAG_CHIME = "chime" BinarySensorFlags = { @@ -30,6 +32,7 @@ BinarySensorFlags = { FLAG_BYPASS_ARMED_HOME: 1 << 1, FLAG_BYPASS_ARMED_NIGHT: 1 << 2, FLAG_CHIME: 1 << 3, + FLAG_BYPASS_AUTO: 1 << 4, } @@ -68,6 +71,7 @@ TEMPLATE_ALARM_CONTROL_PANEL_BINARY_SENSOR_SCHEMA = cv.maybe_simple_value( cv.Required(CONF_INPUT): cv.use_id(binary_sensor.BinarySensor), cv.Optional(CONF_BYPASS_ARMED_HOME, default=False): cv.boolean, cv.Optional(CONF_BYPASS_ARMED_NIGHT, default=False): cv.boolean, + cv.Optional(CONF_BYPASS_AUTO, default=False): cv.boolean, cv.Optional(CONF_CHIME, default=False): cv.boolean, cv.Optional(CONF_TRIGGER_MODE, default="DELAYED"): cv.enum( ALARM_SENSOR_TYPES, upper=True, space="_" @@ -143,6 +147,8 @@ async def to_code(config): if sensor[CONF_BYPASS_ARMED_NIGHT]: flags |= BinarySensorFlags[FLAG_BYPASS_ARMED_NIGHT] supports_arm_night = True + if sensor[CONF_BYPASS_AUTO]: + flags |= BinarySensorFlags[FLAG_BYPASS_AUTO] if sensor[CONF_CHIME]: flags |= BinarySensorFlags[FLAG_CHIME] cg.add(var.add_sensor(bs, flags, sensor[CONF_TRIGGER_MODE])) diff --git a/esphome/components/template/alarm_control_panel/template_alarm_control_panel.cpp b/esphome/components/template/alarm_control_panel/template_alarm_control_panel.cpp index 84d256b18f..4b81ab1c35 100644 --- a/esphome/components/template/alarm_control_panel/template_alarm_control_panel.cpp +++ b/esphome/components/template/alarm_control_panel/template_alarm_control_panel.cpp @@ -49,6 +49,7 @@ void TemplateAlarmControlPanel::dump_config() { TRUEFALSE(sensor_info.second.flags & BINARY_SENSOR_MODE_BYPASS_ARMED_HOME)); ESP_LOGCONFIG(TAG, " Armed night bypass: %s", TRUEFALSE(sensor_info.second.flags & BINARY_SENSOR_MODE_BYPASS_ARMED_NIGHT)); + ESP_LOGCONFIG(TAG, " Auto bypass: %s", TRUEFALSE(sensor_info.second.flags & BINARY_SENSOR_MODE_BYPASS_AUTO)); ESP_LOGCONFIG(TAG, " Chime mode: %s", TRUEFALSE(sensor_info.second.flags & BINARY_SENSOR_MODE_CHIME)); const char *sensor_type; switch (sensor_info.second.type) { @@ -101,6 +102,15 @@ void TemplateAlarmControlPanel::loop() { delay = this->arming_night_time_; } if ((millis() - this->last_update_) > delay) { +#ifdef USE_BINARY_SENSOR + for (auto sensor_info : this->sensor_map_) { + // Check for sensors left on and set to bypass automatically and remove them from monitoring + if ((sensor_info.second.flags & BINARY_SENSOR_MODE_BYPASS_AUTO) && (sensor_info.first->state)) { + ESP_LOGW(TAG, "%s is left on and will be automatically bypassed", sensor_info.first->get_name().c_str()); + this->bypassed_sensor_indicies_.push_back(sensor_info.second.store_index); + } + } +#endif this->publish_state(this->desired_state_); } return; @@ -137,6 +147,11 @@ void TemplateAlarmControlPanel::loop() { } // Check for triggered sensors if (sensor_info.first->state) { // Sensor triggered? + // Skip if auto bypassed + if (std::count(this->bypassed_sensor_indicies_.begin(), this->bypassed_sensor_indicies_.end(), + sensor_info.second.store_index) == 1) { + continue; + } // Skip if bypass armed home if (this->current_state_ == ACP_STATE_ARMED_HOME && (sensor_info.second.flags & BINARY_SENSOR_MODE_BYPASS_ARMED_HOME)) { @@ -255,6 +270,9 @@ void TemplateAlarmControlPanel::control(const AlarmControlPanelCall &call) { } this->desired_state_ = ACP_STATE_DISARMED; this->publish_state(ACP_STATE_DISARMED); +#ifdef USE_BINARY_SENSOR + this->bypassed_sensor_indicies_.clear(); +#endif } else if (call.get_state() == ACP_STATE_TRIGGERED) { this->publish_state(ACP_STATE_TRIGGERED); } else if (call.get_state() == ACP_STATE_PENDING) { diff --git a/esphome/components/template/alarm_control_panel/template_alarm_control_panel.h b/esphome/components/template/alarm_control_panel/template_alarm_control_panel.h index b29a48dfd7..0e3a5c77cf 100644 --- a/esphome/components/template/alarm_control_panel/template_alarm_control_panel.h +++ b/esphome/components/template/alarm_control_panel/template_alarm_control_panel.h @@ -22,6 +22,7 @@ enum BinarySensorFlags : uint16_t { BINARY_SENSOR_MODE_BYPASS_ARMED_HOME = 1 << 1, BINARY_SENSOR_MODE_BYPASS_ARMED_NIGHT = 1 << 2, BINARY_SENSOR_MODE_CHIME = 1 << 3, + BINARY_SENSOR_MODE_BYPASS_AUTO = 1 << 4, }; enum AlarmSensorType : uint16_t { @@ -121,7 +122,8 @@ class TemplateAlarmControlPanel : public alarm_control_panel::AlarmControlPanel, #ifdef USE_BINARY_SENSOR // This maps a binary sensor to its type and attribute bits std::map sensor_map_; - + // a list of automatically bypassed sensors + std::vector bypassed_sensor_indicies_; #endif TemplateAlarmControlPanelRestoreMode restore_mode_{}; diff --git a/tests/components/alarm_control_panel/common.yaml b/tests/components/alarm_control_panel/common.yaml index 218274bad4..5b8ae5a282 100644 --- a/tests/components/alarm_control_panel/common.yaml +++ b/tests/components/alarm_control_panel/common.yaml @@ -19,6 +19,7 @@ alarm_control_panel: - input: bin1 bypass_armed_home: true bypass_armed_night: true + bypass_auto: true on_state: then: - lambda: !lambda |- @@ -38,6 +39,7 @@ alarm_control_panel: - input: bin1 bypass_armed_home: true bypass_armed_night: true + bypass_auto: true on_disarmed: then: - logger.log: "### DISARMED ###"