Home Assistant Unofficial Reference 2024.12.1
switch.py
Go to the documentation of this file.
1 """Support for wake on lan."""
2 
3 from __future__ import annotations
4 
5 import logging
6 import subprocess as sp
7 from typing import Any
8 
9 import voluptuous as vol
10 import wakeonlan
11 
13  PLATFORM_SCHEMA as SWITCH_PLATFORM_SCHEMA,
14  SwitchEntity,
15 )
16 from homeassistant.const import (
17  CONF_BROADCAST_ADDRESS,
18  CONF_BROADCAST_PORT,
19  CONF_HOST,
20  CONF_MAC,
21  CONF_NAME,
22 )
23 from homeassistant.core import HomeAssistant
24 from homeassistant.helpers import device_registry as dr
26 from homeassistant.helpers.entity_platform import AddEntitiesCallback
27 from homeassistant.helpers.script import Script
28 from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
29 
30 from .const import CONF_OFF_ACTION, DEFAULT_NAME, DEFAULT_PING_TIMEOUT, DOMAIN
31 
32 _LOGGER = logging.getLogger(__name__)
33 
34 PLATFORM_SCHEMA = SWITCH_PLATFORM_SCHEMA.extend(
35  {
36  vol.Required(CONF_MAC): cv.string,
37  vol.Optional(CONF_BROADCAST_ADDRESS): cv.string,
38  vol.Optional(CONF_BROADCAST_PORT): cv.port,
39  vol.Optional(CONF_HOST): cv.string,
40  vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
41  vol.Optional(CONF_OFF_ACTION): cv.SCRIPT_SCHEMA,
42  }
43 )
44 
45 
47  hass: HomeAssistant,
48  config: ConfigType,
49  async_add_entities: AddEntitiesCallback,
50  discovery_info: DiscoveryInfoType | None = None,
51 ) -> None:
52  """Set up a wake on lan switch."""
53  broadcast_address: str | None = config.get(CONF_BROADCAST_ADDRESS)
54  broadcast_port: int | None = config.get(CONF_BROADCAST_PORT)
55  host: str | None = config.get(CONF_HOST)
56  mac_address: str = config[CONF_MAC]
57  name: str = config[CONF_NAME]
58  off_action: list[Any] | None = config.get(CONF_OFF_ACTION)
59 
61  [
62  WolSwitch(
63  hass,
64  name,
65  host,
66  mac_address,
67  off_action,
68  broadcast_address,
69  broadcast_port,
70  )
71  ],
72  host is not None,
73  )
74 
75 
77  """Representation of a wake on lan switch."""
78 
79  def __init__(
80  self,
81  hass: HomeAssistant,
82  name: str,
83  host: str | None,
84  mac_address: str,
85  off_action: list[Any] | None,
86  broadcast_address: str | None,
87  broadcast_port: int | None,
88  ) -> None:
89  """Initialize the WOL switch."""
90  self._attr_name_attr_name = name
91  self._host_host = host
92  self._mac_address_mac_address = mac_address
93  self._broadcast_address_broadcast_address = broadcast_address
94  self._broadcast_port_broadcast_port = broadcast_port
95  self._off_script_off_script = (
96  Script(hass, off_action, name, DOMAIN) if off_action else None
97  )
98  self._state_state = False
99  self._attr_assumed_state_attr_assumed_state = host is None
100  self._attr_should_poll_attr_should_poll = bool(not self._attr_assumed_state_attr_assumed_state)
101  self._attr_unique_id_attr_unique_id = dr.format_mac(mac_address)
102 
103  @property
104  def is_on(self) -> bool:
105  """Return true if switch is on."""
106  return self._state_state
107 
108  def turn_on(self, **kwargs: Any) -> None:
109  """Turn the device on."""
110  service_kwargs: dict[str, Any] = {}
111  if self._broadcast_address_broadcast_address is not None:
112  service_kwargs["ip_address"] = self._broadcast_address_broadcast_address
113  if self._broadcast_port_broadcast_port is not None:
114  service_kwargs["port"] = self._broadcast_port_broadcast_port
115 
116  _LOGGER.debug(
117  "Send magic packet to mac %s (broadcast: %s, port: %s)",
118  self._mac_address_mac_address,
119  self._broadcast_address_broadcast_address,
120  self._broadcast_port_broadcast_port,
121  )
122 
123  wakeonlan.send_magic_packet(self._mac_address_mac_address, **service_kwargs)
124 
125  if self._attr_assumed_state_attr_assumed_state:
126  self._state_state = True
127  self.schedule_update_ha_stateschedule_update_ha_state()
128 
129  def turn_off(self, **kwargs: Any) -> None:
130  """Turn the device off if an off action is present."""
131  if self._off_script_off_script is not None:
132  self._off_script_off_script.run(context=self._context_context)
133 
134  if self._attr_assumed_state_attr_assumed_state:
135  self._state_state = False
136  self.schedule_update_ha_stateschedule_update_ha_state()
137 
138  def update(self) -> None:
139  """Check if device is on and update the state. Only called if assumed state is false."""
140  ping_cmd = [
141  "ping",
142  "-c",
143  "1",
144  "-W",
145  str(DEFAULT_PING_TIMEOUT),
146  str(self._host_host),
147  ]
148 
149  status = sp.call(ping_cmd, stdout=sp.DEVNULL, stderr=sp.DEVNULL)
150  self._state_state = not bool(status)
None __init__(self, HomeAssistant hass, str name, str|None host, str mac_address, list[Any]|None off_action, str|None broadcast_address, int|None broadcast_port)
Definition: switch.py:88
None schedule_update_ha_state(self, bool force_refresh=False)
Definition: entity.py:1244
None async_setup_platform(HomeAssistant hass, ConfigType config, AddEntitiesCallback async_add_entities, DiscoveryInfoType|None discovery_info=None)
Definition: switch.py:51
int run(RuntimeConfig runtime_config)
Definition: runner.py:146