Update Qwikswitch: fix typing, add validation, shutdown (#2603)

* Update Qwikswitch: fix typing, add validation, shutdown

* Delay startup listener, fix validation

* Fix workerpool errors
This commit is contained in:
Johann Kellerman 2016-07-24 02:03:29 +02:00 committed by Paulus Schoutsen
parent 2484ee53b8
commit 4195254280
3 changed files with 96 additions and 87 deletions

View File

@ -1,35 +1,21 @@
""" """
Support for Qwikswitch Relays and Dimmers. Support for Qwikswitch Relays and Dimmers.
For more details about this platform, please refer to the documentation at For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/light.qwikswitch/ https://home-assistant.io/components/light.qwikswitch/
""" """
import logging import logging
import homeassistant.components.qwikswitch as qwikswitch import homeassistant.components.qwikswitch as qwikswitch
from homeassistant.components.light import Light
DEPENDENCIES = ['qwikswitch']
DEPENDENCIES = ['qwikswitch']
# pylint: disable=unused-argument
class QSLight(qwikswitch.QSToggleEntity, Light): def setup_platform(hass, config, add_devices, discovery_info=None):
"""Light based on a Qwikswitch relay/dimmer module.""" """Add lights from the main Qwikswitch component."""
if discovery_info is None:
pass logging.getLogger(__name__).error('Configure Qwikswitch Component.')
return False
# pylint: disable=unused-argument add_devices(qwikswitch.QSUSB['light'])
def setup_platform(hass, config, add_devices, discovery_info=None): return True
"""Store add_devices for the light components."""
if discovery_info is None or 'qsusb_id' not in discovery_info:
logging.getLogger(__name__).error(
'Configure main Qwikswitch component')
return False
qsusb = qwikswitch.QSUSB[discovery_info['qsusb_id']]
for item in qsusb.ha_devices:
if item['type'] not in ['dim', 'rel']:
continue
dev = QSLight(item, qsusb)
add_devices([dev])
qsusb.ha_objects[item['id']] = dev

View File

@ -5,18 +5,29 @@ For more details about this component, please refer to the documentation at
https://home-assistant.io/components/qwikswitch/ https://home-assistant.io/components/qwikswitch/
""" """
import logging import logging
from homeassistant.const import EVENT_HOMEASSISTANT_STOP import voluptuous as vol
from homeassistant.components.light import ATTR_BRIGHTNESS
from homeassistant.components.discovery import load_platform
from homeassistant.const import (EVENT_HOMEASSISTANT_START,
EVENT_HOMEASSISTANT_STOP)
from homeassistant.helpers.discovery import load_platform
from homeassistant.components.light import ATTR_BRIGHTNESS, Light
from homeassistant.components.switch import SwitchDevice
DOMAIN = 'qwikswitch'
REQUIREMENTS = ['https://github.com/kellerza/pyqwikswitch/archive/v0.4.zip' REQUIREMENTS = ['https://github.com/kellerza/pyqwikswitch/archive/v0.4.zip'
'#pyqwikswitch==0.4'] '#pyqwikswitch==0.4']
DEPENDENCIES = []
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
DOMAIN = 'qwikswitch' CV_DIM_VALUE = vol.All(vol.Coerce(float), vol.Range(min=1, max=3))
QSUSB = None CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({
vol.Required('url', default='http://127.0.0.1:2020'): vol.Coerce(str),
vol.Optional('dimmer_adjust', default=1): CV_DIM_VALUE,
vol.Optional('button_events'): vol.Coerce(str)
})}, extra=vol.ALLOW_EXTRA)
QSUSB = {}
class QSToggleEntity(object): class QSToggleEntity(object):
@ -42,6 +53,7 @@ class QSToggleEntity(object):
self._value = qsitem[PQS_VALUE] self._value = qsitem[PQS_VALUE]
self._qsusb = qsusb self._qsusb = qsusb
self._dim = qsitem[PQS_TYPE] == QSType.dimmer self._dim = qsitem[PQS_TYPE] == QSType.dimmer
QSUSB[self._id] = self
@property @property
def brightness(self): def brightness(self):
@ -87,51 +99,70 @@ class QSToggleEntity(object):
self.update_value(0) self.update_value(0)
class QSSwitch(QSToggleEntity, SwitchDevice):
"""Switch based on a Qwikswitch relay module."""
pass
class QSLight(QSToggleEntity, Light):
"""Light based on a Qwikswitch relay/dimmer module."""
pass
# pylint: disable=too-many-locals # pylint: disable=too-many-locals
def setup(hass, config): def setup(hass, config):
"""Setup the QSUSB component.""" """Setup the QSUSB component."""
from pyqwikswitch import (QSUsb, CMD_BUTTONS, QS_NAME, QS_ID, QS_CMD, from pyqwikswitch import (QSUsb, CMD_BUTTONS, QS_NAME, QS_ID, QS_CMD,
QS_TYPE, PQS_VALUE, PQS_TYPE, QSType) PQS_VALUE, PQS_TYPE, QSType)
# Override which cmd's in /&listen packets will fire events # Override which cmd's in /&listen packets will fire events
# By default only buttons of type [TOGGLE,SCENE EXE,LEVEL] # By default only buttons of type [TOGGLE,SCENE EXE,LEVEL]
cmd_buttons = config[DOMAIN].get('button_events', ','.join(CMD_BUTTONS)) cmd_buttons = config[DOMAIN].get('button_events', ','.join(CMD_BUTTONS))
cmd_buttons = cmd_buttons.split(',') cmd_buttons = cmd_buttons.split(',')
try: url = config[DOMAIN]['url']
url = config[DOMAIN].get('url', 'http://127.0.0.1:2020') dimmer_adjust = config[DOMAIN]['dimmer_adjust']
dimmer_adjust = float(config[DOMAIN].get('dimmer_adjust', '1'))
qsusb = QSUsb(url, _LOGGER, dimmer_adjust)
# Ensure qsusb terminates threads correctly qsusb = QSUsb(url, _LOGGER, dimmer_adjust)
hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP,
lambda event: qsusb.stop())
except ValueError as val_err:
_LOGGER.error(str(val_err))
return False
qsusb.ha_devices = qsusb.devices() def _stop(event):
qsusb.ha_objects = {} """Stop the listener queue and clean up."""
nonlocal qsusb
# Identify switches & remove ' Switch' postfix in name qsusb.stop()
for item in qsusb.ha_devices: qsusb = None
if item[PQS_TYPE] == QSType.relay and \ global QSUSB
item[QS_NAME].lower().endswith(' switch'):
item[QS_TYPE] = 'switch'
item[QS_NAME] = item[QS_NAME][:-7]
global QSUSB
if QSUSB is None:
QSUSB = {} QSUSB = {}
QSUSB[id(qsusb)] = qsusb _LOGGER.info("Waiting for long poll to QSUSB to time out")
# Load sub-components for qwikswitch hass.bus.listen(EVENT_HOMEASSISTANT_STOP, _stop)
# Discover all devices in QSUSB
devices = qsusb.devices()
QSUSB['switch'] = []
QSUSB['light'] = []
for item in devices:
if item[PQS_TYPE] == QSType.relay and (item[QS_NAME].lower()
.endswith(' switch')):
item[QS_NAME] = item[QS_NAME][:-7] # Remove ' switch' postfix
QSUSB['switch'].append(QSSwitch(item, qsusb))
elif item[PQS_TYPE] in [QSType.relay, QSType.dimmer]:
QSUSB['light'].append(QSLight(item, qsusb))
else:
_LOGGER.warning("Ignored unknown QSUSB device: %s", item)
# Load platforms
for comp_name in ('switch', 'light'): for comp_name in ('switch', 'light'):
load_platform(hass, comp_name, 'qwikswitch', if len(QSUSB[comp_name]) > 0:
{'qsusb_id': id(qsusb)}, config) load_platform(hass, comp_name, 'qwikswitch', {}, config)
def qs_callback(item): def qs_callback(item):
"""Typically a button press or update signal.""" """Typically a button press or update signal."""
if qsusb is None: # Shutting down
_LOGGER.info("Done")
return
# If button pressed, fire a hass event # If button pressed, fire a hass event
if item.get(QS_CMD, '') in cmd_buttons: if item.get(QS_CMD, '') in cmd_buttons:
hass.bus.fire('qwikswitch.button.' + item.get(QS_ID, '@no_id')) hass.bus.fire('qwikswitch.button.' + item.get(QS_ID, '@no_id'))
@ -142,9 +173,13 @@ def setup(hass, config):
if qsreply is False: if qsreply is False:
return return
for item in qsreply: for item in qsreply:
if item[QS_ID] in qsusb.ha_objects: if item[QS_ID] in QSUSB:
qsusb.ha_objects[item[QS_ID]].update_value( QSUSB[item[QS_ID]].update_value(
round(min(item[PQS_VALUE], 100) * 2.55)) round(min(item[PQS_VALUE], 100) * 2.55))
qsusb.listen(callback=qs_callback, timeout=30) def _start(event):
"""Start listening."""
qsusb.listen(callback=qs_callback, timeout=30)
hass.bus.listen_once(EVENT_HOMEASSISTANT_START, _start)
return True return True

