146 lines
4.5 KiB
Python
146 lines
4.5 KiB
Python
"""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
|