diff --git a/custom_components/localtuya/cover.py b/custom_components/localtuya/cover.py index 6e9acd5..785c1f7 100644 --- a/custom_components/localtuya/cover.py +++ b/custom_components/localtuya/cover.py @@ -80,6 +80,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): ) ) print('Setup localtuya cover [{}] with device ID [{}] '.format(config.get(CONF_FRIENDLY_NAME), config.get(CONF_ID))) + _LOGGER.info("Setup localtuya cover %s with device ID %s ", config.get(CONF_FRIENDLY_NAME), config.get(CONF_ID) ) add_entities(covers) @@ -95,24 +96,31 @@ class TuyaCoverCache: self._lock = Lock() def __get_status(self): - for i in range(20): + for i in range(5): try: status = self._device.status() return status - except ConnectionError: + except Exception: + print('Failed to update status of device [{}]'.format(self._device.address)) + sleep(1.0) if i+1 == 3: - raise ConnectionError("Failed to update status.") + _LOGGER.error("Failed to update status of device %s", self._device.address ) +# return None + raise ConnectionError("Failed to update status .") def set_status(self, state, switchid): """Change the Tuya switch status and clear the cache.""" self._cached_status = '' self._cached_status_time = 0 - for i in range(20): + for i in range(5): try: return self._device.set_status(state, switchid) - except ConnectionError: - if i+1 == 5: - raise ConnectionError("Failed to set status.") + except Exception: + print('Failed to set status of device [{}]'.format(self._device.address)) + if i+1 == 3: + _LOGGER.error("Failed to set status of device %s", self._device.address ) + return +# raise ConnectionError("Failed to set status.") def status(self): """Get state of Tuya switch and cache the results.""" diff --git a/custom_components/localtuya/pytuya/__init__.py b/custom_components/localtuya/pytuya/__init__.py index 2430f24..cec00f6 100644 --- a/custom_components/localtuya/pytuya/__init__.py +++ b/custom_components/localtuya/pytuya/__init__.py @@ -34,16 +34,16 @@ __author__ = 'rospogrigio' log = logging.getLogger(__name__) logging.basicConfig() # TODO include function name/line numbers in log -log.setLevel(level=logging.DEBUG) # Debug hack! +#log.setLevel(level=logging.DEBUG) # Debug hack! -log.info('%s version %s', __name__, version) -log.info('Python %s on %s', sys.version, sys.platform) +log.debug('%s version %s', __name__, version) +log.debug('Python %s on %s', sys.version, sys.platform) if Crypto is None: - log.info('Using pyaes version %r', pyaes.VERSION) - log.info('Using pyaes from %r', pyaes.__file__) + log.debug('Using pyaes version %r', pyaes.VERSION) + log.debug('Using pyaes from %r', pyaes.__file__) else: - log.info('Using PyCrypto %r', Crypto.version_info) - log.info('Using PyCrypto from %r', Crypto.__file__) + log.debug('Using PyCrypto %r', Crypto.version_info) + log.debug('Using PyCrypto from %r', Crypto.__file__) SET = 'set' STATUS = 'status' @@ -184,18 +184,34 @@ class XenonDevice(object): Args: payload(bytes): Data to send. """ - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - s.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) - s.settimeout(self.connection_timeout) - s.connect((self.address, self.port)) - s.send(payload) - data = s.recv(1024) -# print("FIRST: Received %d bytes" % len(data) ) - # sometimes the first packet does not contain data (typically 28 bytes): need to read again - if len(data) < 40: - time.sleep(0.1) + try: + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) + s.settimeout(self.connection_timeout) + s.connect((self.address, self.port)) + except Exception as e: + print('Failed to connect to %s. Raising Exception.' % (self.address)) + raise e + try: + s.send(payload) + except Exception as e: + print('Failed to send payload to %s. Raising Exception.' % (self.address)) + #s.close() + raise e + + try: data = s.recv(1024) -# print("SECOND: Received %d bytes" % len(data) ) +# print("FIRST: Received %d bytes" % len(data) ) + # sometimes the first packet does not contain data (typically 28 bytes): need to read again + if len(data) < 40: + time.sleep(0.1) + data = s.recv(1024) +# print("SECOND: Received %d bytes" % len(data) ) + except Exception as e: + print('Failed to receive data from %s. Raising Exception.' % (self.address)) + #s.close() + raise e + s.close() return data diff --git a/custom_components/localtuya/switch.py b/custom_components/localtuya/switch.py index 3586782..60ac1b7 100644 --- a/custom_components/localtuya/switch.py +++ b/custom_components/localtuya/switch.py @@ -24,13 +24,17 @@ switch: friendly_name: USB Plug id: 7 """ +import logging import voluptuous as vol + from homeassistant.components.switch import ENTITY_ID_FORMAT, SwitchDevice, PLATFORM_SCHEMA from homeassistant.const import (CONF_HOST, CONF_ID, CONF_SWITCHES, CONF_FRIENDLY_NAME, CONF_ICON, CONF_NAME) import homeassistant.helpers.config_validation as cv from time import time, sleep from threading import Lock +_LOGGER = logging.getLogger(__name__) + REQUIREMENTS = ['pytuya==7.0.7'] CONF_DEVICE_ID = 'device_id' @@ -99,6 +103,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): ) ) print('Setup localtuya subswitch [{}] with device ID [{}] '.format(device_config.get(CONF_FRIENDLY_NAME, object_id), device_config.get(CONF_ID))) + _LOGGER.info("Setup localtuya subswitch %s with device ID %s ", device_config.get(CONF_FRIENDLY_NAME, object_id), config.get(CONF_ID) ) else: outlet_device = TuyaCache(pytuyadevice) switches.append( @@ -114,6 +119,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): ) ) print('Setup localtuya switch [{}] with device ID [{}] '.format(config.get(CONF_FRIENDLY_NAME), config.get(CONF_ID))) + _LOGGER.info("Setup localtuya switch %s with device ID %s ", config.get(CONF_FRIENDLY_NAME), config.get(CONF_ID) ) add_devices(switches) @@ -128,24 +134,31 @@ class TuyaCache: self._lock = Lock() def __get_status(self): - for i in range(20): + for i in range(5): try: status = self._device.status() return status - except ConnectionError: + except Exception: + print('Failed to update status of device [{}]'.format(self._device.address)) + sleep(1.0) if i+1 == 3: - raise ConnectionError("Failed to update status.") + _LOGGER.error("Failed to update status of device %s", self._device.address ) +# return None + raise ConnectionError("Failed to update status .") def set_status(self, state, switchid): """Change the Tuya switch status and clear the cache.""" self._cached_status = '' self._cached_status_time = 0 - for i in range(20): + for i in range(5): try: return self._device.set_status(state, switchid) - except ConnectionError: - if i+1 == 5: - raise ConnectionError("Failed to set status.") + except Exception: + print('Failed to set status of device [{}]'.format(self._device.address)) + if i+1 == 3: + _LOGGER.error("Failed to set status of device %s", self._device.address ) + return +# raise ConnectionError("Failed to set status.") def status(self): """Get state of Tuya switch and cache the results."""