Home Assistant Unofficial Reference 2024.12.1
entity.py
Go to the documentation of this file.
1 """Base class for pilight."""
2 
3 import voluptuous as vol
4 
5 from homeassistant.const import (
6  CONF_ID,
7  CONF_NAME,
8  CONF_PROTOCOL,
9  CONF_STATE,
10  STATE_OFF,
11  STATE_ON,
12 )
14 from homeassistant.helpers.restore_state import RestoreEntity
15 
16 from . import DOMAIN, EVENT, SERVICE_NAME
17 from .const import (
18  CONF_ECHO,
19  CONF_OFF,
20  CONF_OFF_CODE,
21  CONF_OFF_CODE_RECEIVE,
22  CONF_ON,
23  CONF_ON_CODE,
24  CONF_ON_CODE_RECEIVE,
25  CONF_SYSTEMCODE,
26  CONF_UNIT,
27  CONF_UNITCODE,
28 )
29 
30 COMMAND_SCHEMA = vol.Schema(
31  {
32  vol.Optional(CONF_PROTOCOL): cv.string,
33  vol.Optional(CONF_ON): cv.positive_int,
34  vol.Optional(CONF_OFF): cv.positive_int,
35  vol.Optional(CONF_UNIT): cv.positive_int,
36  vol.Optional(CONF_UNITCODE): cv.positive_int,
37  vol.Optional(CONF_ID): vol.Any(cv.positive_int, cv.string),
38  vol.Optional(CONF_STATE): vol.Any(STATE_ON, STATE_OFF),
39  vol.Optional(CONF_SYSTEMCODE): cv.positive_int,
40  },
41  extra=vol.ALLOW_EXTRA,
42 )
43 
44 RECEIVE_SCHEMA = COMMAND_SCHEMA.extend({vol.Optional(CONF_ECHO): cv.boolean})
45 
46 SWITCHES_SCHEMA = vol.Schema(
47  {
48  vol.Required(CONF_ON_CODE): COMMAND_SCHEMA,
49  vol.Required(CONF_OFF_CODE): COMMAND_SCHEMA,
50  vol.Optional(CONF_NAME): cv.string,
51  vol.Optional(CONF_OFF_CODE_RECEIVE): vol.All(cv.ensure_list, [COMMAND_SCHEMA]),
52  vol.Optional(CONF_ON_CODE_RECEIVE): vol.All(cv.ensure_list, [COMMAND_SCHEMA]),
53  }
54 )
55 
56 
58  """Base class for pilight switches and lights."""
59 
60  _attr_should_poll = False
61 
62  def __init__(self, hass, name, config):
63  """Initialize a device."""
64  self._hass_hass = hass
65  self._name_name = config.get(CONF_NAME, name)
66  self._is_on_is_on = False
67  self._code_on_code_on = config.get(CONF_ON_CODE)
68  self._code_off_code_off = config.get(CONF_OFF_CODE)
69 
70  code_on_receive = config.get(CONF_ON_CODE_RECEIVE, [])
71  code_off_receive = config.get(CONF_OFF_CODE_RECEIVE, [])
72 
73  self._code_on_receive_code_on_receive = []
74  self._code_off_receive_code_off_receive = []
75 
76  for code_list, conf in (
77  (self._code_on_receive_code_on_receive, code_on_receive),
78  (self._code_off_receive_code_off_receive, code_off_receive),
79  ):
80  for code in conf:
81  echo = code.pop(CONF_ECHO, True)
82  code_list.append(_ReceiveHandle(code, echo))
83 
84  if any(self._code_on_receive_code_on_receive) or any(self._code_off_receive_code_off_receive):
85  hass.bus.listen(EVENT, self._handle_code_handle_code)
86 
87  self._brightness_brightness = 255
88 
89  async def async_added_to_hass(self):
90  """Call when entity about to be added to hass."""
91  await super().async_added_to_hass()
92  if state := await self.async_get_last_stateasync_get_last_state():
93  self._is_on_is_on = state.state == STATE_ON
94  self._brightness_brightness = state.attributes.get("brightness")
95 
96  @property
97  def name(self):
98  """Get the name of the switch."""
99  return self._name_name
100 
101  @property
102  def assumed_state(self):
103  """Return True if unable to access real state of the entity."""
104  return True
105 
106  @property
107  def is_on(self):
108  """Return true if switch is on."""
109  return self._is_on_is_on
110 
111  def _handle_code(self, call):
112  """Check if received code by the pilight-daemon.
113 
114  If the code matches the receive on/off codes of this switch the switch
115  state is changed accordingly.
116  """
117  # - True if off_code/on_code is contained in received code dict, not
118  # all items have to match.
119  # - Call turn on/off only once, even if more than one code is received
120  if any(self._code_on_receive_code_on_receive):
121  for on_code in self._code_on_receive_code_on_receive:
122  if on_code.match(call.data):
123  on_code.run(switch=self, turn_on=True)
124  break
125 
126  if any(self._code_off_receive_code_off_receive):
127  for off_code in self._code_off_receive_code_off_receive:
128  if off_code.match(call.data):
129  off_code.run(switch=self, turn_on=False)
130  break
131 
132  def set_state(self, turn_on, send_code=True, dimlevel=None):
133  """Set the state of the switch.
134 
135  This sets the state of the switch. If send_code is set to True, then
136  it will call the pilight.send service to actually send the codes
137  to the pilight daemon.
138  """
139  if send_code:
140  if turn_on:
141  code = self._code_on_code_on
142  if dimlevel is not None:
143  code.update({"dimlevel": dimlevel})
144 
145  self._hass_hass.services.call(DOMAIN, SERVICE_NAME, code, blocking=True)
146  else:
147  self._hass_hass.services.call(
148  DOMAIN, SERVICE_NAME, self._code_off_code_off, blocking=True
149  )
150 
151  self._is_on_is_on = turn_on
152  self.schedule_update_ha_stateschedule_update_ha_state()
153 
154  def turn_on(self, **kwargs):
155  """Turn the switch on by calling pilight.send service with on code."""
156  self.set_stateset_state(turn_on=True)
157 
158  def turn_off(self, **kwargs):
159  """Turn the switch on by calling pilight.send service with off code."""
160  self.set_stateset_state(turn_on=False)
161 
162 
164  def __init__(self, config, echo):
165  """Initialize the handle."""
166  self.config_itemsconfig_items = config.items()
167  self.echoecho = echo
168 
169  def match(self, code):
170  """Test if the received code matches the configured values.
171 
172  The received values have to be a subset of the configured options.
173  """
174  return self.config_itemsconfig_items <= code.items()
175 
176  def run(self, switch, turn_on):
177  """Change the state of the switch."""
178  switch.set_state(turn_on=turn_on, send_code=self.echoecho)
def set_state(self, turn_on, send_code=True, dimlevel=None)
Definition: entity.py:132
None schedule_update_ha_state(self, bool force_refresh=False)
Definition: entity.py:1244