Home Assistant Unofficial Reference 2024.12.1
switch.py
Go to the documentation of this file.
1 """Switches for AVM Fritz!Box functions."""
2 
3 from __future__ import annotations
4 
5 import logging
6 from typing import Any
7 
8 from homeassistant.components.network import async_get_source_ip
9 from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription
10 from homeassistant.config_entries import ConfigEntry
11 from homeassistant.const import EntityCategory
12 from homeassistant.core import HomeAssistant
13 from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, DeviceInfo
14 from homeassistant.helpers.dispatcher import async_dispatcher_connect
15 from homeassistant.helpers.entity import Entity
16 from homeassistant.helpers.entity_platform import AddEntitiesCallback
17 from homeassistant.helpers.update_coordinator import CoordinatorEntity
18 from homeassistant.util import slugify
19 
20 from .const import (
21  DATA_FRITZ,
22  DOMAIN,
23  SWITCH_TYPE_DEFLECTION,
24  SWITCH_TYPE_PORTFORWARD,
25  SWITCH_TYPE_PROFILE,
26  SWITCH_TYPE_WIFINETWORK,
27  WIFI_STANDARD,
28  MeshRoles,
29 )
30 from .coordinator import (
31  AvmWrapper,
32  FritzData,
33  FritzDevice,
34  SwitchInfo,
35  device_filter_out_from_trackers,
36 )
37 from .entity import FritzBoxBaseEntity, FritzDeviceBase
38 
39 _LOGGER = logging.getLogger(__name__)
40 
41 
43  avm_wrapper: AvmWrapper, device_friendly_name: str
44 ) -> list[FritzBoxDeflectionSwitch]:
45  """Get list of deflection entities."""
46 
47  _LOGGER.debug("Setting up %s switches", SWITCH_TYPE_DEFLECTION)
48 
49  if not (call_deflections := avm_wrapper.data["call_deflections"]):
50  _LOGGER.debug("The FRITZ!Box has no %s options", SWITCH_TYPE_DEFLECTION)
51  return []
52 
53  return [
54  FritzBoxDeflectionSwitch(avm_wrapper, device_friendly_name, cd_id)
55  for cd_id in call_deflections
56  ]
57 
58 
60  avm_wrapper: AvmWrapper, device_friendly_name: str, local_ip: str
61 ) -> list[FritzBoxPortSwitch]:
62  """Get list of port forwarding entities."""
63 
64  _LOGGER.debug("Setting up %s switches", SWITCH_TYPE_PORTFORWARD)
65  entities_list: list[FritzBoxPortSwitch] = []
66  if not avm_wrapper.device_conn_type:
67  _LOGGER.debug("The FRITZ!Box has no %s options", SWITCH_TYPE_PORTFORWARD)
68  return []
69 
70  # Query port forwardings and setup a switch for each forward for the current device
71  resp = await avm_wrapper.async_get_num_port_mapping(avm_wrapper.device_conn_type)
72  if not resp:
73  _LOGGER.debug("The FRITZ!Box has no %s options", SWITCH_TYPE_PORTFORWARD)
74  return []
75 
76  port_forwards_count: int = resp["NewPortMappingNumberOfEntries"]
77 
78  _LOGGER.debug(
79  "Specific %s response: GetPortMappingNumberOfEntries=%s",
80  SWITCH_TYPE_PORTFORWARD,
81  port_forwards_count,
82  )
83 
84  _LOGGER.debug("IP source for %s is %s", avm_wrapper.host, local_ip)
85 
86  for i in range(port_forwards_count):
87  portmap = await avm_wrapper.async_get_port_mapping(
88  avm_wrapper.device_conn_type, i
89  )
90  if not portmap:
91  _LOGGER.debug("The FRITZ!Box has no %s options", SWITCH_TYPE_DEFLECTION)
92  continue
93 
94  _LOGGER.debug(
95  "Specific %s response: GetGenericPortMappingEntry=%s",
96  SWITCH_TYPE_PORTFORWARD,
97  portmap,
98  )
99 
100  # We can only handle port forwards of the given device
101  if portmap["NewInternalClient"] == local_ip:
102  port_name = portmap["NewPortMappingDescription"]
103  for entity in entities_list:
104  if entity.port_mapping and (
105  port_name in entity.port_mapping["NewPortMappingDescription"]
106  ):
107  port_name = f"{port_name} {portmap['NewExternalPort']}"
108  entities_list.append(
110  avm_wrapper,
111  device_friendly_name,
112  portmap,
113  port_name,
114  i,
115  avm_wrapper.device_conn_type,
116  )
117  )
118 
119  return entities_list
120 
121 
123  avm_wrapper: AvmWrapper, device_friendly_name: str
124 ) -> list[FritzBoxWifiSwitch]:
125  """Get list of wifi entities."""
126  _LOGGER.debug("Setting up %s switches", SWITCH_TYPE_WIFINETWORK)
127 
128  #
129  # https://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/wlanconfigSCPD.pdf
130  #
131  wifi_count = len(
132  [
133  s
134  for s in avm_wrapper.connection.services
135  if s.startswith("WLANConfiguration")
136  ]
137  )
138  _LOGGER.debug("WiFi networks count: %s", wifi_count)
139  networks: dict = {}
140  for i in range(1, wifi_count + 1):
141  network_info = await avm_wrapper.async_get_wlan_configuration(i)
142  # Devices with 4 WLAN services, use the 2nd for internal communications
143  if not (wifi_count == 4 and i == 2):
144  networks[i] = {
145  "ssid": network_info["NewSSID"],
146  "bssid": network_info["NewBSSID"],
147  "standard": network_info["NewStandard"],
148  "enabled": network_info["NewEnable"],
149  "status": network_info["NewStatus"],
150  }
151  for i, network in networks.copy().items():
152  networks[i]["switch_name"] = network["ssid"]
153  if (
154  len(
155  [
156  j
157  for j, n in networks.items()
158  if slugify(n["ssid"]) == slugify(network["ssid"])
159  ]
160  )
161  > 1
162  ):
163  networks[i]["switch_name"] += f" ({WIFI_STANDARD[i]})"
164 
165  _LOGGER.debug("WiFi networks list: %s", networks)
166  return [
167  FritzBoxWifiSwitch(avm_wrapper, device_friendly_name, index, data)
168  for index, data in networks.items()
169  ]
170 
171 
173  avm_wrapper: AvmWrapper,
174  data_fritz: FritzData,
175 ) -> list[FritzBoxProfileSwitch]:
176  """Add new tracker entities from the AVM device."""
177  _LOGGER.debug("Setting up %s switches", SWITCH_TYPE_PROFILE)
178 
179  new_profiles: list[FritzBoxProfileSwitch] = []
180 
181  if "X_AVM-DE_HostFilter1" not in avm_wrapper.connection.services:
182  return new_profiles
183 
184  if avm_wrapper.unique_id not in data_fritz.profile_switches:
185  data_fritz.profile_switches[avm_wrapper.unique_id] = set()
186 
187  for mac, device in avm_wrapper.devices.items():
189  mac, device, data_fritz.profile_switches.values()
190  ):
191  _LOGGER.debug(
192  "Skipping profile switch creation for device %s", device.hostname
193  )
194  continue
195 
196  new_profiles.append(FritzBoxProfileSwitch(avm_wrapper, device))
197  data_fritz.profile_switches[avm_wrapper.unique_id].add(mac)
198 
199  _LOGGER.debug("Creating %s profile switches", len(new_profiles))
200  return new_profiles
201 
202 
204  avm_wrapper: AvmWrapper,
205  device_friendly_name: str,
206  data_fritz: FritzData,
207  local_ip: str,
208 ) -> list[Entity]:
209  """Get a list of all entities."""
210 
211  if avm_wrapper.mesh_role == MeshRoles.SLAVE:
212  return []
213 
214  return [
215  *await _async_deflection_entities_list(avm_wrapper, device_friendly_name),
216  *await _async_port_entities_list(avm_wrapper, device_friendly_name, local_ip),
217  *await _async_wifi_entities_list(avm_wrapper, device_friendly_name),
218  *await _async_profile_entities_list(avm_wrapper, data_fritz),
219  ]
220 
221 
223  hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
224 ) -> None:
225  """Set up entry."""
226  _LOGGER.debug("Setting up switches")
227  avm_wrapper: AvmWrapper = hass.data[DOMAIN][entry.entry_id]
228  data_fritz: FritzData = hass.data[DATA_FRITZ]
229 
230  _LOGGER.debug("Fritzbox services: %s", avm_wrapper.connection.services)
231 
232  local_ip = await async_get_source_ip(avm_wrapper.hass, target_ip=avm_wrapper.host)
233 
234  entities_list = await async_all_entities_list(
235  avm_wrapper,
236  entry.title,
237  data_fritz,
238  local_ip,
239  )
240 
241  async_add_entities(entities_list)
242 
243  async def async_update_avm_device() -> None:
244  """Update the values of the AVM device."""
245  async_add_entities(await _async_profile_entities_list(avm_wrapper, data_fritz))
246 
247  entry.async_on_unload(
249  hass, avm_wrapper.signal_device_new, async_update_avm_device
250  )
251  )
252 
253 
254 class FritzBoxBaseCoordinatorSwitch(CoordinatorEntity[AvmWrapper], SwitchEntity):
255  """Fritz switch coordinator base class."""
256 
257  entity_description: SwitchEntityDescription
258  _attr_has_entity_name = True
259 
260  def __init__(
261  self,
262  avm_wrapper: AvmWrapper,
263  device_name: str,
264  description: SwitchEntityDescription,
265  ) -> None:
266  """Init device info class."""
267  super().__init__(avm_wrapper)
268  self.entity_descriptionentity_description = description
269  self._device_name_device_name = device_name
270  self._attr_unique_id_attr_unique_id = f"{avm_wrapper.unique_id}-{description.key}"
271 
272  @property
273  def device_info(self) -> DeviceInfo:
274  """Return the device information."""
275  return DeviceInfo(
276  configuration_url=f"http://{self.coordinator.host}",
277  connections={(CONNECTION_NETWORK_MAC, self.coordinator.mac)},
278  identifiers={(DOMAIN, self.coordinator.unique_id)},
279  manufacturer="AVM",
280  model=self.coordinator.model,
281  name=self._device_name_device_name,
282  sw_version=self.coordinator.current_firmware,
283  )
284 
285  @property
286  def data(self) -> dict[str, Any]:
287  """Return entity data from coordinator data."""
288  raise NotImplementedError
289 
290  @property
291  def available(self) -> bool:
292  """Return availability based on data availability."""
293  return super().available and bool(self.datadatadata)
294 
295  async def _async_handle_turn_on_off(self, turn_on: bool) -> None:
296  """Handle switch state change request."""
297  raise NotImplementedError
298 
299  async def async_turn_on(self, **kwargs: Any) -> None:
300  """Turn on switch."""
301  await self._async_handle_turn_on_off_async_handle_turn_on_off(turn_on=True)
302 
303  async def async_turn_off(self, **kwargs: Any) -> None:
304  """Turn off switch."""
305  await self._async_handle_turn_on_off_async_handle_turn_on_off(turn_on=False)
306 
307 
309  """Fritz switch base class."""
310 
311  def __init__(
312  self,
313  avm_wrapper: AvmWrapper,
314  device_friendly_name: str,
315  switch_info: SwitchInfo,
316  ) -> None:
317  """Init Fritzbox base switch."""
318  super().__init__(avm_wrapper, device_friendly_name)
319 
320  self._description_description = switch_info["description"]
321  self._friendly_name_friendly_name = switch_info["friendly_name"]
322  self._icon_icon = switch_info["icon"]
323  self._type_type = switch_info["type"]
324  self._update_update = switch_info["callback_update"]
325  self._switch_switch = switch_info["callback_switch"]
326  self._attr_is_on_attr_is_on = switch_info["init_state"]
327 
328  self._name_name = f"{self._friendly_name} {self._description}"
329  self._unique_id_unique_id = f"{self._avm_wrapper.unique_id}-{slugify(self._description)}"
330 
331  self._attributes: dict[str, str | None] = {}
332  self._is_available_is_available = True
333 
334  @property
335  def name(self) -> str:
336  """Return name."""
337  return self._name_name
338 
339  @property
340  def icon(self) -> str:
341  """Return name."""
342  return self._icon_icon
343 
344  @property
345  def unique_id(self) -> str:
346  """Return unique id."""
347  return self._unique_id_unique_id
348 
349  @property
350  def available(self) -> bool:
351  """Return availability."""
352  return self._is_available_is_available
353 
354  @property
355  def extra_state_attributes(self) -> dict[str, str | None]:
356  """Return device attributes."""
357  return self._attributes
358 
359  async def async_update(self) -> None:
360  """Update data."""
361  _LOGGER.debug("Updating '%s' (%s) switch state", self.namenamename, self._type_type)
362  await self._update_update()
363 
364  async def async_turn_on(self, **kwargs: Any) -> None:
365  """Turn on switch."""
366  await self._async_handle_turn_on_off_async_handle_turn_on_off(turn_on=True)
367 
368  async def async_turn_off(self, **kwargs: Any) -> None:
369  """Turn off switch."""
370  await self._async_handle_turn_on_off_async_handle_turn_on_off(turn_on=False)
371 
372  async def _async_handle_turn_on_off(self, turn_on: bool) -> None:
373  """Handle switch state change request."""
374  await self._switch_switch(turn_on)
375  self._attr_is_on_attr_is_on = turn_on
376 
377 
379  """Defines a FRITZ!Box Tools PortForward switch."""
380 
381  def __init__(
382  self,
383  avm_wrapper: AvmWrapper,
384  device_friendly_name: str,
385  port_mapping: dict[str, Any] | None,
386  port_name: str,
387  idx: int,
388  connection_type: str,
389  ) -> None:
390  """Init Fritzbox port switch."""
391  self._avm_wrapper_avm_wrapper_avm_wrapper = avm_wrapper
392 
393  self._attributes_attributes = {}
394  self.connection_typeconnection_type = connection_type
395  self.port_mappingport_mapping = port_mapping # dict in the format as it comes from fritzconnection. eg: {'NewRemoteHost': '0.0.0.0', 'NewExternalPort': 22, 'NewProtocol': 'TCP', 'NewInternalPort': 22, 'NewInternalClient': '192.168.178.31', 'NewEnabled': True, 'NewPortMappingDescription': 'Beast SSH ', 'NewLeaseDuration': 0}
396  self._idx_idx = idx # needed for update routine
397  self._attr_entity_category_attr_entity_category = EntityCategory.CONFIG
398 
399  if port_mapping is None:
400  return
401 
402  switch_info = SwitchInfo(
403  description=f"Port forward {port_name}",
404  friendly_name=device_friendly_name,
405  icon="mdi:check-network",
406  type=SWITCH_TYPE_PORTFORWARD,
407  callback_update=self._async_fetch_update_async_fetch_update,
408  callback_switch=self._async_switch_on_off_executor_async_switch_on_off_executor,
409  init_state=port_mapping["NewEnabled"],
410  )
411  super().__init__(avm_wrapper, device_friendly_name, switch_info)
412 
413  async def _async_fetch_update(self) -> None:
414  """Fetch updates."""
415 
416  self.port_mappingport_mapping = await self._avm_wrapper_avm_wrapper_avm_wrapper.async_get_port_mapping(
417  self.connection_typeconnection_type, self._idx_idx
418  )
419  _LOGGER.debug(
420  "Specific %s response: %s", SWITCH_TYPE_PORTFORWARD, self.port_mappingport_mapping
421  )
422  if not self.port_mappingport_mapping:
423  self._is_available_is_available_is_available = False
424  return
425 
426  self._attr_is_on_attr_is_on_attr_is_on = self.port_mappingport_mapping["NewEnabled"] is True
427  self._is_available_is_available_is_available = True
428 
429  attributes_dict = {
430  "NewInternalClient": "internal_ip",
431  "NewInternalPort": "internal_port",
432  "NewExternalPort": "external_port",
433  "NewProtocol": "protocol",
434  "NewPortMappingDescription": "description",
435  }
436 
437  for key, attr in attributes_dict.items():
438  self._attributes_attributes[attr] = self.port_mappingport_mapping[key]
439 
440  async def _async_switch_on_off_executor(self, turn_on: bool) -> bool:
441  if self.port_mappingport_mapping is None:
442  return False
443 
444  self.port_mappingport_mapping["NewEnabled"] = "1" if turn_on else "0"
445 
446  resp = await self._avm_wrapper_avm_wrapper_avm_wrapper.async_add_port_mapping(
447  self.connection_typeconnection_type, self.port_mappingport_mapping
448  )
449  return bool(resp is not None)
450 
451 
453  """Defines a FRITZ!Box Tools PortForward switch."""
454 
455  _attr_entity_category = EntityCategory.CONFIG
456 
457  def __init__(
458  self,
459  avm_wrapper: AvmWrapper,
460  device_friendly_name: str,
461  deflection_id: int,
462  ) -> None:
463  """Init Fritxbox Deflection class."""
464  self.deflection_iddeflection_id = deflection_id
465  description = SwitchEntityDescription(
466  key=f"call_deflection_{self.deflection_id}",
467  name=f"Call deflection {self.deflection_id}",
468  icon="mdi:phone-forward",
469  )
470  super().__init__(avm_wrapper, device_friendly_name, description)
471 
472  @property
473  def data(self) -> dict[str, Any]:
474  """Return call deflection data."""
475  return self.coordinator.data["call_deflections"].get(self.deflection_iddeflection_id, {})
476 
477  @property
478  def extra_state_attributes(self) -> dict[str, str]:
479  """Return device attributes."""
480  return {
481  "type": self.datadatadatadata["Type"],
482  "number": self.datadatadatadata["Number"],
483  "deflection_to_number": self.datadatadatadata["DeflectionToNumber"],
484  "mode": self.datadatadatadata["Mode"][1:],
485  "outgoing": self.datadatadatadata["Outgoing"],
486  "phonebook_id": self.datadatadatadata["PhonebookID"],
487  }
488 
489  @property
490  def is_on(self) -> bool | None:
491  """Switch status."""
492  return self.datadatadatadata.get("Enable") == "1"
493 
494  async def _async_handle_turn_on_off(self, turn_on: bool) -> None:
495  """Handle deflection switch."""
496  await self.coordinator.async_set_deflection_enable(self.deflection_iddeflection_id, turn_on)
497 
498 
500  """Defines a FRITZ!Box Tools DeviceProfile switch."""
501 
502  _attr_icon = "mdi:router-wireless-settings"
503 
504  def __init__(self, avm_wrapper: AvmWrapper, device: FritzDevice) -> None:
505  """Init Fritz profile."""
506  super().__init__(avm_wrapper, device)
507  self._attr_is_on: bool = False
508  self._name_name = f"{device.hostname} Internet Access"
509  self._attr_unique_id_attr_unique_id = f"{self._mac}_internet_access"
510  self._attr_entity_category_attr_entity_category = EntityCategory.CONFIG
511  self._attr_device_info_attr_device_info = DeviceInfo(
512  connections={(CONNECTION_NETWORK_MAC, self._mac)},
513  default_manufacturer="AVM",
514  default_model="FRITZ!Box Tracked device",
515  default_name=device.hostname,
516  via_device=(
517  DOMAIN,
518  avm_wrapper.unique_id,
519  ),
520  )
521 
522  @property
523  def is_on(self) -> bool | None:
524  """Switch status."""
525  return self._avm_wrapper_avm_wrapper.devices[self._mac].wan_access
526 
527  @property
528  def available(self) -> bool:
529  """Return availability of the switch."""
530  if self._avm_wrapper_avm_wrapper.devices[self._mac].wan_access is None:
531  return False
532  return super().available
533 
534  async def async_turn_on(self, **kwargs: Any) -> None:
535  """Turn on switch."""
536  await self._async_handle_turn_on_off_async_handle_turn_on_off(turn_on=True)
537 
538  async def async_turn_off(self, **kwargs: Any) -> None:
539  """Turn off switch."""
540  await self._async_handle_turn_on_off_async_handle_turn_on_off(turn_on=False)
541 
542  async def _async_handle_turn_on_off(self, turn_on: bool) -> bool:
543  """Handle switch state change request."""
544  if not self.ip_addressip_address:
545  return False
546  await self._avm_wrapper_avm_wrapper.async_set_allow_wan_access(self.ip_addressip_address, turn_on)
547  self.async_write_ha_stateasync_write_ha_state()
548  return True
549 
550 
552  """Defines a FRITZ!Box Tools Wifi switch."""
553 
554  def __init__(
555  self,
556  avm_wrapper: AvmWrapper,
557  device_friendly_name: str,
558  network_num: int,
559  network_data: dict,
560  ) -> None:
561  """Init Fritz Wifi switch."""
562  self._avm_wrapper_avm_wrapper_avm_wrapper = avm_wrapper
563 
564  self._attributes_attributes = {}
565  self._attr_entity_category_attr_entity_category = EntityCategory.CONFIG
566  self._network_num_network_num = network_num
567 
568  switch_info = SwitchInfo(
569  description=f"Wi-Fi {network_data['switch_name']}",
570  friendly_name=device_friendly_name,
571  icon="mdi:wifi",
572  type=SWITCH_TYPE_WIFINETWORK,
573  callback_update=self._async_fetch_update_async_fetch_update,
574  callback_switch=self._async_switch_on_off_executor_async_switch_on_off_executor,
575  init_state=network_data["enabled"],
576  )
577  super().__init__(self._avm_wrapper_avm_wrapper_avm_wrapper, device_friendly_name, switch_info)
578 
579  async def _async_fetch_update(self) -> None:
580  """Fetch updates."""
581 
582  wifi_info = await self._avm_wrapper_avm_wrapper_avm_wrapper.async_get_wlan_configuration(
583  self._network_num_network_num
584  )
585  _LOGGER.debug(
586  "Specific %s response: GetInfo=%s", SWITCH_TYPE_WIFINETWORK, wifi_info
587  )
588 
589  if not wifi_info:
590  self._is_available_is_available_is_available = False
591  return
592 
593  self._attr_is_on_attr_is_on_attr_is_on = wifi_info["NewEnable"] is True
594  self._is_available_is_available_is_available = True
595 
596  std = wifi_info["NewStandard"]
597  self._attributes_attributes["standard"] = std if std else None
598  self._attributes_attributes["bssid"] = wifi_info["NewBSSID"]
599  self._attributes_attributes["mac_address_control"] = wifi_info[
600  "NewMACAddressControlEnabled"
601  ]
602 
603  async def _async_switch_on_off_executor(self, turn_on: bool) -> None:
604  """Handle wifi switch."""
605  await self._avm_wrapper_avm_wrapper_avm_wrapper.async_set_wlan_configuration(self._network_num_network_num, turn_on)
dict[str, Any] async_set_allow_wan_access(self, str ip_address, bool turn_on)
Definition: coordinator.py:864
dict[str, Any] async_set_deflection_enable(self, int index, bool turn_on)
Definition: coordinator.py:839
None __init__(self, AvmWrapper avm_wrapper, str device_name, SwitchEntityDescription description)
Definition: switch.py:265
None __init__(self, AvmWrapper avm_wrapper, str device_friendly_name, SwitchInfo switch_info)
Definition: switch.py:316
None __init__(self, AvmWrapper avm_wrapper, str device_friendly_name, int deflection_id)
Definition: switch.py:462
None __init__(self, AvmWrapper avm_wrapper, str device_friendly_name, dict[str, Any]|None port_mapping, str port_name, int idx, str connection_type)
Definition: switch.py:389
bool _async_switch_on_off_executor(self, bool turn_on)
Definition: switch.py:440
None __init__(self, AvmWrapper avm_wrapper, FritzDevice device)
Definition: switch.py:504
None _async_switch_on_off_executor(self, bool turn_on)
Definition: switch.py:603
None __init__(self, AvmWrapper avm_wrapper, str device_friendly_name, int network_num, dict network_data)
Definition: switch.py:560
str|UndefinedType|None name(self)
Definition: entity.py:738
bool add(self, _T matcher)
Definition: match.py:185
web.Response get(self, web.Request request, str config_key)
Definition: view.py:88
bool device_filter_out_from_trackers(str mac, FritzDevice device, ValuesView current_devices)
Definition: coordinator.py:65
None async_setup_entry(HomeAssistant hass, ConfigEntry entry, AddEntitiesCallback async_add_entities)
Definition: switch.py:224
list[FritzBoxPortSwitch] _async_port_entities_list(AvmWrapper avm_wrapper, str device_friendly_name, str local_ip)
Definition: switch.py:61
list[FritzBoxWifiSwitch] _async_wifi_entities_list(AvmWrapper avm_wrapper, str device_friendly_name)
Definition: switch.py:124
list[Entity] async_all_entities_list(AvmWrapper avm_wrapper, str device_friendly_name, FritzData data_fritz, str local_ip)
Definition: switch.py:208
list[FritzBoxDeflectionSwitch] _async_deflection_entities_list(AvmWrapper avm_wrapper, str device_friendly_name)
Definition: switch.py:44
list[FritzBoxProfileSwitch] _async_profile_entities_list(AvmWrapper avm_wrapper, FritzData data_fritz)
Definition: switch.py:175
str async_get_source_ip(HomeAssistant hass, str|UndefinedType target_ip=UNDEFINED)
Definition: __init__.py:40
Callable[[], None] async_dispatcher_connect(HomeAssistant hass, str signal, Callable[..., Any] target)
Definition: dispatcher.py:103