Home Assistant Unofficial Reference 2024.12.1
switch.py
Go to the documentation of this file.
1 """The Netio switch component."""
2 
3 from __future__ import annotations
4 
5 from collections import namedtuple
6 from datetime import timedelta
7 import logging
8 from typing import Any
9 
10 from pynetio import Netio
11 import voluptuous as vol
12 
13 from homeassistant import util
14 from homeassistant.components.http import HomeAssistantView
16  PLATFORM_SCHEMA as SWITCH_PLATFORM_SCHEMA,
17  SwitchEntity,
18 )
19 from homeassistant.const import (
20  CONF_HOST,
21  CONF_PASSWORD,
22  CONF_PORT,
23  CONF_USERNAME,
24  EVENT_HOMEASSISTANT_STOP,
25  STATE_ON,
26 )
27 from homeassistant.core import HomeAssistant, callback
29 from homeassistant.helpers.entity_platform import AddEntitiesCallback
30 from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
31 
32 _LOGGER = logging.getLogger(__name__)
33 
34 ATTR_START_DATE = "start_date"
35 ATTR_TOTAL_CONSUMPTION_KWH = "total_energy_kwh"
36 
37 CONF_OUTLETS = "outlets"
38 
39 DEFAULT_PORT = 1234
40 DEFAULT_USERNAME = "admin"
41 Device = namedtuple("Device", ["netio", "entities"]) # noqa: PYI024
42 DEVICES: dict[str, Device] = {}
43 
44 MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10)
45 
46 REQ_CONF = [CONF_HOST, CONF_OUTLETS]
47 
48 URL_API_NETIO_EP = "/api/netio/{host}"
49 
50 PLATFORM_SCHEMA = SWITCH_PLATFORM_SCHEMA.extend(
51  {
52  vol.Required(CONF_HOST): cv.string,
53  vol.Required(CONF_PORT, default=DEFAULT_PORT): cv.port,
54  vol.Required(CONF_USERNAME, default=DEFAULT_USERNAME): cv.string,
55  vol.Required(CONF_PASSWORD): cv.string,
56  vol.Optional(CONF_OUTLETS): {cv.string: cv.string},
57  }
58 )
59 
60 
62  hass: HomeAssistant,
63  config: ConfigType,
64  add_entities: AddEntitiesCallback,
65  discovery_info: DiscoveryInfoType | None = None,
66 ) -> None:
67  """Set up the Netio platform."""
68 
69  host = config[CONF_HOST]
70  username = config[CONF_USERNAME]
71  password = config[CONF_PASSWORD]
72  port = config[CONF_PORT]
73 
74  if not DEVICES:
75  hass.http.register_view(NetioApiView)
76 
77  dev = Netio(host, port, username, password)
78 
79  DEVICES[host] = Device(dev, [])
80 
81  # Throttle the update for all Netio switches of one Netio
82  dev.update = util.Throttle(MIN_TIME_BETWEEN_SCANS)(dev.update)
83 
84  for key in config[CONF_OUTLETS]:
85  switch = NetioSwitch(DEVICES[host].netio, key, config[CONF_OUTLETS][key])
86  DEVICES[host].entities.append(switch)
87 
88  add_entities(DEVICES[host].entities)
89 
90  hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, dispose)
91 
92 
93 def dispose(event):
94  """Close connections to Netio Devices."""
95  for value in DEVICES.values():
96  value.netio.stop()
97 
98 
99 class NetioApiView(HomeAssistantView):
100  """WSGI handler class."""
101 
102  url = URL_API_NETIO_EP
103  name = "api:netio"
104 
105  @callback
106  def get(self, request, host):
107  """Request handler."""
108  data = request.query
109  states, consumptions, cumulated_consumptions, start_dates = [], [], [], []
110 
111  for i in range(1, 5):
112  out = f"output{i}"
113  states.append(data.get(f"{out}_state") == STATE_ON)
114  consumptions.append(float(data.get(f"{out}_consumption", 0)))
115  cumulated_consumptions.append(
116  float(data.get(f"{out}_cumulatedConsumption", 0)) / 1000
117  )
118  start_dates.append(data.get(f"{out}_consumptionStart", ""))
119 
120  _LOGGER.debug(
121  "%s: %s, %s, %s since %s",
122  host,
123  states,
124  consumptions,
125  cumulated_consumptions,
126  start_dates,
127  )
128 
129  ndev = DEVICES[host].netio
130  ndev.consumptions = consumptions
131  ndev.cumulated_consumptions = cumulated_consumptions
132  ndev.states = states
133  ndev.start_dates = start_dates
134 
135  for dev in DEVICES[host].entities:
136  dev.async_write_ha_state()
137 
138  return self.json(True)
139 
140 
142  """Provide a Netio linked switch."""
143 
144  def __init__(self, netio, outlet, name):
145  """Initialize the Netio switch."""
146  self._name_name = name
147  self.outletoutlet = outlet
148  self.netionetio = netio
149 
150  @property
151  def name(self):
152  """Return the device's name."""
153  return self._name_name
154 
155  @property
156  def available(self) -> bool:
157  """Return true if entity is available."""
158  return not hasattr(self, "telnet")
159 
160  def turn_on(self, **kwargs: Any) -> None:
161  """Turn switch on."""
162  self._set_set(True)
163 
164  def turn_off(self, **kwargs: Any) -> None:
165  """Turn switch off."""
166  self._set_set(False)
167 
168  def _set(self, value):
169  val = list("uuuu")
170  val[int(self.outletoutlet) - 1] = "1" if value else "0"
171  val = "".join(val)
172  self.netionetio.get(f"port list {val}")
173  self.netionetio.states[int(self.outletoutlet) - 1] = value
174  self.schedule_update_ha_stateschedule_update_ha_state()
175 
176  @property
177  def is_on(self):
178  """Return the switch's status."""
179  return self.netionetio.states[int(self.outletoutlet) - 1]
180 
181  def update(self) -> None:
182  """Update the state."""
183  self.netionetio.update()
def __init__(self, netio, outlet, name)
Definition: switch.py:144
None schedule_update_ha_state(self, bool force_refresh=False)
Definition: entity.py:1244
None add_entities(AsusWrtRouter router, AddEntitiesCallback async_add_entities, set[str] tracked)
web.Response get(self, web.Request request, str config_key)
Definition: view.py:88
None setup_platform(HomeAssistant hass, ConfigType config, AddEntitiesCallback add_entities, DiscoveryInfoType|None discovery_info=None)
Definition: switch.py:66