core/homeassistant/components/scsgate/__init__.py

163 lines
5.2 KiB
Python
Raw Normal View History

"""Support for SCSGate components."""
import logging
from threading import Lock
2016-02-19 05:27:50 +00:00
from scsgate.connection import Connection
from scsgate.messages import ScenarioTriggeredMessage, StateMessage
from scsgate.reactor import Reactor
from scsgate.tasks import GetStatusTask
import voluptuous as vol
from homeassistant.const import CONF_DEVICE, CONF_NAME, EVENT_HOMEASSISTANT_STOP
from homeassistant.core import HomeAssistant
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.typing import ConfigType
_LOGGER = logging.getLogger(__name__)
2019-07-31 19:25:30 +00:00
CONF_SCS_ID = "scs_id"
2019-07-31 19:25:30 +00:00
DOMAIN = "scsgate"
2019-07-31 19:25:30 +00:00
CONFIG_SCHEMA = vol.Schema(
{DOMAIN: vol.Schema({vol.Required(CONF_DEVICE): cv.string})}, extra=vol.ALLOW_EXTRA
)
2019-07-31 19:25:30 +00:00
SCSGATE_SCHEMA = vol.Schema(
{vol.Required(CONF_SCS_ID): cv.string, vol.Optional(CONF_NAME): cv.string}
)
def setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up the SCSGate component."""
device = config[DOMAIN][CONF_DEVICE]
scsgate = None
try:
scsgate = SCSGate(device=device, logger=_LOGGER)
scsgate.start()
except Exception as exception: # pylint: disable=broad-except
_LOGGER.error("Cannot setup SCSGate component: %s", exception)
return False
def stop_monitor(event):
"""Stop the SCSGate."""
_LOGGER.info("Stopping SCSGate monitor thread")
scsgate.stop()
hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_monitor)
hass.data[DOMAIN] = scsgate
return True
class SCSGate:
"""The class for dealing with the SCSGate device via scsgate.Reactor."""
2016-03-08 16:55:57 +00:00
def __init__(self, device, logger):
2016-03-08 16:55:57 +00:00
"""Initialize the SCSGate."""
self._logger = logger
self._devices = {}
self._devices_to_register = {}
self._devices_to_register_lock = Lock()
self._device_being_registered = None
self._device_being_registered_lock = Lock()
connection = Connection(device=device, logger=self._logger)
self._reactor = Reactor(
2019-07-31 19:25:30 +00:00
connection=connection,
logger=self._logger,
handle_message=self.handle_message,
)
def handle_message(self, message):
"""Handle a messages seen on the bus."""
self._logger.debug(f"Received message {message}")
2019-07-31 19:25:30 +00:00
if not isinstance(message, StateMessage) and not isinstance(
message, ScenarioTriggeredMessage
):
msg = f"Ignored message {message} - not relevant type"
self._logger.debug(msg)
return
if message.entity in self._devices:
new_device_activated = False
with self._devices_to_register_lock:
if message.entity == self._device_being_registered:
self._device_being_registered = None
new_device_activated = True
if new_device_activated:
self._activate_next_device()
try:
self._devices[message.entity].process_event(message)
except Exception as exception: # pylint: disable=broad-except
msg = f"Exception while processing event: {exception}"
self._logger.error(msg)
else:
self._logger.info(
"Ignoring state message for device {} because unknown".format(
2019-07-31 19:25:30 +00:00
message.entity
)
)
@property
def devices(self):
"""Return a dictionary with known devices.
2016-03-08 16:55:57 +00:00
Key is device ID, value is the device itself.
2016-02-02 23:35:53 +00:00
"""
return self._devices
def add_device(self, device):
2016-03-08 16:55:57 +00:00
"""Add the specified device.
2016-03-08 16:55:57 +00:00
The list contain already registered ones.
2016-02-02 23:35:53 +00:00
Beware: this is not what you usually want to do, take a look at
`add_devices_to_register`
"""
self._devices[device.scs_id] = device
def add_devices_to_register(self, devices):
2016-03-07 17:49:31 +00:00
"""List of devices to be registered."""
with self._devices_to_register_lock:
for device in devices:
self._devices_to_register[device.scs_id] = device
self._activate_next_device()
def _activate_next_device(self):
2016-03-08 16:55:57 +00:00
"""Start the activation of the first device."""
with self._devices_to_register_lock:
while self._devices_to_register:
device = self._devices_to_register.popitem()[1]
self._devices[device.scs_id] = device
self._device_being_registered = device.scs_id
self._reactor.append_task(GetStatusTask(target=device.scs_id))
def is_device_registered(self, device_id):
2016-03-08 16:55:57 +00:00
"""Check whether a device is already registered or not."""
with self._devices_to_register_lock:
if device_id in self._devices_to_register:
return False
with self._device_being_registered_lock:
if device_id == self._device_being_registered:
return False
return True
def start(self):
2016-03-07 17:49:31 +00:00
"""Start the scsgate.Reactor."""
self._reactor.start()
def stop(self):
2016-03-07 17:49:31 +00:00
"""Stop the scsgate.Reactor."""
self._reactor.stop()
def append_task(self, task):
2016-03-08 16:55:57 +00:00
"""Register a new task to be executed."""
self._reactor.append_task(task)