Add (EU-based) Honeywell evohome CH/DHW controller (#16427)
* Add support for Honeywell evohome CH/DHW systems More flake8 corrections Passes Flake8 tests Almost passed flake8.pylint! Passed all tox tests Now it needs serious testing! Almost ready to submit BUGFIX: DHW state now functional More improvements to available() Solved the DHW temp units problem! Last minute bug squash to improve dicts merge Trying to rebase fixing more rbase errors revert to creating HTTP_error_code internally for now ready to submit PR Added support for Honeywell evohome CH/DHW systems * Updated requirements_test_all.txt * Fix: D401 First line should be in imperative mood * Remove _LOGGER.info (replace with _LOGGER.debug) * raise PlatformNotReady when RequestException during setup() * Revert some LOGGER.debug to LOGGER.warning * Improved logging levels, and removed some unwanted comments * Improvments to logging - additional self._status info * BUGFIX: DHW wrongly showing available = False (and some other tweaks) * Fix trailing whitespace * Remove state_attributes override and API_VER code * Removed heating zones, DHW and heuristics to reduce # lines of code * Removed some more lines of code * Removed unused configuration parameters * Remove some more un-needed lines * Removed more (uneeded) lines of code & fixed two minor typos * Improvements to debug logging of available() = False * Improvements to code, and code clean-up * Corrected a minor typo * A small tidy up * reduces precision of emulated temps floats to 0.1 * Some code improvements as suggested by JeardM * Rewrite of exception handler * Removed another unwanted logging in properties * Remove async_ version of various methods * moved available heuristics to update() * Cleanup of code, and re-work linter hints * fixed a minor documentation typo * scan_interval is now no longer a configurable option * Change from Master/Slave to Parent/Child * Removed the last of the slaves * Removed the last of the masters * Move -PARALLEL_UPDATES to .\climate\evohome.py' * main code moved to climate/evohome.py * merge EvoEntity into EvoController class * remove should_poll (for now) * woops! left a hint in * removed icon * only log a WARNING the first time available = False * cleanup dodgy exception handling * Tidy up exception handling * Many changes as suggested by @MartinHjelmare, thanks * remove hass from init, part 1 * use async_added_to_hass instead of dispatcher_connect * remove hass from init, part 2 (done) * add 1-2 arrays, and tidied up some comments * from dispatcher to async_added_to_hass * cleaned up some logging, and removed others * Many changes as request by @MartinHjelmare * Homage to the lint * Changed to the HA of doing operating_mode * Now using update_before_add=True * reduced logging further still... * fixed minor lint * fix a small logic error * Add device_state_attributes to track actual operating mode * Clean up doc quotes caused by previous changes * Woops! removed some debug lines that shoudln't have stayed in * Add a complete set of device_state_attributes * Cleanup some constants * Remove more legacy code * domain_data to evo_data & this else should be a finally * minor change for readability * Minor change for readability #2 * removed unused code * small tidy up - no code changes * fix minor lint * Correct URLs & descriptions in docstring * whoops - fixed a typo in docstrings * remove an unused line of cide & a small tidy-uppull/16919/head
parent
2cc6263092
commit
8d65230a36
|
@ -105,6 +105,9 @@ omit =
|
|||
homeassistant/components/envisalink.py
|
||||
homeassistant/components/*/envisalink.py
|
||||
|
||||
homeassistant/components/evohome.py
|
||||
homeassistant/components/*/evohome.py
|
||||
|
||||
homeassistant/components/fritzbox.py
|
||||
homeassistant/components/switch/fritzbox.py
|
||||
|
||||
|
|
|
@ -0,0 +1,371 @@
|
|||
"""Support for Honeywell evohome (EMEA/EU-based systems only).
|
||||
|
||||
Support for a temperature control system (TCS, controller) with 0+ heating
|
||||
zones (e.g. TRVs, relays) and, optionally, a DHW controller.
|
||||
|
||||
For more details about this platform, please refer to the documentation at
|
||||
https://home-assistant.io/components/climate.evohome/
|
||||
"""
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
import logging
|
||||
|
||||
from requests.exceptions import HTTPError
|
||||
|
||||
from homeassistant.components.climate import (
|
||||
ClimateDevice,
|
||||
STATE_AUTO,
|
||||
STATE_ECO,
|
||||
STATE_OFF,
|
||||
SUPPORT_OPERATION_MODE,
|
||||
SUPPORT_AWAY_MODE,
|
||||
)
|
||||
from homeassistant.components.evohome import (
|
||||
CONF_LOCATION_IDX,
|
||||
DATA_EVOHOME,
|
||||
MAX_TEMP,
|
||||
MIN_TEMP,
|
||||
SCAN_INTERVAL_MAX
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONF_SCAN_INTERVAL,
|
||||
PRECISION_TENTHS,
|
||||
TEMP_CELSIUS,
|
||||
HTTP_TOO_MANY_REQUESTS,
|
||||
)
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
# these are for the controller's opmode/state and the zone's state
|
||||
EVO_RESET = 'AutoWithReset'
|
||||
EVO_AUTO = 'Auto'
|
||||
EVO_AUTOECO = 'AutoWithEco'
|
||||
EVO_AWAY = 'Away'
|
||||
EVO_DAYOFF = 'DayOff'
|
||||
EVO_CUSTOM = 'Custom'
|
||||
EVO_HEATOFF = 'HeatingOff'
|
||||
|
||||
EVO_STATE_TO_HA = {
|
||||
EVO_RESET: STATE_AUTO,
|
||||
EVO_AUTO: STATE_AUTO,
|
||||
EVO_AUTOECO: STATE_ECO,
|
||||
EVO_AWAY: STATE_AUTO,
|
||||
EVO_DAYOFF: STATE_AUTO,
|
||||
EVO_CUSTOM: STATE_AUTO,
|
||||
EVO_HEATOFF: STATE_OFF
|
||||
}
|
||||
|
||||
HA_STATE_TO_EVO = {
|
||||
STATE_AUTO: EVO_AUTO,
|
||||
STATE_ECO: EVO_AUTOECO,
|
||||
STATE_OFF: EVO_HEATOFF
|
||||
}
|
||||
|
||||
HA_OP_LIST = list(HA_STATE_TO_EVO)
|
||||
|
||||
# these are used to help prevent E501 (line too long) violations
|
||||
GWS = 'gateways'
|
||||
TCS = 'temperatureControlSystems'
|
||||
|
||||
# debug codes - these happen occasionally, but the cause is unknown
|
||||
EVO_DEBUG_NO_RECENT_UPDATES = '0x01'
|
||||
EVO_DEBUG_NO_STATUS = '0x02'
|
||||
|
||||
|
||||
def setup_platform(hass, config, add_entities, discovery_info=None):
|
||||
"""Create a Honeywell (EMEA/EU) evohome CH/DHW system.
|
||||
|
||||
An evohome system consists of: a controller, with 0-12 heating zones (e.g.
|
||||
TRVs, relays) and, optionally, a DHW controller (a HW boiler).
|
||||
|
||||
Here, we add the controller only.
|
||||
"""
|
||||
evo_data = hass.data[DATA_EVOHOME]
|
||||
|
||||
client = evo_data['client']
|
||||
loc_idx = evo_data['params'][CONF_LOCATION_IDX]
|
||||
|
||||
# evohomeclient has no defined way of accessing non-default location other
|
||||
# than using a protected member, such as below
|
||||
tcs_obj_ref = client.locations[loc_idx]._gateways[0]._control_systems[0] # noqa E501; pylint: disable=protected-access
|
||||
|
||||
_LOGGER.debug(
|
||||
"setup_platform(): Found Controller: id: %s [%s], type: %s",
|
||||
tcs_obj_ref.systemId,
|
||||
tcs_obj_ref.location.name,
|
||||
tcs_obj_ref.modelType
|
||||
)
|
||||
parent = EvoController(evo_data, client, tcs_obj_ref)
|
||||
add_entities([parent], update_before_add=True)
|
||||
|
||||
|
||||
class EvoController(ClimateDevice):
|
||||
"""Base for a Honeywell evohome hub/Controller device.
|
||||
|
||||
The Controller (aka TCS, temperature control system) is the parent of all
|
||||
the child (CH/DHW) devices.
|
||||
"""
|
||||
|
||||
def __init__(self, evo_data, client, obj_ref):
|
||||
"""Initialize the evohome entity.
|
||||
|
||||
Most read-only properties are set here. So are pseudo read-only,
|
||||
for example name (which _could_ change between update()s).
|
||||
"""
|
||||
self.client = client
|
||||
self._obj = obj_ref
|
||||
|
||||
self._id = obj_ref.systemId
|
||||
self._name = evo_data['config']['locationInfo']['name']
|
||||
|
||||
self._config = evo_data['config'][GWS][0][TCS][0]
|
||||
self._params = evo_data['params']
|
||||
self._timers = evo_data['timers']
|
||||
|
||||
self._timers['statusUpdated'] = datetime.min
|
||||
self._status = {}
|
||||
|
||||
self._available = False # should become True after first update()
|
||||
|
||||
def _handle_requests_exceptions(self, err):
|
||||
# evohomeclient v2 api (>=0.2.7) exposes requests exceptions, incl.:
|
||||
# - HTTP_BAD_REQUEST, is usually Bad user credentials
|
||||
# - HTTP_TOO_MANY_REQUESTS, is api usuage limit exceeded
|
||||
# - HTTP_SERVICE_UNAVAILABLE, is often Vendor's fault
|
||||
|
||||
if err.response.status_code == HTTP_TOO_MANY_REQUESTS:
|
||||
# execute a back off: pause, and reduce rate
|
||||
old_scan_interval = self._params[CONF_SCAN_INTERVAL]
|
||||
new_scan_interval = min(old_scan_interval * 2, SCAN_INTERVAL_MAX)
|
||||
self._params[CONF_SCAN_INTERVAL] = new_scan_interval
|
||||
|
||||
_LOGGER.warning(
|
||||
"API rate limit has been exceeded: increasing '%s' from %s to "
|
||||
"%s seconds, and suspending polling for %s seconds.",
|
||||
CONF_SCAN_INTERVAL,
|
||||
old_scan_interval,
|
||||
new_scan_interval,
|
||||
new_scan_interval * 3
|
||||
)
|
||||
|
||||
self._timers['statusUpdated'] = datetime.now() + \
|
||||
timedelta(seconds=new_scan_interval * 3)
|
||||
|
||||
else:
|
||||
raise err
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the name to use in the frontend UI."""
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def available(self):
|
||||
"""Return True if the device is available.
|
||||
|
||||
All evohome entities are initially unavailable. Once HA has started,
|
||||
state data is then retrieved by the Controller, and then the children
|
||||
will get a state (e.g. operating_mode, current_temperature).
|
||||
|
||||
However, evohome entities can become unavailable for other reasons.
|
||||
"""
|
||||
return self._available
|
||||
|
||||
@property
|
||||
def supported_features(self):
|
||||
"""Get the list of supported features of the Controller."""
|
||||
return SUPPORT_OPERATION_MODE | SUPPORT_AWAY_MODE
|
||||
|
||||
@property
|
||||
def device_state_attributes(self):
|
||||
"""Return the device state attributes of the controller.
|
||||
|
||||
This is operating mode state data that is not available otherwise, due
|
||||
to the restrictions placed upon ClimateDevice properties, etc by HA.
|
||||
"""
|
||||
data = {}
|
||||
data['systemMode'] = self._status['systemModeStatus']['mode']
|
||||
data['isPermanent'] = self._status['systemModeStatus']['isPermanent']
|
||||
if 'timeUntil' in self._status['systemModeStatus']:
|
||||
data['timeUntil'] = self._status['systemModeStatus']['timeUntil']
|
||||
data['activeFaults'] = self._status['activeFaults']
|
||||
return data
|
||||
|
||||
@property
|
||||
def operation_list(self):
|
||||
"""Return the list of available operations."""
|
||||
return HA_OP_LIST
|
||||
|
||||
@property
|
||||
def current_operation(self):
|
||||
"""Return the operation mode of the evohome entity."""
|
||||
return EVO_STATE_TO_HA.get(self._status['systemModeStatus']['mode'])
|
||||
|
||||
@property
|
||||
def target_temperature(self):
|
||||
"""Return the average target temperature of the Heating/DHW zones."""
|
||||
temps = [zone['setpointStatus']['targetHeatTemperature']
|
||||
for zone in self._status['zones']]
|
||||
|
||||
avg_temp = round(sum(temps) / len(temps), 1) if temps else None
|
||||
return avg_temp
|
||||
|
||||
@property
|
||||
def current_temperature(self):
|
||||
"""Return the average current temperature of the Heating/DHW zones."""
|
||||
tmp_list = [x for x in self._status['zones']
|
||||
if x['temperatureStatus']['isAvailable'] is True]
|
||||
temps = [zone['temperatureStatus']['temperature'] for zone in tmp_list]
|
||||
|
||||
avg_temp = round(sum(temps) / len(temps), 1) if temps else None
|
||||
return avg_temp
|
||||
|
||||
@property
|
||||
def temperature_unit(self):
|
||||
"""Return the temperature unit to use in the frontend UI."""
|
||||
return TEMP_CELSIUS
|
||||
|
||||
@property
|
||||
def precision(self):
|
||||
"""Return the temperature precision to use in the frontend UI."""
|
||||
return PRECISION_TENTHS
|
||||
|
||||
@property
|
||||
def min_temp(self):
|
||||
"""Return the minimum target temp (setpoint) of a evohome entity."""
|
||||
return MIN_TEMP
|
||||
|
||||
@property
|
||||
def max_temp(self):
|
||||
"""Return the maximum target temp (setpoint) of a evohome entity."""
|
||||
return MAX_TEMP
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
"""Return true as evohome controllers are always on.
|
||||
|
||||
Operating modes can include 'HeatingOff', but (for example) DHW would
|
||||
remain on.
|
||||
"""
|
||||
return True
|
||||
|
||||
@property
|
||||
def is_away_mode_on(self):
|
||||
"""Return true if away mode is on."""
|
||||
return self._status['systemModeStatus']['mode'] == EVO_AWAY
|
||||
|
||||
def turn_away_mode_on(self):
|
||||
"""Turn away mode on."""
|
||||
self._set_operation_mode(EVO_AWAY)
|
||||
|
||||
def turn_away_mode_off(self):
|
||||
"""Turn away mode off."""
|
||||
self._set_operation_mode(EVO_AUTO)
|
||||
|
||||
def _set_operation_mode(self, operation_mode):
|
||||
# Set new target operation mode for the TCS.
|
||||
_LOGGER.debug(
|
||||
"_set_operation_mode(): API call [1 request(s)]: "
|
||||
"tcs._set_status(%s)...",
|
||||
operation_mode
|
||||
)
|
||||
try:
|
||||
self._obj._set_status(operation_mode) # noqa: E501; pylint: disable=protected-access
|
||||
except HTTPError as err:
|
||||
self._handle_requests_exceptions(err)
|
||||
|
||||
def set_operation_mode(self, operation_mode):
|
||||
"""Set new target operation mode for the TCS.
|
||||
|
||||
Currently limited to 'Auto', 'AutoWithEco' & 'HeatingOff'. If 'Away'
|
||||
mode is needed, it can be enabled via turn_away_mode_on method.
|
||||
"""
|
||||
self._set_operation_mode(HA_STATE_TO_EVO.get(operation_mode))
|
||||
|
||||
def _update_state_data(self, evo_data):
|
||||
client = evo_data['client']
|
||||
loc_idx = evo_data['params'][CONF_LOCATION_IDX]
|
||||
|
||||
_LOGGER.debug(
|
||||
"_update_state_data(): API call [1 request(s)]: "
|
||||
"client.locations[loc_idx].status()..."
|
||||
)
|
||||
|
||||
try:
|
||||
evo_data['status'].update(
|
||||
client.locations[loc_idx].status()[GWS][0][TCS][0])
|
||||
except HTTPError as err: # check if we've exceeded the api rate limit
|
||||
self._handle_requests_exceptions(err)
|
||||
else:
|
||||
evo_data['timers']['statusUpdated'] = datetime.now()
|
||||
|
||||
_LOGGER.debug(
|
||||
"_update_state_data(): evo_data['status'] = %s",
|
||||
evo_data['status']
|
||||
)
|
||||
|
||||
def update(self):
|
||||
"""Get the latest state data of the installation.
|
||||
|
||||
This includes state data for the Controller and its child devices, such
|
||||
as the operating_mode of the Controller and the current_temperature
|
||||
of its children.
|
||||
|
||||
This is not asyncio-friendly due to the underlying client api.
|
||||
"""
|
||||
evo_data = self.hass.data[DATA_EVOHOME]
|
||||
|
||||
timeout = datetime.now() + timedelta(seconds=55)
|
||||
expired = timeout > self._timers['statusUpdated'] + \
|
||||
timedelta(seconds=evo_data['params'][CONF_SCAN_INTERVAL])
|
||||
|
||||
if not expired:
|
||||
return
|
||||
|
||||
was_available = self._available or \
|
||||
self._timers['statusUpdated'] == datetime.min
|
||||
|
||||
self._update_state_data(evo_data)
|
||||
self._status = evo_data['status']
|
||||
|
||||
if _LOGGER.isEnabledFor(logging.DEBUG):
|
||||
tmp_dict = dict(self._status)
|
||||
if 'zones' in tmp_dict:
|
||||
tmp_dict['zones'] = '...'
|
||||
if 'dhw' in tmp_dict:
|
||||
tmp_dict['dhw'] = '...'
|
||||
|
||||
_LOGGER.debug(
|
||||
"update(%s), self._status = %s",
|
||||
self._id + " [" + self._name + "]",
|
||||
tmp_dict
|
||||
)
|
||||
|
||||
no_recent_updates = self._timers['statusUpdated'] < datetime.now() - \
|
||||
timedelta(seconds=self._params[CONF_SCAN_INTERVAL] * 3.1)
|
||||
|
||||
if no_recent_updates:
|
||||
self._available = False
|
||||
debug_code = EVO_DEBUG_NO_RECENT_UPDATES
|
||||
|
||||
elif not self._status:
|
||||
# unavailable because no status (but how? other than at startup?)
|
||||
self._available = False
|
||||
debug_code = EVO_DEBUG_NO_STATUS
|
||||
|
||||
else:
|
||||
self._available = True
|
||||
|
||||
if not self._available and was_available:
|
||||
# only warn if available went from True to False
|
||||
_LOGGER.warning(
|
||||
"The entity, %s, has become unavailable, debug code is: %s",
|
||||
self._id + " [" + self._name + "]",
|
||||
debug_code
|
||||
)
|
||||
|
||||
elif self._available and not was_available:
|
||||
# this isn't the first re-available (e.g. _after_ STARTUP)
|
||||
_LOGGER.debug(
|
||||
"The entity, %s, has become available",
|
||||
self._id + " [" + self._name + "]"
|
||||
)
|
|
@ -20,7 +20,7 @@ from homeassistant.const import (
|
|||
CONF_PASSWORD, CONF_USERNAME, TEMP_CELSIUS, TEMP_FAHRENHEIT,
|
||||
ATTR_TEMPERATURE, CONF_REGION)
|
||||
|
||||
REQUIREMENTS = ['evohomeclient==0.2.5', 'somecomfort==0.5.2']
|
||||
REQUIREMENTS = ['evohomeclient==0.2.7', 'somecomfort==0.5.2']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
|
|
@ -0,0 +1,145 @@
|
|||
"""Support for Honeywell evohome (EMEA/EU-based systems only).
|
||||
|
||||
Support for a temperature control system (TCS, controller) with 0+ heating
|
||||
zones (e.g. TRVs, relays) and, optionally, a DHW controller.
|
||||
|
||||
For more details about this component, please refer to the documentation at
|
||||
https://home-assistant.io/components/evohome/
|
||||
"""
|
||||
|
||||
# Glossary:
|
||||
# TCS - temperature control system (a.k.a. Controller, Parent), which can
|
||||
# have up to 13 Children:
|
||||
# 0-12 Heating zones (a.k.a. Zone), and
|
||||
# 0-1 DHW controller, (a.k.a. Boiler)
|
||||
|
||||
import logging
|
||||
|
||||
from requests.exceptions import HTTPError
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.const import (
|
||||
CONF_USERNAME,
|
||||
CONF_PASSWORD,
|
||||
CONF_SCAN_INTERVAL,
|
||||
HTTP_BAD_REQUEST
|
||||
)
|
||||
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.discovery import load_platform
|
||||
|
||||
REQUIREMENTS = ['evohomeclient==0.2.7']
|
||||
# If ever > 0.2.7, re-check the work-around wrapper is still required when
|
||||
# instantiating the client, below.
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DOMAIN = 'evohome'
|
||||
DATA_EVOHOME = 'data_' + DOMAIN
|
||||
|
||||
CONF_LOCATION_IDX = 'location_idx'
|
||||
MAX_TEMP = 28
|
||||
MIN_TEMP = 5
|
||||
SCAN_INTERVAL_DEFAULT = 180
|
||||
SCAN_INTERVAL_MAX = 300
|
||||
|
||||
CONFIG_SCHEMA = vol.Schema({
|
||||
DOMAIN: vol.Schema({
|
||||
vol.Required(CONF_USERNAME): cv.string,
|
||||
vol.Required(CONF_PASSWORD): cv.string,
|
||||
vol.Optional(CONF_LOCATION_IDX, default=0): cv.positive_int,
|
||||
}),
|
||||
}, extra=vol.ALLOW_EXTRA)
|
||||
|
||||
# These are used to help prevent E501 (line too long) violations.
|
||||
GWS = 'gateways'
|
||||
TCS = 'temperatureControlSystems'
|
||||
|
||||
|
||||
def setup(hass, config):
|
||||
"""Create a Honeywell (EMEA/EU) evohome CH/DHW system.
|
||||
|
||||
One controller with 0+ heating zones (e.g. TRVs, relays) and, optionally, a
|
||||
DHW controller. Does not work for US-based systems.
|
||||
"""
|
||||
evo_data = hass.data[DATA_EVOHOME] = {}
|
||||
evo_data['timers'] = {}
|
||||
|
||||
evo_data['params'] = dict(config[DOMAIN])
|
||||
evo_data['params'][CONF_SCAN_INTERVAL] = SCAN_INTERVAL_DEFAULT
|
||||
|
||||
from evohomeclient2 import EvohomeClient
|
||||
|
||||
_LOGGER.debug("setup(): API call [4 request(s)]: client.__init__()...")
|
||||
|
||||
try:
|
||||
# There's a bug in evohomeclient2 v0.2.7: the client.__init__() sets
|
||||
# the root loglevel when EvohomeClient(debug=?), so remember it now...
|
||||
log_level = logging.getLogger().getEffectiveLevel()
|
||||
|
||||
client = EvohomeClient(
|
||||
evo_data['params'][CONF_USERNAME],
|
||||
evo_data['params'][CONF_PASSWORD],
|
||||
debug=False
|
||||
)
|
||||
# ...then restore it to what it was before instantiating the client
|
||||
logging.getLogger().setLevel(log_level)
|
||||
|
||||
except HTTPError as err:
|
||||
if err.response.status_code == HTTP_BAD_REQUEST:
|
||||
_LOGGER.error(
|
||||
"Failed to establish a connection with evohome web servers, "
|
||||
"Check your username (%s), and password are correct."
|
||||
"Unable to continue. Resolve any errors and restart HA.",
|
||||
evo_data['params'][CONF_USERNAME]
|
||||
)
|
||||
return False # unable to continue
|
||||
|
||||
raise # we dont handle any other HTTPErrors
|
||||
|
||||
finally: # Redact username, password as no longer needed.
|
||||
evo_data['params'][CONF_USERNAME] = 'REDACTED'
|
||||
evo_data['params'][CONF_PASSWORD] = 'REDACTED'
|
||||
|
||||
evo_data['client'] = client
|
||||
|
||||
# Redact any installation data we'll never need.
|
||||
if client.installation_info[0]['locationInfo']['locationId'] != 'REDACTED':
|
||||
for loc in client.installation_info:
|
||||
loc['locationInfo']['streetAddress'] = 'REDACTED'
|
||||
loc['locationInfo']['city'] = 'REDACTED'
|
||||
loc['locationInfo']['locationOwner'] = 'REDACTED'
|
||||
loc[GWS][0]['gatewayInfo'] = 'REDACTED'
|
||||
|
||||
# Pull down the installation configuration.
|
||||
loc_idx = evo_data['params'][CONF_LOCATION_IDX]
|
||||
|
||||
try:
|
||||
evo_data['config'] = client.installation_info[loc_idx]
|
||||
|
||||
except IndexError:
|
||||
_LOGGER.warning(
|
||||
"setup(): Parameter '%s' = %s , is outside its range (0-%s)",
|
||||
CONF_LOCATION_IDX,
|
||||
loc_idx,
|
||||
len(client.installation_info) - 1
|
||||
)
|
||||
|
||||
return False # unable to continue
|
||||
|
||||
evo_data['status'] = {}
|
||||
|
||||
if _LOGGER.isEnabledFor(logging.DEBUG):
|
||||
tmp_loc = dict(evo_data['config'])
|
||||
tmp_loc['locationInfo']['postcode'] = 'REDACTED'
|
||||
tmp_tcs = tmp_loc[GWS][0][TCS][0]
|
||||
if 'zones' in tmp_tcs:
|
||||
tmp_tcs['zones'] = '...'
|
||||
if 'dhw' in tmp_tcs:
|
||||
tmp_tcs['dhw'] = '...'
|
||||
|
||||
_LOGGER.debug("setup(), location = %s", tmp_loc)
|
||||
|
||||
load_platform(hass, 'climate', DOMAIN)
|
||||
|
||||
return True
|
|
@ -410,7 +410,9 @@ HTTP_UNAUTHORIZED = 401
|
|||
HTTP_NOT_FOUND = 404
|
||||
HTTP_METHOD_NOT_ALLOWED = 405
|
||||
HTTP_UNPROCESSABLE_ENTITY = 422
|
||||
HTTP_TOO_MANY_REQUESTS = 429
|
||||
HTTP_INTERNAL_SERVER_ERROR = 500
|
||||
HTTP_SERVICE_UNAVAILABLE = 503
|
||||
|
||||
HTTP_BASIC_AUTHENTICATION = 'basic'
|
||||
HTTP_DIGEST_AUTHENTICATION = 'digest'
|
||||
|
|
|
@ -338,8 +338,9 @@ eternalegypt==0.0.5
|
|||
# homeassistant.components.keyboard_remote
|
||||
# evdev==0.6.1
|
||||
|
||||
# homeassistant.components.evohome
|
||||
# homeassistant.components.climate.honeywell
|
||||
evohomeclient==0.2.5
|
||||
evohomeclient==0.2.7
|
||||
|
||||
# homeassistant.components.image_processing.dlib_face_detect
|
||||
# homeassistant.components.image_processing.dlib_face_identify
|
||||
|
|
|
@ -52,8 +52,9 @@ dsmr_parser==0.11
|
|||
# homeassistant.components.sensor.season
|
||||
ephem==3.7.6.0
|
||||
|
||||
# homeassistant.components.evohome
|
||||
# homeassistant.components.climate.honeywell
|
||||
evohomeclient==0.2.5
|
||||
evohomeclient==0.2.7
|
||||
|
||||
# homeassistant.components.feedreader
|
||||
# homeassistant.components.sensor.geo_rss_events
|
||||
|
|
Loading…
Reference in New Issue