View File

@ -6,29 +6,17 @@ https://home-assistant.io/components/switch.qwikswitch/
""" """
import logging import logging
import homeassistant.components.qwikswitch as qwikswitch import homeassistant.components.qwikswitch as qwikswitch
from homeassistant.components.switch import SwitchDevice
DEPENDENCIES = ['qwikswitch'] DEPENDENCIES = ['qwikswitch']
class QSSwitch(qwikswitch.QSToggleEntity, SwitchDevice):
"""Switch based on a Qwikswitch relay module."""
pass
# pylint: disable=unused-argument # pylint: disable=unused-argument
def setup_platform(hass, config, add_devices, discovery_info=None): def setup_platform(hass, config, add_devices, discovery_info=None):
"""Store add_devices for the switch components.""" """Add switched from the main Qwikswitch component."""
if discovery_info is None or 'qsusb_id' not in discovery_info: if discovery_info is None:
logging.getLogger(__name__).error( logging.getLogger(__name__).error(
'Configure main Qwikswitch component') 'Configure main Qwikswitch component')
return False return False
qsusb = qwikswitch.QSUSB[discovery_info['qsusb_id']] add_devices(qwikswitch.QSUSB['switch'])
return True
for item in qsusb.ha_devices:
if item['type'] == 'switch':
dev = QSSwitch(item, qsusb)
add_devices([dev])
qsusb.ha_objects[item['id']] = dev