Home Assistant Unofficial Reference 2024.12.1
__init__.py
Go to the documentation of this file.
1 """Support for SCSGate components."""
2 
3 import logging
4 from threading import Lock
5 
6 from scsgate.connection import Connection
7 from scsgate.messages import ScenarioTriggeredMessage, StateMessage
8 from scsgate.reactor import Reactor
9 from scsgate.tasks import GetStatusTask
10 import voluptuous as vol
11 
12 from homeassistant.const import CONF_DEVICE, CONF_NAME, EVENT_HOMEASSISTANT_STOP
13 from homeassistant.core import HomeAssistant
15 from homeassistant.helpers.typing import ConfigType
16 
17 _LOGGER = logging.getLogger(__name__)
18 
19 CONF_SCS_ID = "scs_id"
20 
21 DOMAIN = "scsgate"
22 
23 CONFIG_SCHEMA = vol.Schema(
24  {DOMAIN: vol.Schema({vol.Required(CONF_DEVICE): cv.string})}, extra=vol.ALLOW_EXTRA
25 )
26 
27 SCSGATE_SCHEMA = vol.Schema(
28  {vol.Required(CONF_SCS_ID): cv.string, vol.Optional(CONF_NAME): cv.string}
29 )
30 
31 
32 def setup(hass: HomeAssistant, config: ConfigType) -> bool:
33  """Set up the SCSGate component."""
34  device = config[DOMAIN][CONF_DEVICE]
35  scsgate = None
36 
37  try:
38  scsgate = SCSGate(device=device, logger=_LOGGER)
39  scsgate.start()
40  except Exception as exception: # noqa: BLE001
41  _LOGGER.error("Cannot setup SCSGate component: %s", exception)
42  return False
43 
44  def stop_monitor(event):
45  """Stop the SCSGate."""
46  _LOGGER.debug("Stopping SCSGate monitor thread")
47  scsgate.stop()
48 
49  hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_monitor)
50  hass.data[DOMAIN] = scsgate
51 
52  return True
53 
54 
55 class SCSGate:
56  """The class for dealing with the SCSGate device via scsgate.Reactor."""
57 
58  def __init__(self, device, logger):
59  """Initialize the SCSGate."""
60  self._logger_logger = logger
61  self._devices_devices = {}
62  self._devices_to_register_devices_to_register = {}
63  self._devices_to_register_lock_devices_to_register_lock = Lock()
64  self._device_being_registered_device_being_registered = None
65  self._device_being_registered_lock_device_being_registered_lock = Lock()
66 
67  connection = Connection(device=device, logger=self._logger_logger)
68 
69  self._reactor_reactor = Reactor(
70  connection=connection,
71  logger=self._logger_logger,
72  handle_message=self.handle_messagehandle_message,
73  )
74 
75  def handle_message(self, message):
76  """Handle a messages seen on the bus."""
77 
78  self._logger_logger.debug("Received message %s", message)
79  if not isinstance(message, StateMessage) and not isinstance(
80  message, ScenarioTriggeredMessage
81  ):
82  msg = f"Ignored message {message} - not relevant type"
83  self._logger_logger.debug(msg)
84  return
85 
86  if message.entity in self._devices_devices:
87  new_device_activated = False
88  with self._devices_to_register_lock_devices_to_register_lock:
89  if message.entity == self._device_being_registered_device_being_registered:
90  self._device_being_registered_device_being_registered = None
91  new_device_activated = True
92  if new_device_activated:
93  self._activate_next_device_activate_next_device()
94 
95  try:
96  self._devices_devices[message.entity].process_event(message)
97  except Exception as exception: # noqa: BLE001
98  msg = f"Exception while processing event: {exception}"
99  self._logger_logger.error(msg)
100  else:
101  self._logger_logger.info(
102  "Ignoring state message for device %s because unknown", message.entity
103  )
104 
105  @property
106  def devices(self):
107  """Return a dictionary with known devices.
108 
109  Key is device ID, value is the device itself.
110  """
111  return self._devices_devices
112 
113  def add_device(self, device):
114  """Add the specified device.
115 
116  The list contain already registered ones.
117  Beware: this is not what you usually want to do, take a look at
118  `add_devices_to_register`
119  """
120  self._devices_devices[device.scs_id] = device
121 
122  def add_devices_to_register(self, devices):
123  """List of devices to be registered."""
124  with self._devices_to_register_lock_devices_to_register_lock:
125  for device in devices:
126  self._devices_to_register_devices_to_register[device.scs_id] = device
127  self._activate_next_device_activate_next_device()
128 
130  """Start the activation of the first device."""
131 
132  with self._devices_to_register_lock_devices_to_register_lock:
133  while self._devices_to_register_devices_to_register:
134  device = self._devices_to_register_devices_to_register.popitem()[1]
135  self._devices_devices[device.scs_id] = device
136  self._device_being_registered_device_being_registered = device.scs_id
137  self._reactor_reactor.append_task(GetStatusTask(target=device.scs_id))
138 
139  def is_device_registered(self, device_id):
140  """Check whether a device is already registered or not."""
141  with self._devices_to_register_lock_devices_to_register_lock:
142  if device_id in self._devices_to_register_devices_to_register:
143  return False
144 
145  with self._device_being_registered_lock_device_being_registered_lock:
146  if device_id == self._device_being_registered_device_being_registered:
147  return False
148 
149  return True
150 
151  def start(self):
152  """Start the scsgate.Reactor."""
153  self._reactor_reactor.start()
154 
155  def stop(self):
156  """Stop the scsgate.Reactor."""
157  self._reactor_reactor.stop()
158 
159  def append_task(self, task):
160  """Register a new task to be executed."""
161  self._reactor_reactor.append_task(task)
def add_devices_to_register(self, devices)
Definition: __init__.py:122
def is_device_registered(self, device_id)
Definition: __init__.py:139
def __init__(self, device, logger)
Definition: __init__.py:58
bool setup(HomeAssistant hass, ConfigType config)
Definition: __init__.py:32