mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 07:03:55 +00:00 
			
		
		
		
	Add arm night to alarm control panel (#5186)
This commit is contained in:
		
				
					committed by
					
						 GitHub
						GitHub
					
				
			
			
				
	
			
			
			
						parent
						
							ffd2cb9814
						
					
				
				
					commit
					a6b89e4e8a
				
			| @@ -31,6 +31,7 @@ ClearedTrigger = alarm_control_panel_ns.class_( | |||||||
| ) | ) | ||||||
| ArmAwayAction = alarm_control_panel_ns.class_("ArmAwayAction", automation.Action) | ArmAwayAction = alarm_control_panel_ns.class_("ArmAwayAction", automation.Action) | ||||||
| ArmHomeAction = alarm_control_panel_ns.class_("ArmHomeAction", automation.Action) | ArmHomeAction = alarm_control_panel_ns.class_("ArmHomeAction", automation.Action) | ||||||
|  | ArmNightAction = alarm_control_panel_ns.class_("ArmNightAction", automation.Action) | ||||||
| DisarmAction = alarm_control_panel_ns.class_("DisarmAction", automation.Action) | DisarmAction = alarm_control_panel_ns.class_("DisarmAction", automation.Action) | ||||||
| PendingAction = alarm_control_panel_ns.class_("PendingAction", automation.Action) | PendingAction = alarm_control_panel_ns.class_("PendingAction", automation.Action) | ||||||
| TriggeredAction = alarm_control_panel_ns.class_("TriggeredAction", automation.Action) | TriggeredAction = alarm_control_panel_ns.class_("TriggeredAction", automation.Action) | ||||||
| @@ -117,6 +118,18 @@ async def alarm_action_arm_home_to_code(config, action_id, template_arg, args): | |||||||
|     return var |     return var | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @automation.register_action( | ||||||
|  |     "alarm_control_panel.arm_night", ArmNightAction, ALARM_CONTROL_PANEL_ACTION_SCHEMA | ||||||
|  | ) | ||||||
|  | async def alarm_action_arm_night_to_code(config, action_id, template_arg, args): | ||||||
|  |     paren = await cg.get_variable(config[CONF_ID]) | ||||||
|  |     var = cg.new_Pvariable(action_id, template_arg, paren) | ||||||
|  |     if CONF_CODE in config: | ||||||
|  |         templatable_ = await cg.templatable(config[CONF_CODE], args, cg.std_string) | ||||||
|  |         cg.add(var.set_code(templatable_)) | ||||||
|  |     return var | ||||||
|  |  | ||||||
|  |  | ||||||
| @automation.register_action( | @automation.register_action( | ||||||
|     "alarm_control_panel.disarm", DisarmAction, ALARM_CONTROL_PANEL_ACTION_SCHEMA |     "alarm_control_panel.disarm", DisarmAction, ALARM_CONTROL_PANEL_ACTION_SCHEMA | ||||||
| ) | ) | ||||||
|   | |||||||
| @@ -85,6 +85,11 @@ void AlarmControlPanelCall::validate_() { | |||||||
|       this->state_.reset(); |       this->state_.reset(); | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|  |     if (state == ACP_STATE_ARMED_NIGHT && (this->parent_->get_supported_features() & ACP_FEAT_ARM_NIGHT) == 0) { | ||||||
|  |       ESP_LOGW(TAG, "Cannot arm night when not supported"); | ||||||
|  |       this->state_.reset(); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -12,7 +12,7 @@ const LogString *alarm_control_panel_state_to_string(AlarmControlPanelState stat | |||||||
|     case ACP_STATE_ARMED_AWAY: |     case ACP_STATE_ARMED_AWAY: | ||||||
|       return LOG_STR("ARMED_AWAY"); |       return LOG_STR("ARMED_AWAY"); | ||||||
|     case ACP_STATE_ARMED_NIGHT: |     case ACP_STATE_ARMED_NIGHT: | ||||||
|       return LOG_STR("NIGHT"); |       return LOG_STR("ARMED_NIGHT"); | ||||||
|     case ACP_STATE_ARMED_VACATION: |     case ACP_STATE_ARMED_VACATION: | ||||||
|       return LOG_STR("ARMED_VACATION"); |       return LOG_STR("ARMED_VACATION"); | ||||||
|     case ACP_STATE_ARMED_CUSTOM_BYPASS: |     case ACP_STATE_ARMED_CUSTOM_BYPASS: | ||||||
|   | |||||||
| @@ -67,6 +67,26 @@ template<typename... Ts> class ArmHomeAction : public Action<Ts...> { | |||||||
|   AlarmControlPanel *alarm_control_panel_; |   AlarmControlPanel *alarm_control_panel_; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | template<typename... Ts> class ArmNightAction : public Action<Ts...> { | ||||||
|  |  public: | ||||||
|  |   explicit ArmNightAction(AlarmControlPanel *alarm_control_panel) : alarm_control_panel_(alarm_control_panel) {} | ||||||
|  |  | ||||||
|  |   TEMPLATABLE_VALUE(std::string, code) | ||||||
|  |  | ||||||
|  |   void play(Ts... x) override { | ||||||
|  |     auto call = this->alarm_control_panel_->make_call(); | ||||||
|  |     auto code = this->code_.optional_value(x...); | ||||||
|  |     if (code.has_value()) { | ||||||
|  |       call.set_code(code.value()); | ||||||
|  |     } | ||||||
|  |     call.arm_night(); | ||||||
|  |     call.perform(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   AlarmControlPanel *alarm_control_panel_; | ||||||
|  | }; | ||||||
|  |  | ||||||
| template<typename... Ts> class DisarmAction : public Action<Ts...> { | template<typename... Ts> class DisarmAction : public Action<Ts...> { | ||||||
|  public: |  public: | ||||||
|   explicit DisarmAction(AlarmControlPanel *alarm_control_panel) : alarm_control_panel_(alarm_control_panel) {} |   explicit DisarmAction(AlarmControlPanel *alarm_control_panel) : alarm_control_panel_(alarm_control_panel) {} | ||||||
|   | |||||||
| @@ -16,18 +16,22 @@ CODEOWNERS = ["@grahambrown11"] | |||||||
|  |  | ||||||
| CONF_CODES = "codes" | CONF_CODES = "codes" | ||||||
| CONF_BYPASS_ARMED_HOME = "bypass_armed_home" | CONF_BYPASS_ARMED_HOME = "bypass_armed_home" | ||||||
|  | CONF_BYPASS_ARMED_NIGHT = "bypass_armed_night" | ||||||
| CONF_REQUIRES_CODE_TO_ARM = "requires_code_to_arm" | CONF_REQUIRES_CODE_TO_ARM = "requires_code_to_arm" | ||||||
| CONF_ARMING_HOME_TIME = "arming_home_time" | CONF_ARMING_HOME_TIME = "arming_home_time" | ||||||
|  | CONF_ARMING_NIGHT_TIME = "arming_night_time" | ||||||
| CONF_ARMING_AWAY_TIME = "arming_away_time" | CONF_ARMING_AWAY_TIME = "arming_away_time" | ||||||
| CONF_PENDING_TIME = "pending_time" | CONF_PENDING_TIME = "pending_time" | ||||||
| CONF_TRIGGER_TIME = "trigger_time" | CONF_TRIGGER_TIME = "trigger_time" | ||||||
|  |  | ||||||
| FLAG_NORMAL = "normal" | FLAG_NORMAL = "normal" | ||||||
| FLAG_BYPASS_ARMED_HOME = "bypass_armed_home" | FLAG_BYPASS_ARMED_HOME = "bypass_armed_home" | ||||||
|  | FLAG_BYPASS_ARMED_NIGHT = "bypass_armed_night" | ||||||
|  |  | ||||||
| BinarySensorFlags = { | BinarySensorFlags = { | ||||||
|     FLAG_NORMAL: 1 << 0, |     FLAG_NORMAL: 1 << 0, | ||||||
|     FLAG_BYPASS_ARMED_HOME: 1 << 1, |     FLAG_BYPASS_ARMED_HOME: 1 << 1, | ||||||
|  |     FLAG_BYPASS_ARMED_NIGHT: 1 << 2, | ||||||
| } | } | ||||||
|  |  | ||||||
| TemplateAlarmControlPanel = template_ns.class_( | TemplateAlarmControlPanel = template_ns.class_( | ||||||
| @@ -55,6 +59,7 @@ TEMPLATE_ALARM_CONTROL_PANEL_BINARY_SENSOR_SCHEMA = cv.maybe_simple_value( | |||||||
|     { |     { | ||||||
|         cv.Required(CONF_INPUT): cv.use_id(binary_sensor.BinarySensor), |         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_HOME, default=False): cv.boolean, | ||||||
|  |         cv.Optional(CONF_BYPASS_ARMED_NIGHT, default=False): cv.boolean, | ||||||
|     }, |     }, | ||||||
|     key=CONF_INPUT, |     key=CONF_INPUT, | ||||||
| ) | ) | ||||||
| @@ -66,6 +71,7 @@ TEMPLATE_ALARM_CONTROL_PANEL_SCHEMA = ( | |||||||
|             cv.Optional(CONF_CODES): cv.ensure_list(cv.string_strict), |             cv.Optional(CONF_CODES): cv.ensure_list(cv.string_strict), | ||||||
|             cv.Optional(CONF_REQUIRES_CODE_TO_ARM): cv.boolean, |             cv.Optional(CONF_REQUIRES_CODE_TO_ARM): cv.boolean, | ||||||
|             cv.Optional(CONF_ARMING_HOME_TIME): cv.positive_time_period_milliseconds, |             cv.Optional(CONF_ARMING_HOME_TIME): cv.positive_time_period_milliseconds, | ||||||
|  |             cv.Optional(CONF_ARMING_NIGHT_TIME): cv.positive_time_period_milliseconds, | ||||||
|             cv.Optional( |             cv.Optional( | ||||||
|                 CONF_ARMING_AWAY_TIME, default="0s" |                 CONF_ARMING_AWAY_TIME, default="0s" | ||||||
|             ): cv.positive_time_period_milliseconds, |             ): cv.positive_time_period_milliseconds, | ||||||
| @@ -110,14 +116,23 @@ async def to_code(config): | |||||||
|         cg.add(var.set_arming_home_time(config[CONF_ARMING_HOME_TIME])) |         cg.add(var.set_arming_home_time(config[CONF_ARMING_HOME_TIME])) | ||||||
|         supports_arm_home = True |         supports_arm_home = True | ||||||
|  |  | ||||||
|  |     supports_arm_night = False | ||||||
|  |     if CONF_ARMING_NIGHT_TIME in config: | ||||||
|  |         cg.add(var.set_arming_night_time(config[CONF_ARMING_NIGHT_TIME])) | ||||||
|  |         supports_arm_night = True | ||||||
|  |  | ||||||
|     for sensor in config.get(CONF_BINARY_SENSORS, []): |     for sensor in config.get(CONF_BINARY_SENSORS, []): | ||||||
|         bs = await cg.get_variable(sensor[CONF_INPUT]) |         bs = await cg.get_variable(sensor[CONF_INPUT]) | ||||||
|         flags = BinarySensorFlags[FLAG_NORMAL] |         flags = BinarySensorFlags[FLAG_NORMAL] | ||||||
|         if sensor[CONF_BYPASS_ARMED_HOME]: |         if sensor[CONF_BYPASS_ARMED_HOME]: | ||||||
|             flags |= BinarySensorFlags[FLAG_BYPASS_ARMED_HOME] |             flags |= BinarySensorFlags[FLAG_BYPASS_ARMED_HOME] | ||||||
|             supports_arm_home = True |             supports_arm_home = True | ||||||
|  |         if sensor[CONF_BYPASS_ARMED_NIGHT]: | ||||||
|  |             flags |= BinarySensorFlags[FLAG_BYPASS_ARMED_NIGHT] | ||||||
|  |             supports_arm_night = True | ||||||
|         cg.add(var.add_sensor(bs, flags)) |         cg.add(var.add_sensor(bs, flags)) | ||||||
|  |  | ||||||
|     cg.add(var.set_supports_arm_home(supports_arm_home)) |     cg.add(var.set_supports_arm_home(supports_arm_home)) | ||||||
|  |     cg.add(var.set_supports_arm_night(supports_arm_night)) | ||||||
|  |  | ||||||
|     cg.add(var.set_restore_mode(config[CONF_RESTORE_MODE])) |     cg.add(var.set_restore_mode(config[CONF_RESTORE_MODE])) | ||||||
|   | |||||||
| @@ -29,6 +29,8 @@ void TemplateAlarmControlPanel::dump_config() { | |||||||
|   ESP_LOGCONFIG(TAG, "  Arming Away Time: %us", (this->arming_away_time_ / 1000)); |   ESP_LOGCONFIG(TAG, "  Arming Away Time: %us", (this->arming_away_time_ / 1000)); | ||||||
|   if (this->arming_home_time_ != 0) |   if (this->arming_home_time_ != 0) | ||||||
|     ESP_LOGCONFIG(TAG, "  Arming Home Time: %us", (this->arming_home_time_ / 1000)); |     ESP_LOGCONFIG(TAG, "  Arming Home Time: %us", (this->arming_home_time_ / 1000)); | ||||||
|  |   if (this->arming_night_time_ != 0) | ||||||
|  |     ESP_LOGCONFIG(TAG, "  Arming Night Time: %us", (this->arming_night_time_ / 1000)); | ||||||
|   ESP_LOGCONFIG(TAG, "  Pending Time: %us", (this->pending_time_ / 1000)); |   ESP_LOGCONFIG(TAG, "  Pending Time: %us", (this->pending_time_ / 1000)); | ||||||
|   ESP_LOGCONFIG(TAG, "  Trigger Time: %us", (this->trigger_time_ / 1000)); |   ESP_LOGCONFIG(TAG, "  Trigger Time: %us", (this->trigger_time_ / 1000)); | ||||||
|   ESP_LOGCONFIG(TAG, "  Supported Features: %u", this->get_supported_features()); |   ESP_LOGCONFIG(TAG, "  Supported Features: %u", this->get_supported_features()); | ||||||
| @@ -38,6 +40,8 @@ void TemplateAlarmControlPanel::dump_config() { | |||||||
|     ESP_LOGCONFIG(TAG, "    Name: %s", sensor_pair.first->get_name().c_str()); |     ESP_LOGCONFIG(TAG, "    Name: %s", sensor_pair.first->get_name().c_str()); | ||||||
|     ESP_LOGCONFIG(TAG, "    Armed home bypass: %s", |     ESP_LOGCONFIG(TAG, "    Armed home bypass: %s", | ||||||
|                   TRUEFALSE(sensor_pair.second & BINARY_SENSOR_MODE_BYPASS_ARMED_HOME)); |                   TRUEFALSE(sensor_pair.second & BINARY_SENSOR_MODE_BYPASS_ARMED_HOME)); | ||||||
|  |     ESP_LOGCONFIG(TAG, "    Armed night bypass: %s", | ||||||
|  |                   TRUEFALSE(sensor_pair.second & BINARY_SENSOR_MODE_BYPASS_ARMED_NIGHT)); | ||||||
|   } |   } | ||||||
| #endif | #endif | ||||||
| } | } | ||||||
| @@ -69,6 +73,9 @@ void TemplateAlarmControlPanel::loop() { | |||||||
|     if (this->desired_state_ == ACP_STATE_ARMED_HOME) { |     if (this->desired_state_ == ACP_STATE_ARMED_HOME) { | ||||||
|       delay = this->arming_home_time_; |       delay = this->arming_home_time_; | ||||||
|     } |     } | ||||||
|  |     if (this->desired_state_ == ACP_STATE_ARMED_NIGHT) { | ||||||
|  |       delay = this->arming_night_time_; | ||||||
|  |     } | ||||||
|     if ((millis() - this->last_update_) > delay) { |     if ((millis() - this->last_update_) > delay) { | ||||||
|       this->publish_state(this->desired_state_); |       this->publish_state(this->desired_state_); | ||||||
|     } |     } | ||||||
| @@ -95,6 +102,10 @@ void TemplateAlarmControlPanel::loop() { | |||||||
|             (sensor_pair.second & BINARY_SENSOR_MODE_BYPASS_ARMED_HOME)) { |             (sensor_pair.second & BINARY_SENSOR_MODE_BYPASS_ARMED_HOME)) { | ||||||
|           continue; |           continue; | ||||||
|         } |         } | ||||||
|  |         if (this->current_state_ == ACP_STATE_ARMED_NIGHT && | ||||||
|  |             (sensor_pair.second & BINARY_SENSOR_MODE_BYPASS_ARMED_NIGHT)) { | ||||||
|  |           continue; | ||||||
|  |         } | ||||||
|         trigger = true; |         trigger = true; | ||||||
|         break; |         break; | ||||||
|       } |       } | ||||||
| @@ -129,6 +140,9 @@ uint32_t TemplateAlarmControlPanel::get_supported_features() const { | |||||||
|   if (this->supports_arm_home_) { |   if (this->supports_arm_home_) { | ||||||
|     features |= ACP_FEAT_ARM_HOME; |     features |= ACP_FEAT_ARM_HOME; | ||||||
|   } |   } | ||||||
|  |   if (this->supports_arm_night_) { | ||||||
|  |     features |= ACP_FEAT_ARM_NIGHT; | ||||||
|  |   } | ||||||
|   return features; |   return features; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -158,6 +172,8 @@ void TemplateAlarmControlPanel::control(const AlarmControlPanelCall &call) { | |||||||
|       this->arm_(call.get_code(), ACP_STATE_ARMED_AWAY, this->arming_away_time_); |       this->arm_(call.get_code(), ACP_STATE_ARMED_AWAY, this->arming_away_time_); | ||||||
|     } else if (call.get_state() == ACP_STATE_ARMED_HOME) { |     } else if (call.get_state() == ACP_STATE_ARMED_HOME) { | ||||||
|       this->arm_(call.get_code(), ACP_STATE_ARMED_HOME, this->arming_home_time_); |       this->arm_(call.get_code(), ACP_STATE_ARMED_HOME, this->arming_home_time_); | ||||||
|  |     } else if (call.get_state() == ACP_STATE_ARMED_NIGHT) { | ||||||
|  |       this->arm_(call.get_code(), ACP_STATE_ARMED_NIGHT, this->arming_night_time_); | ||||||
|     } else if (call.get_state() == ACP_STATE_DISARMED) { |     } else if (call.get_state() == ACP_STATE_DISARMED) { | ||||||
|       if (!this->is_code_valid_(call.get_code())) { |       if (!this->is_code_valid_(call.get_code())) { | ||||||
|         ESP_LOGW(TAG, "Not disarming code doesn't match"); |         ESP_LOGW(TAG, "Not disarming code doesn't match"); | ||||||
|   | |||||||
| @@ -19,6 +19,7 @@ namespace template_ { | |||||||
| enum BinarySensorFlags : uint16_t { | enum BinarySensorFlags : uint16_t { | ||||||
|   BINARY_SENSOR_MODE_NORMAL = 1 << 0, |   BINARY_SENSOR_MODE_NORMAL = 1 << 0, | ||||||
|   BINARY_SENSOR_MODE_BYPASS_ARMED_HOME = 1 << 1, |   BINARY_SENSOR_MODE_BYPASS_ARMED_HOME = 1 << 1, | ||||||
|  |   BINARY_SENSOR_MODE_BYPASS_ARMED_NIGHT = 1 << 2, | ||||||
| }; | }; | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| @@ -71,6 +72,12 @@ class TemplateAlarmControlPanel : public alarm_control_panel::AlarmControlPanel, | |||||||
|    */ |    */ | ||||||
|   void set_arming_home_time(uint32_t time) { this->arming_home_time_ = time; } |   void set_arming_home_time(uint32_t time) { this->arming_home_time_ = time; } | ||||||
|  |  | ||||||
|  |   /** set the delay before arming night | ||||||
|  |    * | ||||||
|  |    * @param time The milliseconds | ||||||
|  |    */ | ||||||
|  |   void set_arming_night_time(uint32_t time) { this->arming_night_time_ = time; } | ||||||
|  |  | ||||||
|   /** set the delay before triggering |   /** set the delay before triggering | ||||||
|    * |    * | ||||||
|    * @param time The milliseconds |    * @param time The milliseconds | ||||||
| @@ -85,6 +92,8 @@ class TemplateAlarmControlPanel : public alarm_control_panel::AlarmControlPanel, | |||||||
|  |  | ||||||
|   void set_supports_arm_home(bool supports_arm_home) { supports_arm_home_ = supports_arm_home; } |   void set_supports_arm_home(bool supports_arm_home) { supports_arm_home_ = supports_arm_home; } | ||||||
|  |  | ||||||
|  |   void set_supports_arm_night(bool supports_arm_night) { supports_arm_night_ = supports_arm_night; } | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|   void control(const alarm_control_panel::AlarmControlPanelCall &call) override; |   void control(const alarm_control_panel::AlarmControlPanelCall &call) override; | ||||||
| #ifdef USE_BINARY_SENSOR | #ifdef USE_BINARY_SENSOR | ||||||
| @@ -97,6 +106,8 @@ class TemplateAlarmControlPanel : public alarm_control_panel::AlarmControlPanel, | |||||||
|   uint32_t arming_away_time_; |   uint32_t arming_away_time_; | ||||||
|   // the arming home delay |   // the arming home delay | ||||||
|   uint32_t arming_home_time_{0}; |   uint32_t arming_home_time_{0}; | ||||||
|  |   // the arming night delay | ||||||
|  |   uint32_t arming_night_time_{0}; | ||||||
|   // the trigger delay |   // the trigger delay | ||||||
|   uint32_t pending_time_; |   uint32_t pending_time_; | ||||||
|   // the time in trigger |   // the time in trigger | ||||||
| @@ -106,6 +117,7 @@ class TemplateAlarmControlPanel : public alarm_control_panel::AlarmControlPanel, | |||||||
|   // requires a code to arm |   // requires a code to arm | ||||||
|   bool requires_code_to_arm_ = false; |   bool requires_code_to_arm_ = false; | ||||||
|   bool supports_arm_home_ = false; |   bool supports_arm_home_ = false; | ||||||
|  |   bool supports_arm_night_ = false; | ||||||
|   // check if the code is valid |   // check if the code is valid | ||||||
|   bool is_code_valid_(optional<std::string> code); |   bool is_code_valid_(optional<std::string> code); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1194,12 +1194,14 @@ alarm_control_panel: | |||||||
|       - "1234" |       - "1234" | ||||||
|     requires_code_to_arm: true |     requires_code_to_arm: true | ||||||
|     arming_home_time: 1s |     arming_home_time: 1s | ||||||
|  |     arming_night_time: 1s | ||||||
|     arming_away_time: 15s |     arming_away_time: 15s | ||||||
|     pending_time: 15s |     pending_time: 15s | ||||||
|     trigger_time: 30s |     trigger_time: 30s | ||||||
|     binary_sensors: |     binary_sensors: | ||||||
|       - input: bin1 |       - input: bin1 | ||||||
|         bypass_armed_home: true |         bypass_armed_home: true | ||||||
|  |         bypass_armed_night: true | ||||||
|     on_state: |     on_state: | ||||||
|       then: |       then: | ||||||
|         - lambda: !lambda |- |         - lambda: !lambda |- | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user