Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/sensor ac #48

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ def target_temperature(self):

@property
def hvac_modes(self):
LOGGER.debug("hvac_modes")
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps we can take out these extra debug statements now?

return list(MODES.values()) + [c_const.HVAC_MODE_OFF]

@property
Expand All @@ -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
Expand Down
232 changes: 228 additions & 4 deletions sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The . and .wideq don't quite look right—wouldn't that require us to copy the wideq code here?


REQUIREMENTS = ['https://github.com/dacrypt/wideq/archive/master.zip#wideq==1.3.1']
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could be wrong, but I thought this was already enforced in the top-level module?


ATTR_DW_STATE = 'state'
ATTR_DW_REMAINING_TIME = 'remaining_time'
Expand All @@ -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'
Expand All @@ -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)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also perhaps unnecessary now? Or perhaps we could just make the messages more readable with English phrases?


if device.type == wideq.DeviceType.DISHWASHER:
base_name = "lg_dishwasher_" + device.id
LOGGER.debug("Creating new LG DishWasher: %s" % base_name)
Expand All @@ -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
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Delete?

base_name = device.name + " Power"
LOGGER.debug("Creating new LG AC power sensot: %s" % base_name)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sensot (spelling)

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):
Expand Down Expand Up @@ -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):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe delete this stuff that's no longer in use?

# 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
Expand Down