1 """Class to hold all switch accessories."""
3 from __future__
import annotations
6 from typing
import Any, Final, NamedTuple
8 from pyhap.characteristic
import Characteristic
9 from pyhap.const
import (
21 DOMAIN
as VACUUM_DOMAIN,
22 SERVICE_RETURN_TO_BASE,
29 ATTR_SUPPORTED_FEATURES,
43 from .accessories
import TYPES, HomeAccessory, HomeDriver
59 from .util
import cleanup_name_for_homekit
61 _LOGGER = logging.getLogger(__name__)
63 VALVE_OPEN_STATES: Final = {STATE_OPEN, STATE_OPENING, STATE_CLOSING}
67 """Category and type information for valve."""
73 VALVE_TYPE: dict[str, ValveInfo] = {
74 TYPE_FAUCET:
ValveInfo(CATEGORY_FAUCET, 3),
75 TYPE_SHOWER:
ValveInfo(CATEGORY_SHOWER_HEAD, 2),
76 TYPE_SPRINKLER:
ValveInfo(CATEGORY_SPRINKLER, 1),
77 TYPE_VALVE:
ValveInfo(CATEGORY_FAUCET, 0),
81 ACTIVATE_ONLY_SWITCH_DOMAINS = {
"button",
"input_button",
"scene",
"script"}
83 ACTIVATE_ONLY_RESET_SECONDS = 10
86 @TYPES.register("Outlet")
88 """Generate an Outlet accessory."""
91 """Initialize an Outlet accessory object."""
92 super().
__init__(*args, category=CATEGORY_OUTLET)
96 serv_outlet = self.add_preload_service(SERV_OUTLET)
97 self.
char_onchar_on = serv_outlet.configure_char(
98 CHAR_ON, value=
False, setter_callback=self.
set_stateset_state
101 CHAR_OUTLET_IN_USE, value=
True
108 """Move switch state to value if call came from HomeKit."""
109 _LOGGER.debug(
"%s: Set switch state to %s", self.
entity_identity_id, value)
110 params = {ATTR_ENTITY_ID: self.
entity_identity_id}
111 service = SERVICE_TURN_ON
if value
else SERVICE_TURN_OFF
116 """Update switch state after state changed."""
117 current_state = new_state.state == STATE_ON
118 _LOGGER.debug(
"%s: Set current state to %s", self.
entity_identity_id, current_state)
119 self.
char_onchar_on.set_value(current_state)
122 @TYPES.register("Switch")
124 """Generate a Switch accessory."""
127 """Initialize a Switch accessory object."""
128 super().
__init__(*args, category=CATEGORY_SWITCH)
135 serv_switch = self.add_preload_service(SERV_SWITCH)
136 self.
char_onchar_on = serv_switch.configure_char(
137 CHAR_ON, value=
False, setter_callback=self.
set_stateset_state
144 """Check if entity is activate only."""
145 return self.
_domain_domain
in ACTIVATE_ONLY_SWITCH_DOMAINS
148 """Reset switch to emulate activate click."""
149 _LOGGER.debug(
"%s: Reset switch to off", self.
entity_identity_id)
150 self.
char_onchar_on.set_value(
False)
153 """Move switch state to value if call came from HomeKit."""
154 _LOGGER.debug(
"%s: Set switch state to %s", self.
entity_identity_id, value)
156 _LOGGER.debug(
"%s: Ignoring turn_off call", self.
entity_identity_id)
159 params = {ATTR_ENTITY_ID: self.
entity_identity_id}
163 elif self.
_domain_domain == button.DOMAIN:
164 service = button.SERVICE_PRESS
165 elif self.
_domain_domain == input_button.DOMAIN:
166 service = input_button.SERVICE_PRESS
168 service = SERVICE_TURN_ON
if value
else SERVICE_TURN_OFF
177 """Update switch state after state changed."""
181 "%s: Ignore state change, entity is activate only", self.
entity_identity_id
185 current_state = new_state.state == STATE_ON
186 _LOGGER.debug(
"%s: Set current state to %s", self.
entity_identity_id, current_state)
187 self.
char_onchar_on.set_value(current_state)
190 @TYPES.register("Vacuum")
192 """Generate a Switch accessory."""
195 """Move switch state to value if call came from HomeKit."""
196 _LOGGER.debug(
"%s: Set switch state to %s", self.
entity_identity_id, value)
200 features = state.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
203 sup_start = features & VacuumEntityFeature.START
204 service = SERVICE_START
if sup_start
else SERVICE_TURN_ON
206 sup_return_home = features & VacuumEntityFeature.RETURN_HOME
207 service = SERVICE_RETURN_TO_BASE
if sup_return_home
else SERVICE_TURN_OFF
210 VACUUM_DOMAIN, service, {ATTR_ENTITY_ID: self.
entity_identity_id}
215 """Update switch state after state changed."""
216 current_state = new_state.state
in (STATE_CLEANING, STATE_ON)
217 _LOGGER.debug(
"%s: Set current state to %s", self.
entity_identity_id, current_state)
218 self.
char_onchar_on.set_value(current_state)
222 """Valve base class."""
227 open_states: set[str],
233 """Initialize a Valve accessory object."""
244 serv_valve = self.add_preload_service(SERV_VALVE)
246 CHAR_ACTIVE, value=
False, setter_callback=self.
set_stateset_state
248 self.
char_in_usechar_in_use = serv_valve.configure_char(CHAR_IN_USE, value=
False)
250 CHAR_VALVE_TYPE, value=VALVE_TYPE[valve_type].valve_type
257 """Move value state to value if call came from HomeKit."""
258 _LOGGER.debug(
"%s: Set switch state to %s", self.
entity_identity_id, value)
260 params = {ATTR_ENTITY_ID: self.
entity_identity_id}
266 """Update switch state after state changed."""
267 current_state = 1
if new_state.state
in self.
open_statesopen_states
else 0
268 _LOGGER.debug(
"%s: Set active state to %s", self.
entity_identity_id, current_state)
269 self.
char_activechar_active.set_value(current_state)
270 _LOGGER.debug(
"%s: Set in_use state to %s", self.
entity_identity_id, current_state)
271 self.
char_in_usechar_in_use.set_value(current_state)
274 @TYPES.register("ValveSwitch")
276 """Generate a Valve accessory from a HomeAssistant switch."""
285 config: dict[str, Any],
288 """Initialize a Valve accessory object."""
304 @TYPES.register("Valve")
306 """Generate a Valve accessory from a HomeAssistant valve."""
309 """Initialize a Valve accessory object."""
319 @TYPES.register("SelectSwitch")
321 """Generate a Switch accessory that contains multiple switches."""
324 """Initialize a Switch accessory object."""
325 super().
__init__(*args, category=CATEGORY_SWITCH)
330 self.select_chars: dict[str, Characteristic] = {}
331 options = state.attributes[ATTR_OPTIONS]
332 for option
in options:
333 serv_option = self.add_preload_service(
334 SERV_OUTLET, [CHAR_NAME, CHAR_IN_USE], unique_id=option
336 serv_option.configure_char(
337 CHAR_NAME, value=cleanup_name_for_homekit(option)
339 serv_option.configure_char(CHAR_IN_USE, value=
False)
340 self.select_chars[option] = serv_option.configure_char(
343 setter_callback=
lambda value, option=option: self.
select_optionselect_option(option),
345 self.set_primary_service(self.select_chars[options[0]])
351 """Set option from HomeKit."""
352 _LOGGER.debug(
"%s: Set option to %s", self.
entity_identity_id, option)
353 params = {ATTR_ENTITY_ID: self.
entity_identity_id,
"option": option}
358 """Update switch state after state changed."""
359 current_option = cleanup_name_for_homekit(new_state.state)
360 for option, char
in self.select_chars.items():
361 char.set_value(option == current_option)
None async_call_service(self, str domain, str service, dict[str, Any]|None service_data, Any|None value=None)
None async_update_state(self, State new_state)
None async_update_state(self, State new_state)
None __init__(self, *Any args)
None set_state(self, bool value)
None select_option(self, str option)
None async_update_state(self, State new_state)
None __init__(self, *Any args)
None set_state(self, bool value)
None async_update_state(self, State new_state)
None reset_switch(self, *Any args)
bool is_activate(self, State state)
None __init__(self, *Any args)
None async_update_state(self, State new_state)
None set_state(self, bool value)
None async_update_state(self, State new_state)
None __init__(self, str valve_type, set[str] open_states, str on_service, str off_service, *Any args, **Any kwargs)
None set_state(self, bool value)
None __init__(self, HomeAssistant hass, HomeDriver driver, str name, str entity_id, int aid, dict[str, Any] config, *Any args)
None __init__(self, *Any args)
tuple[str, str] split_entity_id(str entity_id)
CALLBACK_TYPE async_call_later(HomeAssistant hass, float|timedelta delay, HassJob[[datetime], Coroutine[Any, Any, None]|None]|Callable[[datetime], Coroutine[Any, Any, None]|None] action)