diff --git a/.coveragerc b/.coveragerc index 58bdac1ff31..d0a29acc897 100644 --- a/.coveragerc +++ b/.coveragerc @@ -11,6 +11,9 @@ omit = homeassistant/components/abode.py homeassistant/components/*/abode.py + homeassistant/components/ads.py + homeassistant/components/*/ads.py + homeassistant/components/alarmdecoder.py homeassistant/components/*/alarmdecoder.py diff --git a/homeassistant/components/ads.py b/homeassistant/components/ads.py index 16cd16bc181..4866e0ee53b 100644 --- a/homeassistant/components/ads.py +++ b/homeassistant/components/ads.py @@ -4,8 +4,8 @@ ADS Component. For more details about this component, please refer to the documentation. """ +import threading import struct -import time import logging import ctypes from collections import namedtuple @@ -13,10 +13,8 @@ import voluptuous as vol from homeassistant.const import CONF_DEVICE, CONF_PORT, CONF_IP_ADDRESS, \ EVENT_HOMEASSISTANT_STOP import homeassistant.helpers.config_validation as cv -import pyads -from pyads import PLCTYPE_BOOL, PLCTYPE_INT, PLCTYPE_UINT, PLCTYPE_BYTE -REQUIREMENTS = ['pyads'] +REQUIREMENTS = ['pyads==2.2.6'] _LOGGER = logging.getLogger(__name__) @@ -28,17 +26,17 @@ ADSTYPE_UINT = 'uint' ADSTYPE_BYTE = 'byte' ADSTYPE_BOOL = 'bool' -ADS_TYPEMAP = { - ADSTYPE_BOOL: PLCTYPE_BOOL, - ADSTYPE_BYTE: PLCTYPE_BYTE, - ADSTYPE_INT: PLCTYPE_INT, - ADSTYPE_UINT: PLCTYPE_UINT, -} - ADS_PLATFORMS = ['switch', 'binary_sensor', 'light'] DOMAIN = 'ads' +# config variable names +CONF_ADSVAR = 'adsvar' +CONF_ADSTYPE = 'adstype' +CONF_ADS_USE_NOTIFY = 'use_notify' +CONF_ADS_POLL_INTERVAL = 'poll_interval' +CONF_ADS_FACTOR = 'factor' + CONFIG_SCHEMA = vol.Schema({ DOMAIN: vol.Schema({ vol.Required(CONF_DEVICE): cv.string, @@ -47,8 +45,12 @@ CONFIG_SCHEMA = vol.Schema({ }) }, extra=vol.ALLOW_EXTRA) +MAX_RETRIES = 5 +RETRY_SLEEPTIME_S = 0.1 + def setup(hass, config): + import pyads """ Set up the ADS component. """ _LOGGER.info('created ADS client') conf = config[DOMAIN] @@ -81,12 +83,29 @@ class AdsHub: """ Representation of a PyADS connection. """ def __init__(self, ads_client): + from pyads import PLCTYPE_BOOL, PLCTYPE_BYTE, PLCTYPE_INT, \ + PLCTYPE_UINT, ADSError + + self.ADS_TYPEMAP = { + ADSTYPE_BOOL: PLCTYPE_BOOL, + ADSTYPE_BYTE: PLCTYPE_BYTE, + ADSTYPE_INT: PLCTYPE_INT, + ADSTYPE_UINT: PLCTYPE_UINT, + } + + self.PLCTYPE_BOOL = PLCTYPE_BOOL + self.PLCTYPE_BYTE = PLCTYPE_BYTE + self.PLCTYPE_INT = PLCTYPE_INT + self.PLCTYPE_UINT = PLCTYPE_UINT + self.ADSError = ADSError + self._client = ads_client self._client.open() # all ADS devices are registered here self._devices = [] self._notification_items = {} + self._lock = threading.Lock() def shutdown(self, *args, **kwargs): _LOGGER.debug('Shutting down ADS') @@ -105,28 +124,23 @@ class AdsHub: self._devices.append(device) def write_by_name(self, name, value, plc_datatype): - return self._client.write_by_name(name, value, plc_datatype) + with self._lock: + return self._client.write_by_name(name, value, plc_datatype) def read_by_name(self, name, plc_datatype): - return self._client.read_by_name(name, plc_datatype) + with self._lock: + return self._client.read_by_name(name, plc_datatype) def add_device_notification(self, name, plc_datatype, callback): + from pyads import NotificationAttrib """ Add a notification to the ADS devices. """ - attr = pyads.NotificationAttrib(ctypes.sizeof(plc_datatype)) + attr = NotificationAttrib(ctypes.sizeof(plc_datatype)) - for i in range(5): - try: - hnotify, huser = self._client.add_device_notification( - name, attr, self._device_notification_callback - ) - hnotify = int(hnotify) - break - except pyads.pyads.ADSError: - _LOGGER.debug('Could not add notification for "{0}". Retrying...' - .format(name)) - time.sleep(0.1) - else: - return False + with self._lock: + hnotify, huser = self._client.add_device_notification( + name, attr, self._device_notification_callback + ) + hnotify = int(hnotify) _LOGGER.debug('Added Device Notification {0} for variable {1}' .format(hnotify, name)) @@ -136,6 +150,7 @@ class AdsHub: ) def _device_notification_callback(self, addr, notification, huser): + from pyads import PLCTYPE_BOOL, PLCTYPE_INT, PLCTYPE_BYTE, PLCTYPE_UINT contents = notification.contents hnotify = int(contents.hNotification) @@ -150,13 +165,13 @@ class AdsHub: return # parse data to desired datatype - if notification_item.plc_datatype == pyads.PLCTYPE_BOOL: + if notification_item.plc_datatype == PLCTYPE_BOOL: value = bool(struct.unpack('