Home Assistant Unofficial Reference 2024.12.1
switch.py
Go to the documentation of this file.
1 """Support for EnOcean switches."""
2 
3 from __future__ import annotations
4 
5 from typing import Any
6 
7 from enocean.utils import combine_hex
8 import voluptuous as vol
9 
11  PLATFORM_SCHEMA as SWITCH_PLATFORM_SCHEMA,
12  SwitchEntity,
13 )
14 from homeassistant.const import CONF_ID, CONF_NAME, Platform
15 from homeassistant.core import HomeAssistant
16 from homeassistant.helpers import config_validation as cv, entity_registry as er
17 from homeassistant.helpers.entity_platform import AddEntitiesCallback
18 from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
19 
20 from .const import DOMAIN, LOGGER
21 from .entity import EnOceanEntity
22 
23 CONF_CHANNEL = "channel"
24 DEFAULT_NAME = "EnOcean Switch"
25 
26 PLATFORM_SCHEMA = SWITCH_PLATFORM_SCHEMA.extend(
27  {
28  vol.Required(CONF_ID): vol.All(cv.ensure_list, [vol.Coerce(int)]),
29  vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
30  vol.Optional(CONF_CHANNEL, default=0): cv.positive_int,
31  }
32 )
33 
34 
35 def generate_unique_id(dev_id: list[int], channel: int) -> str:
36  """Generate a valid unique id."""
37  return f"{combine_hex(dev_id)}-{channel}"
38 
39 
40 def _migrate_to_new_unique_id(hass: HomeAssistant, dev_id, channel) -> None:
41  """Migrate old unique ids to new unique ids."""
42  old_unique_id = f"{combine_hex(dev_id)}"
43 
44  ent_reg = er.async_get(hass)
45  entity_id = ent_reg.async_get_entity_id(Platform.SWITCH, DOMAIN, old_unique_id)
46 
47  if entity_id is not None:
48  new_unique_id = generate_unique_id(dev_id, channel)
49  try:
50  ent_reg.async_update_entity(entity_id, new_unique_id=new_unique_id)
51  except ValueError:
52  LOGGER.warning(
53  "Skip migration of id [%s] to [%s] because it already exists",
54  old_unique_id,
55  new_unique_id,
56  )
57  else:
58  LOGGER.debug(
59  "Migrating unique_id from [%s] to [%s]",
60  old_unique_id,
61  new_unique_id,
62  )
63 
64 
66  hass: HomeAssistant,
67  config: ConfigType,
68  async_add_entities: AddEntitiesCallback,
69  discovery_info: DiscoveryInfoType | None = None,
70 ) -> None:
71  """Set up the EnOcean switch platform."""
72  channel: int = config[CONF_CHANNEL]
73  dev_id: list[int] = config[CONF_ID]
74  dev_name: str = config[CONF_NAME]
75 
76  _migrate_to_new_unique_id(hass, dev_id, channel)
77  async_add_entities([EnOceanSwitch(dev_id, dev_name, channel)])
78 
79 
81  """Representation of an EnOcean switch device."""
82 
83  _attr_is_on = False
84 
85  def __init__(self, dev_id: list[int], dev_name: str, channel: int) -> None:
86  """Initialize the EnOcean switch device."""
87  super().__init__(dev_id)
88  self._light_light = None
89  self.channelchannel = channel
90  self._attr_unique_id_attr_unique_id = generate_unique_id(dev_id, channel)
91  self._attr_name_attr_name = dev_name
92 
93  def turn_on(self, **kwargs: Any) -> None:
94  """Turn on the switch."""
95  optional = [0x03]
96  optional.extend(self.dev_iddev_id)
97  optional.extend([0xFF, 0x00])
98  self.send_commandsend_command(
99  data=[0xD2, 0x01, self.channelchannel & 0xFF, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00],
100  optional=optional,
101  packet_type=0x01,
102  )
103  self._attr_is_on_attr_is_on_attr_is_on = True
104 
105  def turn_off(self, **kwargs: Any) -> None:
106  """Turn off the switch."""
107  optional = [0x03]
108  optional.extend(self.dev_iddev_id)
109  optional.extend([0xFF, 0x00])
110  self.send_commandsend_command(
111  data=[0xD2, 0x01, self.channelchannel & 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
112  optional=optional,
113  packet_type=0x01,
114  )
115  self._attr_is_on_attr_is_on_attr_is_on = False
116 
117  def value_changed(self, packet):
118  """Update the internal state of the switch."""
119  if packet.data[0] == 0xA5:
120  # power meter telegram, turn on if > 10 watts
121  packet.parse_eep(0x12, 0x01)
122  if packet.parsed["DT"]["raw_value"] == 1:
123  raw_val = packet.parsed["MR"]["raw_value"]
124  divisor = packet.parsed["DIV"]["raw_value"]
125  watts = raw_val / (10**divisor)
126  if watts > 1:
127  self._attr_is_on_attr_is_on_attr_is_on = True
128  self.schedule_update_ha_stateschedule_update_ha_state()
129  elif packet.data[0] == 0xD2:
130  # actuator status telegram
131  packet.parse_eep(0x01, 0x01)
132  if packet.parsed["CMD"]["raw_value"] == 4:
133  channel = packet.parsed["IO"]["raw_value"]
134  output = packet.parsed["OV"]["raw_value"]
135  if channel == self.channelchannel:
136  self._attr_is_on_attr_is_on_attr_is_on = output > 0
137  self.schedule_update_ha_stateschedule_update_ha_state()
def send_command(self, data, optional, packet_type)
Definition: entity.py:36
None __init__(self, list[int] dev_id, str dev_name, int channel)
Definition: switch.py:85
None schedule_update_ha_state(self, bool force_refresh=False)
Definition: entity.py:1244
None _migrate_to_new_unique_id(HomeAssistant hass, dev_id, channel)
Definition: switch.py:40
str generate_unique_id(list[int] dev_id, int channel)
Definition: switch.py:35
None async_setup_platform(HomeAssistant hass, ConfigType config, AddEntitiesCallback async_add_entities, DiscoveryInfoType|None discovery_info=None)
Definition: switch.py:70