Home Assistant Unofficial Reference 2024.12.1
binary_sensor.py
Go to the documentation of this file.
1 """Support for custom shell commands to retrieve values."""
2 
3 from __future__ import annotations
4 
5 import asyncio
6 from datetime import datetime, timedelta
7 from typing import cast
8 
9 from homeassistant.components.binary_sensor import BinarySensorEntity
10 from homeassistant.const import (
11  CONF_COMMAND,
12  CONF_NAME,
13  CONF_PAYLOAD_OFF,
14  CONF_PAYLOAD_ON,
15  CONF_SCAN_INTERVAL,
16  CONF_VALUE_TEMPLATE,
17 )
18 from homeassistant.core import HomeAssistant
19 from homeassistant.helpers.entity_platform import AddEntitiesCallback
20 from homeassistant.helpers.event import async_track_time_interval
21 from homeassistant.helpers.template import Template
22 from homeassistant.helpers.trigger_template_entity import ManualTriggerEntity
23 from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
24 from homeassistant.util import dt as dt_util
25 
26 from .const import CONF_COMMAND_TIMEOUT, LOGGER, TRIGGER_ENTITY_OPTIONS
27 from .sensor import CommandSensorData
28 
29 DEFAULT_NAME = "Binary Command Sensor"
30 DEFAULT_PAYLOAD_ON = "ON"
31 DEFAULT_PAYLOAD_OFF = "OFF"
32 
33 SCAN_INTERVAL = timedelta(seconds=60)
34 
35 
37  hass: HomeAssistant,
38  config: ConfigType,
39  async_add_entities: AddEntitiesCallback,
40  discovery_info: DiscoveryInfoType | None = None,
41 ) -> None:
42  """Set up the Command line Binary Sensor."""
43  if not discovery_info:
44  return
45 
46  discovery_info = cast(DiscoveryInfoType, discovery_info)
47  binary_sensor_config = discovery_info
48 
49  command: str = binary_sensor_config[CONF_COMMAND]
50  payload_off: str = binary_sensor_config[CONF_PAYLOAD_OFF]
51  payload_on: str = binary_sensor_config[CONF_PAYLOAD_ON]
52  command_timeout: int = binary_sensor_config[CONF_COMMAND_TIMEOUT]
53  scan_interval: timedelta = binary_sensor_config.get(
54  CONF_SCAN_INTERVAL, SCAN_INTERVAL
55  )
56  value_template: Template | None = binary_sensor_config.get(CONF_VALUE_TEMPLATE)
57 
58  data = CommandSensorData(hass, command, command_timeout)
59 
60  trigger_entity_config = {
61  CONF_NAME: Template(binary_sensor_config.get(CONF_NAME, DEFAULT_NAME), hass),
62  **{
63  k: v for k, v in binary_sensor_config.items() if k in TRIGGER_ENTITY_OPTIONS
64  },
65  }
66 
68  [
70  data,
71  trigger_entity_config,
72  payload_on,
73  payload_off,
74  value_template,
75  scan_interval,
76  )
77  ],
78  )
79 
80 
82  """Representation of a command line binary sensor."""
83 
84  _attr_should_poll = False
85 
86  def __init__(
87  self,
88  data: CommandSensorData,
89  config: ConfigType,
90  payload_on: str,
91  payload_off: str,
92  value_template: Template | None,
93  scan_interval: timedelta,
94  ) -> None:
95  """Initialize the Command line binary sensor."""
96  super().__init__(self.hasshasshass, config)
97  self.datadata = data
98  self._attr_is_on_attr_is_on = None
99  self._payload_on_payload_on = payload_on
100  self._payload_off_payload_off = payload_off
101  self._value_template_value_template = value_template
102  self._scan_interval_scan_interval = scan_interval
103  self._process_updates_process_updates: asyncio.Lock | None = None
104 
105  async def async_added_to_hass(self) -> None:
106  """Call when entity about to be added to hass."""
107  await super().async_added_to_hass()
108  await self._update_entity_state_update_entity_state()
109  self.async_on_removeasync_on_remove(
111  self.hasshasshass,
112  self._update_entity_state_update_entity_state,
113  self._scan_interval_scan_interval,
114  name=f"Command Line Binary Sensor - {self.name}",
115  cancel_on_shutdown=True,
116  ),
117  )
118 
119  async def _update_entity_state(self, now: datetime | None = None) -> None:
120  """Update the state of the entity."""
121  if self._process_updates_process_updates is None:
122  self._process_updates_process_updates = asyncio.Lock()
123  if self._process_updates_process_updates.locked():
124  LOGGER.warning(
125  "Updating Command Line Binary Sensor %s took longer than the scheduled update interval %s",
126  self.namenamename,
127  self._scan_interval_scan_interval,
128  )
129  return
130 
131  async with self._process_updates_process_updates:
132  await self._async_update_async_update()
133 
134  async def _async_update(self) -> None:
135  """Get the latest data and updates the state."""
136  await self.datadata.async_update()
137  value = self.datadata.value
138 
139  if self._value_template_value_template is not None:
140  value = self._value_template_value_template.async_render_with_possible_json_value(
141  value, None
142  )
143  self._attr_is_on_attr_is_on = None
144  if value == self._payload_on_payload_on:
145  self._attr_is_on_attr_is_on = True
146  elif value == self._payload_off_payload_off:
147  self._attr_is_on_attr_is_on = False
148 
149  self._process_manual_data_process_manual_data(value)
150  self.async_write_ha_stateasync_write_ha_state()
151 
152  async def async_update(self) -> None:
153  """Update the entity.
154 
155  Only used by the generic entity update service.
156  """
157  await self._update_entity_state_update_entity_state(dt_util.now())
None __init__(self, CommandSensorData data, ConfigType config, str payload_on, str payload_off, Template|None value_template, timedelta scan_interval)
None async_on_remove(self, CALLBACK_TYPE func)
Definition: entity.py:1331
str|UndefinedType|None name(self)
Definition: entity.py:738
None async_setup_platform(HomeAssistant hass, ConfigType config, AddEntitiesCallback async_add_entities, DiscoveryInfoType|None discovery_info=None)
CALLBACK_TYPE async_track_time_interval(HomeAssistant hass, Callable[[datetime], Coroutine[Any, Any, None]|None] action, timedelta interval, *str|None name=None, bool|None cancel_on_shutdown=None)
Definition: event.py:1679