2016-01-09 13:51:49 +00:00
|
|
|
"""
|
|
|
|
homeassistant.components.scsgate
|
2016-02-02 23:35:53 +00:00
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
2016-01-09 13:51:49 +00:00
|
|
|
Provides support for SCSGate components.
|
|
|
|
|
|
|
|
For more details about this component, please refer to the documentation at
|
|
|
|
https://home-assistant.io/components/scsgate/
|
|
|
|
"""
|
|
|
|
import logging
|
|
|
|
from threading import Lock
|
2016-02-19 05:27:50 +00:00
|
|
|
|
2016-01-09 13:51:49 +00:00
|
|
|
from homeassistant.core import EVENT_HOMEASSISTANT_STOP
|
|
|
|
|
|
|
|
REQUIREMENTS = ['scsgate==0.1.0']
|
|
|
|
DOMAIN = "scsgate"
|
|
|
|
SCSGATE = None
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
class SCSGate:
|
2016-02-02 23:35:53 +00:00
|
|
|
""" Class dealing with the SCSGate device via scsgate.Reactor. """
|
2016-01-09 13:51:49 +00:00
|
|
|
|
|
|
|
def __init__(self, device, logger):
|
|
|
|
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()
|
|
|
|
|
|
|
|
from scsgate.connection import Connection
|
|
|
|
connection = Connection(device=device, logger=self._logger)
|
|
|
|
|
|
|
|
from scsgate.reactor import Reactor
|
|
|
|
self._reactor = Reactor(
|
|
|
|
connection=connection,
|
|
|
|
logger=self._logger,
|
|
|
|
handle_message=self.handle_message)
|
|
|
|
|
|
|
|
def handle_message(self, message):
|
2016-02-02 23:35:53 +00:00
|
|
|
""" Method called whenever a message is seen on the bus. """
|
2016-01-09 13:51:49 +00:00
|
|
|
from scsgate.messages import StateMessage, ScenarioTriggeredMessage
|
|
|
|
|
|
|
|
self._logger.debug("Received message {}".format(message))
|
|
|
|
if not isinstance(message, StateMessage) and \
|
|
|
|
not isinstance(message, ScenarioTriggeredMessage):
|
|
|
|
msg = "Ignored message {} - not releavant type".format(
|
|
|
|
message)
|
|
|
|
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()
|
|
|
|
|
|
|
|
# pylint: disable=broad-except
|
|
|
|
try:
|
|
|
|
self._devices[message.entity].process_event(message)
|
|
|
|
except Exception as exception:
|
|
|
|
msg = "Exception while processing event: {}".format(
|
|
|
|
exception)
|
|
|
|
self._logger.error(msg)
|
|
|
|
else:
|
|
|
|
self._logger.info(
|
|
|
|
"Ignoring state message for device {} because unknonw".format(
|
|
|
|
message.entity))
|
|
|
|
|
|
|
|
@property
|
|
|
|
def devices(self):
|
2016-02-02 23:35:53 +00:00
|
|
|
"""
|
|
|
|
Dictionary with known devices. Key is device ID, value is the device
|
|
|
|
itself.
|
|
|
|
"""
|
2016-01-09 13:51:49 +00:00
|
|
|
return self._devices
|
|
|
|
|
|
|
|
def add_device(self, device):
|
2016-02-02 23:35:53 +00:00
|
|
|
"""
|
|
|
|
Adds the specified device to the list of the already registered ones.
|
2016-01-09 13:51:49 +00:00
|
|
|
|
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`
|
2016-01-09 13:51:49 +00:00
|
|
|
"""
|
|
|
|
self._devices[device.scs_id] = device
|
|
|
|
|
|
|
|
def add_devices_to_register(self, devices):
|
2016-02-02 23:35:53 +00:00
|
|
|
""" List of devices to be registered. """
|
2016-01-09 13:51:49 +00:00
|
|
|
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-02-02 23:35:53 +00:00
|
|
|
""" Starts the activation of the first device. """
|
2016-01-09 13:51:49 +00:00
|
|
|
from scsgate.tasks import GetStatusTask
|
|
|
|
|
|
|
|
with self._devices_to_register_lock:
|
|
|
|
if len(self._devices_to_register) == 0:
|
|
|
|
return
|
|
|
|
_, device = self._devices_to_register.popitem()
|
|
|
|
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-02-02 23:35:53 +00:00
|
|
|
""" Checks whether a device is already registered or not. """
|
2016-01-09 13:51:49 +00:00
|
|
|
with self._devices_to_register_lock:
|
|
|
|
if device_id in self._devices_to_register.keys():
|
|
|
|
return False
|
|
|
|
|
|
|
|
with self._device_being_registered_lock:
|
|
|
|
if device_id == self._device_being_registered:
|
|
|
|
return False
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
def start(self):
|
2016-02-02 23:35:53 +00:00
|
|
|
""" Start the scsgate.Reactor. """
|
2016-01-09 13:51:49 +00:00
|
|
|
self._reactor.start()
|
|
|
|
|
|
|
|
def stop(self):
|
2016-02-02 23:35:53 +00:00
|
|
|
""" Stop the scsgate.Reactor. """
|
2016-01-09 13:51:49 +00:00
|
|
|
self._reactor.stop()
|
|
|
|
|
|
|
|
def append_task(self, task):
|
2016-02-02 23:35:53 +00:00
|
|
|
""" Registers a new task to be executed. """
|
2016-01-09 13:51:49 +00:00
|
|
|
self._reactor.append_task(task)
|
|
|
|
|
|
|
|
|
|
|
|
def setup(hass, config):
|
|
|
|
""" Setup the SCSGate component. """
|
|
|
|
device = config['scsgate']['device']
|
|
|
|
global SCSGATE
|
|
|
|
|
|
|
|
# pylint: disable=broad-except
|
|
|
|
try:
|
|
|
|
SCSGATE = SCSGate(device=device, logger=_LOGGER)
|
|
|
|
SCSGATE.start()
|
|
|
|
except Exception as exception:
|
|
|
|
_LOGGER.error("Cannot setup SCSGate component: %s", exception)
|
|
|
|
return False
|
|
|
|
|
|
|
|
def stop_monitor(event):
|
2016-02-02 23:35:53 +00:00
|
|
|
"""
|
|
|
|
Invoked when home-assistant is exiting. Performs the necessary
|
|
|
|
cleanups.
|
|
|
|
"""
|
2016-01-09 13:51:49 +00:00
|
|
|
_LOGGER.info("Stopping SCSGate monitor thread")
|
|
|
|
SCSGATE.stop()
|
|
|
|
|
|
|
|
hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_monitor)
|
|
|
|
|
|
|
|
return True
|