Home Assistant Unofficial Reference 2024.12.1
cover.py
Go to the documentation of this file.
1 """Support for Modbus covers."""
2 
3 from __future__ import annotations
4 
5 from datetime import datetime
6 from typing import Any
7 
8 from homeassistant.components.cover import CoverEntity, CoverEntityFeature, CoverState
9 from homeassistant.const import CONF_COVERS, CONF_NAME, STATE_UNAVAILABLE, STATE_UNKNOWN
10 from homeassistant.core import HomeAssistant
11 from homeassistant.helpers.entity_platform import AddEntitiesCallback
12 from homeassistant.helpers.restore_state import RestoreEntity
13 from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
14 
15 from . import get_hub
16 from .const import (
17  CALL_TYPE_COIL,
18  CALL_TYPE_WRITE_COIL,
19  CALL_TYPE_WRITE_REGISTER,
20  CONF_STATE_CLOSED,
21  CONF_STATE_CLOSING,
22  CONF_STATE_OPEN,
23  CONF_STATE_OPENING,
24  CONF_STATUS_REGISTER,
25  CONF_STATUS_REGISTER_TYPE,
26 )
27 from .entity import BasePlatform
28 from .modbus import ModbusHub
29 
30 PARALLEL_UPDATES = 1
31 
32 
34  hass: HomeAssistant,
35  config: ConfigType,
36  async_add_entities: AddEntitiesCallback,
37  discovery_info: DiscoveryInfoType | None = None,
38 ) -> None:
39  """Read configuration and create Modbus cover."""
40  if discovery_info is None:
41  return
42 
43  covers = []
44  for cover in discovery_info[CONF_COVERS]:
45  hub: ModbusHub = get_hub(hass, discovery_info[CONF_NAME])
46  covers.append(ModbusCover(hass, hub, cover))
47 
48  async_add_entities(covers)
49 
50 
52  """Representation of a Modbus cover."""
53 
54  _attr_supported_features = CoverEntityFeature.OPEN | CoverEntityFeature.CLOSE
55 
56  def __init__(
57  self,
58  hass: HomeAssistant,
59  hub: ModbusHub,
60  config: dict[str, Any],
61  ) -> None:
62  """Initialize the modbus cover."""
63  super().__init__(hass, hub, config)
64  self._state_closed_state_closed = config[CONF_STATE_CLOSED]
65  self._state_closing_state_closing = config[CONF_STATE_CLOSING]
66  self._state_open_state_open = config[CONF_STATE_OPEN]
67  self._state_opening_state_opening = config[CONF_STATE_OPENING]
68  self._status_register_status_register = config.get(CONF_STATUS_REGISTER)
69  self._status_register_type_status_register_type = config[CONF_STATUS_REGISTER_TYPE]
70 
71  self._attr_is_closed_attr_is_closed = False
72 
73  # If we read cover status from coil, and not from optional status register,
74  # we interpret boolean value False as closed cover, and value True as open cover.
75  # Intermediate states are not supported in such a setup.
76  if self._input_type_input_type_input_type == CALL_TYPE_COIL:
77  self._write_type_write_type = CALL_TYPE_WRITE_COIL
78  self._write_address_write_address = self._address_address_address
79  if self._status_register_status_register is None:
80  self._state_closed_state_closed = False
81  self._state_open_state_open = True
82  self._state_closing_state_closing = None
83  self._state_opening_state_opening = None
84  else:
85  # If we read cover status from the main register (i.e., an optional
86  # status register is not specified), we need to make sure the register_type
87  # is set to "holding".
88  self._write_type_write_type = CALL_TYPE_WRITE_REGISTER
89  self._write_address_write_address = self._address_address_address
90  if self._status_register_status_register:
91  self._address_address_address = self._status_register_status_register
92  self._input_type_input_type_input_type = self._status_register_type_status_register_type
93 
94  async def async_added_to_hass(self) -> None:
95  """Handle entity which will be added."""
96  await self.async_base_added_to_hassasync_base_added_to_hass()
97  if state := await self.async_get_last_stateasync_get_last_state():
98  convert = {
99  CoverState.CLOSED: self._state_closed_state_closed,
100  CoverState.CLOSING: self._state_closing_state_closing,
101  CoverState.OPENING: self._state_opening_state_opening,
102  CoverState.OPEN: self._state_open_state_open,
103  STATE_UNAVAILABLE: None,
104  STATE_UNKNOWN: None,
105  }
106  self._set_attr_state_set_attr_state(convert[state.state])
107 
108  def _set_attr_state(self, value: str | bool | int) -> None:
109  """Convert received value to HA state."""
110  self._attr_is_opening_attr_is_opening = value == self._state_opening_state_opening
111  self._attr_is_closing_attr_is_closing = value == self._state_closing_state_closing
112  self._attr_is_closed_attr_is_closed = value == self._state_closed_state_closed
113 
114  async def async_open_cover(self, **kwargs: Any) -> None:
115  """Open cover."""
116  result = await self._hub_hub.async_pb_call(
117  self._slave_slave, self._write_address_write_address, self._state_open_state_open, self._write_type_write_type
118  )
119  self._attr_available_attr_available_attr_available = result is not None
120  await self.async_updateasync_updateasync_update()
121 
122  async def async_close_cover(self, **kwargs: Any) -> None:
123  """Close cover."""
124  result = await self._hub_hub.async_pb_call(
125  self._slave_slave, self._write_address_write_address, self._state_closed_state_closed, self._write_type_write_type
126  )
127  self._attr_available_attr_available_attr_available = result is not None
128  await self.async_updateasync_updateasync_update()
129 
130  async def async_update(self, now: datetime | None = None) -> None:
131  """Update the state of the cover."""
132  # remark "now" is a dummy parameter to avoid problems with
133  # async_track_time_interval
134  result = await self._hub_hub.async_pb_call(
135  self._slave_slave, self._address_address_address, 1, self._input_type_input_type_input_type
136  )
137  if result is None:
138  self._attr_available_attr_available_attr_available = False
139  self.async_write_ha_stateasync_write_ha_state()
140  return
141  self._attr_available_attr_available_attr_available = True
142  if self._input_type_input_type_input_type == CALL_TYPE_COIL:
143  self._set_attr_state_set_attr_state(bool(result.bits[0] & 1))
144  else:
145  self._set_attr_state_set_attr_state(int(result.registers[0]))
146  self.async_write_ha_stateasync_write_ha_state()
None __init__(self, HomeAssistant hass, ModbusHub hub, dict[str, Any] config)
Definition: cover.py:61
None async_close_cover(self, **Any kwargs)
Definition: cover.py:122
None async_open_cover(self, **Any kwargs)
Definition: cover.py:114
None async_update(self, datetime|None now=None)
Definition: cover.py:130
None _set_attr_state(self, str|bool|int value)
Definition: cover.py:108
None async_update(self, datetime|None now=None)
Definition: entity.py:112
None async_setup_platform(HomeAssistant hass, ConfigType config, AddEntitiesCallback async_add_entities, DiscoveryInfoType|None discovery_info=None)
Definition: cover.py:38
ModbusHub get_hub(HomeAssistant hass, str name)
Definition: __init__.py:445