From 8debe71bab2ab5b669212fd82357baaef66b61f5 Mon Sep 17 00:00:00 2001 From: David Date: Sun, 26 Jan 2020 21:06:13 -0500 Subject: [PATCH 1/2] add debug logging --- climate.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/climate.py b/climate.py index fd8eaf6..6e428ce 100644 --- a/climate.py +++ b/climate.py @@ -171,6 +171,7 @@ def target_temperature(self): @property def hvac_modes(self): + LOGGER.debug("hvac_modes") return list(MODES.values()) + [c_const.HVAC_MODE_OFF] @property @@ -179,10 +180,14 @@ def fan_modes(self): @property def hvac_mode(self): + LOGGER.debug("hvac_mode") if self._state: + LOGGER.debug('hvac_mode is_on %s', self._state.is_on) + if not self._state.is_on: return c_const.HVAC_MODE_OFF mode = self._state.mode + LOGGER.debug('hvac_mode name %s', MODES[mode.name]) return MODES[mode.name] @property From 1773271c8e9d98ce5521d48b38e1a10ab6c9428d Mon Sep 17 00:00:00 2001 From: David Date: Sun, 26 Jan 2020 21:06:36 -0500 Subject: [PATCH 2/2] add current total insant power sensor --- sensor.py | 232 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 228 insertions(+), 4 deletions(-) diff --git a/sensor.py b/sensor.py index be4fdee..6f1c925 100644 --- a/sensor.py +++ b/sensor.py @@ -6,10 +6,13 @@ from custom_components.smartthinq import ( CONF_LANGUAGE, KEY_SMARTTHINQ_DEVICES, LGDevice) import homeassistant.helpers.config_validation as cv -from homeassistant.const import CONF_REGION, CONF_TOKEN +from homeassistant.const import CONF_REGION, CONF_TOKEN, DEVICE_CLASS_POWER, POWER_WATT -import wideq -from wideq import dishwasher +from . import wideq +from .wideq import dishwasher +from .wideq import ac + +REQUIREMENTS = ['https://github.com/dacrypt/wideq/archive/master.zip#wideq==1.3.1'] ATTR_DW_STATE = 'state' ATTR_DW_REMAINING_TIME = 'remaining_time' @@ -22,6 +25,9 @@ ATTR_DW_ERROR = 'error' ATTR_DW_DEVICE_TYPE = 'device_type' +ATTR_AC_STATE = 'state' +ATTR_AC_POWER = 'power' + MAX_RETRIES = 5 KEY_DW_OFF = 'Off' @@ -39,11 +45,15 @@ def setup_platform(hass, config, add_entities, discovery_info=None): client = wideq.Client.from_token(refresh_token, region, language) dishwashers = [] + acs = [] for device_id in hass.data[KEY_SMARTTHINQ_DEVICES]: device = client.get_device(device_id) model = client.model_info(device) + LOGGER.debug('SMARTTHINQ_DEVICE: %s' % device.type) + LOGGER.debug('SMARTTHINQ_DEVICE: %s' % wideq.DeviceType.AC) + if device.type == wideq.DeviceType.DISHWASHER: base_name = "lg_dishwasher_" + device.id LOGGER.debug("Creating new LG DishWasher: %s" % base_name) @@ -53,11 +63,24 @@ def setup_platform(hass, config, add_entities, discovery_info=None): # Dishwashers are only connected when in use. Ignore # NotConnectedError on platform setup. pass + elif device.type == wideq.DeviceType.AC: + # base_name = "lg_ac_" + device.id + base_name = device.name + " Power" + LOGGER.debug("Creating new LG AC power sensot: %s" % base_name) + try: + acs.append(LGACPowerSensor(client, device, base_name)) + except wideq.NotConnectedError: + # AC are only connected when in use. Ignore + # NotConnectedError on platform setup. + pass if dishwashers: add_entities(dishwashers, True) - return True + if acs: + add_entities(acs, True) + + return True class LGDishWasherDevice(LGDevice): def __init__(self, client, device, name): @@ -205,6 +228,207 @@ def update(self): LOGGER.debug('No status available yet.') self._failed_request_count += 1 + if self._failed_request_count >= MAX_RETRIES: + # We tried several times but got no result. This might happen + # when the monitoring request gets into a bad state, so we + # restart the task. + self._restart_monitor() + self._failed_request_count = 0 +# class LGACDevice(LGDevice): +# def __init__(self, client, device, name): +# """Initialize an LG AC Device.""" + +# super().__init__(client, device) + +# # This constructor is called during platform creation. It must not +# # involve any API calls that actually need the ac to be +# # connected, otherwise the device construction will fail and the entity +# # will not get created. Specifically, calls that depend on ac +# # interaction should only happen in update(...), including the start of +# # the monitor task. +# self._ac = ac.ACDevice(client, device) +# self._name = name +# self._status = None +# self._failed_request_count = 0 + +# @property +# def state_attributes(self): +# """Return the optional state attributes for the ac.""" +# data = {} +# # For convenience, include the state as an attribute. +# data[ATTR_AC_STATE] = self.state +# return data + +# @property +# def name(self): +# return self._name + +# @property +# def state(self): +# if self._status: +# # Process is a more refined string to use for state, if it's present, +# # use it instead. +# return self._status.mode.name +# return 'OFF' + +# @property +# def error(self): +# if self._status: +# return self._status.error +# return KEY_AC_DISCONNECTED + +# def _restart_monitor(self): +# try: +# self._ac.monitor_start() +# except wideq.NotConnectedError: +# self._status = None +# except wideq.NotLoggedInError: +# LOGGER.info('Session expired. Refreshing.') +# self._client.refresh() + +# def update(self): +# """Poll for ac state updates.""" + +# # This method is polled, so try to avoid sleeping in here. If an error +# # occurs, it will naturally be retried on the next poll. + +# LOGGER.debug('Updating sensor %s.', self.name) + +# # On initial construction, the ac monitor task +# # will not have been created. If so, start monitoring here. +# if getattr(self._ac, 'mon', None) is None: +# self._restart_monitor() + +# try: +# status = self._ac.poll() +# except wideq.NotConnectedError: +# self._status = None +# return +# except wideq.NotLoggedInError: +# LOGGER.info('Session expired. Refreshing.') +# self._client.refresh() +# self._restart_monitor() +# return + +# if status: +# LOGGER.debug('Status updated.') +# self._status = status +# self._failed_request_count = 0 +# return + +# LOGGER.debug('No status available yet.') +# self._failed_request_count += 1 + +# if self._failed_request_count >= MAX_RETRIES: +# # We tried several times but got no result. This might happen +# # when the monitoring request gets into a bad state, so we +# # restart the task. +# self._restart_monitor() +# self._failed_request_count = 0 + +class LGACPowerSensor(LGDevice): + def __init__(self, client, device, name): + """Initialize an LG AC Power Sensor.""" + + super().__init__(client, device) + + # This constructor is called during platform creation. It must not + # involve any API calls that actually need the ac to be + # connected, otherwise the device construction will fail and the entity + # will not get created. Specifically, calls that depend on ac + # interaction should only happen in update(...), including the start of + # the monitor task. + self._ac = ac.ACDevice(client, device) + self._name = name + # self._status = None + self._state = None + self._unit_of_measurement = POWER_WATT + self._device_class = DEVICE_CLASS_POWER + self._failed_request_count = 0 + + # @property + # def state_attributes(self): + # """Return the optional state attributes for the ac.""" + # data = {} + # data[ATTR_AC_POWER] = self.power + + # # For convenience, include the state as an attribute. + # # data[ATTR_AC_STATE] = self.state + # return data + + @property + def name(self): + """Return the name of the sensor.""" + LOGGER.info('Sensor name: %s', self._name) + return self._name + + @property + def state(self): + """Return the state of the sensor.""" + return self._state + + @property + def unit_of_measurement(self): + """Return the unit of measurement of this entity.""" + return self._unit_of_measurement + + @property + def device_class(self): + """Type of sensor.""" + return self._device_class + + # @property + # def error(self): + # if self._status: + # return self._status.error + # return KEY_AC_DISCONNECTED + + def _restart_monitor(self): + try: + self._ac.monitor_start() + except wideq.NotConnectedError: + self._state = None + except wideq.NotLoggedInError: + LOGGER.info('Session expired. Refreshing.') + self._client.refresh() + + def update(self): + """Poll for ac power updates.""" + + # This method is polled, so try to avoid sleeping in here. If an error + # occurs, it will naturally be retried on the next poll. + + LOGGER.debug('Updating sensor %s.', self.name) + + # On initial construction, the ac monitor task + # will not have been created. If so, start monitoring here. + if getattr(self._ac, 'mon', None) is None: + LOGGER.debug('Restart monitor') + self._restart_monitor() + + try: + state = float(self._ac.get_power()) + LOGGER.debug('Power %d', state) + + except wideq.NotConnectedError: + LOGGER.debug('Not connected') + self._state = None + return + except wideq.NotLoggedInError: + LOGGER.info('Session expired. Refreshing.') + self._client.refresh() + self._restart_monitor() + return + + if state: + LOGGER.debug('state updated. %d', state) + self._state = state + self._failed_request_count = 0 + return + + LOGGER.debug('No state available yet.') + self._failed_request_count += 1 + if self._failed_request_count >= MAX_RETRIES: # We tried several times but got no result. This might happen # when the monitoring request gets into a bad state, so we