2019-02-13 20:21:14 +00:00
|
|
|
"""Support for Ecobee Thermostats."""
|
2016-08-19 07:17:28 +00:00
|
|
|
import logging
|
2016-09-07 18:21:42 +00:00
|
|
|
|
2016-08-19 07:17:28 +00:00
|
|
|
import voluptuous as vol
|
|
|
|
|
|
|
|
from homeassistant.components import ecobee
|
2019-02-14 19:34:43 +00:00
|
|
|
from homeassistant.components.climate import ClimateDevice
|
|
|
|
from homeassistant.components.climate.const import (
|
|
|
|
DOMAIN, STATE_COOL, STATE_HEAT, STATE_AUTO, STATE_IDLE,
|
2017-11-29 10:01:28 +00:00
|
|
|
ATTR_TARGET_TEMP_LOW, ATTR_TARGET_TEMP_HIGH, SUPPORT_TARGET_TEMPERATURE,
|
|
|
|
SUPPORT_AWAY_MODE, SUPPORT_HOLD_MODE, SUPPORT_OPERATION_MODE,
|
2018-02-02 09:11:13 +00:00
|
|
|
SUPPORT_TARGET_HUMIDITY_LOW, SUPPORT_TARGET_HUMIDITY_HIGH,
|
2018-03-18 16:02:07 +00:00
|
|
|
SUPPORT_AUX_HEAT, SUPPORT_TARGET_TEMPERATURE_HIGH, SUPPORT_FAN_MODE,
|
2019-02-14 19:34:43 +00:00
|
|
|
SUPPORT_TARGET_TEMPERATURE_LOW)
|
2016-08-19 07:17:28 +00:00
|
|
|
from homeassistant.const import (
|
2019-02-14 19:34:43 +00:00
|
|
|
ATTR_ENTITY_ID, STATE_ON, STATE_OFF, ATTR_TEMPERATURE, TEMP_FAHRENHEIT)
|
2016-08-19 07:17:28 +00:00
|
|
|
import homeassistant.helpers.config_validation as cv
|
|
|
|
|
|
|
|
_CONFIGURING = {}
|
2016-09-07 18:21:42 +00:00
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
ATTR_FAN_MIN_ON_TIME = 'fan_min_on_time'
|
2016-12-27 20:56:26 +00:00
|
|
|
ATTR_RESUME_ALL = 'resume_all'
|
|
|
|
|
|
|
|
DEFAULT_RESUME_ALL = False
|
Additional support for ecobee hold mode (#6258)
* Integrate suggestion in #5590 by nordlead2005. This change has been
sitting in limbo for over a month, but it is a good idea. I don't
mean to step on nordlead2005's toes, but we need to make progress.
* Use defined constant for TEMPERATURE_HOLD
* Integrate handling of vacation into hold mode. Canceling vacation
hold requires an update to the external pyecobee library. Creation
of vacation is not supported (it would be straightforward in the code,
but a complex user interface would be required, similar to what is
now done in the ecobee thermostat).
* Add capability to retrieve list of defined climates from ecobee.
* The mode() method used to return the system mode in internal
representation. However, the user sees a different notation in
the ecobee thermostat. Seeing some internal name is particularly
weired with user-defined climates, where these are named "smart1",
"smart2", etc., instead of the name the user has defined. Return
the user-defined name instead. This change might break some user
interfaces but is easily remedied (e.g., use "Away" instead of
"away").
* Simplify is_away_mode_on().
* Correction of erroneously indented else statement.
* Change comment as flake8 gets confused.
2017-03-02 07:52:31 +00:00
|
|
|
TEMPERATURE_HOLD = 'temp'
|
|
|
|
VACATION_HOLD = 'vacation'
|
2017-09-29 14:57:31 +00:00
|
|
|
AWAY_MODE = 'awayMode'
|
2016-09-07 18:21:42 +00:00
|
|
|
|
|
|
|
DEPENDENCIES = ['ecobee']
|
|
|
|
|
|
|
|
SERVICE_SET_FAN_MIN_ON_TIME = 'ecobee_set_fan_min_on_time'
|
2016-12-27 20:56:26 +00:00
|
|
|
SERVICE_RESUME_PROGRAM = 'ecobee_resume_program'
|
2016-08-19 07:17:28 +00:00
|
|
|
|
|
|
|
SET_FAN_MIN_ON_TIME_SCHEMA = vol.Schema({
|
|
|
|
vol.Optional(ATTR_ENTITY_ID): cv.entity_ids,
|
|
|
|
vol.Required(ATTR_FAN_MIN_ON_TIME): vol.Coerce(int),
|
|
|
|
})
|
|
|
|
|
2016-12-27 20:56:26 +00:00
|
|
|
RESUME_PROGRAM_SCHEMA = vol.Schema({
|
|
|
|
vol.Optional(ATTR_ENTITY_ID): cv.entity_ids,
|
|
|
|
vol.Optional(ATTR_RESUME_ALL, default=DEFAULT_RESUME_ALL): cv.boolean,
|
|
|
|
})
|
|
|
|
|
2017-11-29 10:01:28 +00:00
|
|
|
SUPPORT_FLAGS = (SUPPORT_TARGET_TEMPERATURE | SUPPORT_AWAY_MODE |
|
|
|
|
SUPPORT_HOLD_MODE | SUPPORT_OPERATION_MODE |
|
2018-02-02 09:11:13 +00:00
|
|
|
SUPPORT_TARGET_HUMIDITY_LOW | SUPPORT_TARGET_HUMIDITY_HIGH |
|
2018-02-05 08:21:20 +00:00
|
|
|
SUPPORT_AUX_HEAT | SUPPORT_TARGET_TEMPERATURE_HIGH |
|
2018-03-18 16:02:07 +00:00
|
|
|
SUPPORT_TARGET_TEMPERATURE_LOW | SUPPORT_FAN_MODE)
|
2017-11-29 10:01:28 +00:00
|
|
|
|
2016-08-19 07:17:28 +00:00
|
|
|
|
2018-08-24 14:37:30 +00:00
|
|
|
def setup_platform(hass, config, add_entities, discovery_info=None):
|
2017-04-30 05:04:49 +00:00
|
|
|
"""Set up the Ecobee Thermostat Platform."""
|
2016-08-19 07:17:28 +00:00
|
|
|
if discovery_info is None:
|
|
|
|
return
|
|
|
|
data = ecobee.NETWORK
|
|
|
|
hold_temp = discovery_info['hold_temp']
|
|
|
|
_LOGGER.info(
|
|
|
|
"Loading ecobee thermostat component with hold_temp set to %s",
|
|
|
|
hold_temp)
|
|
|
|
devices = [Thermostat(data, index, hold_temp)
|
|
|
|
for index in range(len(data.ecobee.thermostats))]
|
2018-08-24 14:37:30 +00:00
|
|
|
add_entities(devices)
|
2016-08-19 07:17:28 +00:00
|
|
|
|
|
|
|
def fan_min_on_time_set_service(service):
|
|
|
|
"""Set the minimum fan on time on the target thermostats."""
|
2016-12-27 20:56:26 +00:00
|
|
|
entity_id = service.data.get(ATTR_ENTITY_ID)
|
|
|
|
fan_min_on_time = service.data[ATTR_FAN_MIN_ON_TIME]
|
2016-08-19 07:17:28 +00:00
|
|
|
|
|
|
|
if entity_id:
|
|
|
|
target_thermostats = [device for device in devices
|
2016-12-27 20:56:26 +00:00
|
|
|
if device.entity_id in entity_id]
|
2016-08-19 07:17:28 +00:00
|
|
|
else:
|
|
|
|
target_thermostats = devices
|
|
|
|
|
|
|
|
for thermostat in target_thermostats:
|
|
|
|
thermostat.set_fan_min_on_time(str(fan_min_on_time))
|
|
|
|
|
2017-02-02 05:44:05 +00:00
|
|
|
thermostat.schedule_update_ha_state(True)
|
2016-08-19 07:17:28 +00:00
|
|
|
|
2016-12-27 20:56:26 +00:00
|
|
|
def resume_program_set_service(service):
|
|
|
|
"""Resume the program on the target thermostats."""
|
|
|
|
entity_id = service.data.get(ATTR_ENTITY_ID)
|
|
|
|
resume_all = service.data.get(ATTR_RESUME_ALL)
|
|
|
|
|
|
|
|
if entity_id:
|
|
|
|
target_thermostats = [device for device in devices
|
|
|
|
if device.entity_id in entity_id]
|
|
|
|
else:
|
|
|
|
target_thermostats = devices
|
|
|
|
|
|
|
|
for thermostat in target_thermostats:
|
|
|
|
thermostat.resume_program(resume_all)
|
|
|
|
|
2017-02-02 05:44:05 +00:00
|
|
|
thermostat.schedule_update_ha_state(True)
|
2016-12-27 20:56:26 +00:00
|
|
|
|
2016-08-19 07:17:28 +00:00
|
|
|
hass.services.register(
|
|
|
|
DOMAIN, SERVICE_SET_FAN_MIN_ON_TIME, fan_min_on_time_set_service,
|
|
|
|
schema=SET_FAN_MIN_ON_TIME_SCHEMA)
|
|
|
|
|
2016-12-27 20:56:26 +00:00
|
|
|
hass.services.register(
|
|
|
|
DOMAIN, SERVICE_RESUME_PROGRAM, resume_program_set_service,
|
|
|
|
schema=RESUME_PROGRAM_SCHEMA)
|
|
|
|
|
2016-08-19 07:17:28 +00:00
|
|
|
|
|
|
|
class Thermostat(ClimateDevice):
|
|
|
|
"""A thermostat class for Ecobee."""
|
|
|
|
|
|
|
|
def __init__(self, data, thermostat_index, hold_temp):
|
|
|
|
"""Initialize the thermostat."""
|
|
|
|
self.data = data
|
|
|
|
self.thermostat_index = thermostat_index
|
|
|
|
self.thermostat = self.data.ecobee.get_thermostat(
|
|
|
|
self.thermostat_index)
|
|
|
|
self._name = self.thermostat['name']
|
|
|
|
self.hold_temp = hold_temp
|
Additional support for ecobee hold mode (#6258)
* Integrate suggestion in #5590 by nordlead2005. This change has been
sitting in limbo for over a month, but it is a good idea. I don't
mean to step on nordlead2005's toes, but we need to make progress.
* Use defined constant for TEMPERATURE_HOLD
* Integrate handling of vacation into hold mode. Canceling vacation
hold requires an update to the external pyecobee library. Creation
of vacation is not supported (it would be straightforward in the code,
but a complex user interface would be required, similar to what is
now done in the ecobee thermostat).
* Add capability to retrieve list of defined climates from ecobee.
* The mode() method used to return the system mode in internal
representation. However, the user sees a different notation in
the ecobee thermostat. Seeing some internal name is particularly
weired with user-defined climates, where these are named "smart1",
"smart2", etc., instead of the name the user has defined. Return
the user-defined name instead. This change might break some user
interfaces but is easily remedied (e.g., use "Away" instead of
"away").
* Simplify is_away_mode_on().
* Correction of erroneously indented else statement.
* Change comment as flake8 gets confused.
2017-03-02 07:52:31 +00:00
|
|
|
self.vacation = None
|
|
|
|
self._climate_list = self.climate_list
|
2016-08-30 19:04:53 +00:00
|
|
|
self._operation_list = ['auto', 'auxHeatOnly', 'cool',
|
|
|
|
'heat', 'off']
|
2018-03-18 16:02:07 +00:00
|
|
|
self._fan_list = ['auto', 'on']
|
2016-09-18 20:20:06 +00:00
|
|
|
self.update_without_throttle = False
|
2016-08-19 07:17:28 +00:00
|
|
|
|
|
|
|
def update(self):
|
|
|
|
"""Get the latest state from the thermostat."""
|
2016-09-18 20:20:06 +00:00
|
|
|
if self.update_without_throttle:
|
|
|
|
self.data.update(no_throttle=True)
|
|
|
|
self.update_without_throttle = False
|
|
|
|
else:
|
|
|
|
self.data.update()
|
|
|
|
|
2016-08-19 07:17:28 +00:00
|
|
|
self.thermostat = self.data.ecobee.get_thermostat(
|
|
|
|
self.thermostat_index)
|
|
|
|
|
2017-11-29 10:01:28 +00:00
|
|
|
@property
|
|
|
|
def supported_features(self):
|
|
|
|
"""Return the list of supported features."""
|
|
|
|
return SUPPORT_FLAGS
|
|
|
|
|
2016-08-19 07:17:28 +00:00
|
|
|
@property
|
|
|
|
def name(self):
|
|
|
|
"""Return the name of the Ecobee Thermostat."""
|
|
|
|
return self.thermostat['name']
|
|
|
|
|
|
|
|
@property
|
2016-10-11 07:00:29 +00:00
|
|
|
def temperature_unit(self):
|
2016-08-19 07:17:28 +00:00
|
|
|
"""Return the unit of measurement."""
|
2016-10-18 03:06:03 +00:00
|
|
|
return TEMP_FAHRENHEIT
|
2016-08-19 07:17:28 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
def current_temperature(self):
|
|
|
|
"""Return the current temperature."""
|
2017-09-29 14:57:31 +00:00
|
|
|
return self.thermostat['runtime']['actualTemperature'] / 10.0
|
2016-08-19 07:17:28 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
def target_temperature_low(self):
|
|
|
|
"""Return the lower bound temperature we try to reach."""
|
2017-01-17 01:58:34 +00:00
|
|
|
if self.current_operation == STATE_AUTO:
|
2017-09-29 14:57:31 +00:00
|
|
|
return self.thermostat['runtime']['desiredHeat'] / 10.0
|
2017-07-06 06:30:01 +00:00
|
|
|
return None
|
2016-08-19 07:17:28 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
def target_temperature_high(self):
|
|
|
|
"""Return the upper bound temperature we try to reach."""
|
2017-01-17 01:58:34 +00:00
|
|
|
if self.current_operation == STATE_AUTO:
|
2017-09-29 14:57:31 +00:00
|
|
|
return self.thermostat['runtime']['desiredCool'] / 10.0
|
2017-07-06 06:30:01 +00:00
|
|
|
return None
|
2017-01-17 01:58:34 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
def target_temperature(self):
|
|
|
|
"""Return the temperature we try to reach."""
|
|
|
|
if self.current_operation == STATE_AUTO:
|
|
|
|
return None
|
|
|
|
if self.current_operation == STATE_HEAT:
|
2017-09-29 14:57:31 +00:00
|
|
|
return self.thermostat['runtime']['desiredHeat'] / 10.0
|
2018-07-23 08:16:05 +00:00
|
|
|
if self.current_operation == STATE_COOL:
|
2017-09-29 14:57:31 +00:00
|
|
|
return self.thermostat['runtime']['desiredCool'] / 10.0
|
2017-07-06 06:30:01 +00:00
|
|
|
return None
|
2016-08-19 07:17:28 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
def fan(self):
|
2018-03-18 16:02:07 +00:00
|
|
|
"""Return the current fan status."""
|
2016-08-19 07:17:28 +00:00
|
|
|
if 'fan' in self.thermostat['equipmentStatus']:
|
|
|
|
return STATE_ON
|
2017-07-06 06:30:01 +00:00
|
|
|
return STATE_OFF
|
2016-08-19 07:17:28 +00:00
|
|
|
|
2018-03-18 16:02:07 +00:00
|
|
|
@property
|
|
|
|
def current_fan_mode(self):
|
|
|
|
"""Return the fan setting."""
|
|
|
|
return self.thermostat['runtime']['desiredFanMode']
|
|
|
|
|
2017-01-27 16:57:18 +00:00
|
|
|
@property
|
|
|
|
def current_hold_mode(self):
|
|
|
|
"""Return current hold mode."""
|
2017-09-29 14:57:31 +00:00
|
|
|
mode = self._current_hold_mode
|
|
|
|
return None if mode == AWAY_MODE else mode
|
|
|
|
|
2018-03-18 16:02:07 +00:00
|
|
|
@property
|
|
|
|
def fan_list(self):
|
|
|
|
"""Return the available fan modes."""
|
|
|
|
return self._fan_list
|
|
|
|
|
2017-09-29 14:57:31 +00:00
|
|
|
@property
|
|
|
|
def _current_hold_mode(self):
|
2017-02-09 04:04:09 +00:00
|
|
|
events = self.thermostat['events']
|
Additional support for ecobee hold mode (#6258)
* Integrate suggestion in #5590 by nordlead2005. This change has been
sitting in limbo for over a month, but it is a good idea. I don't
mean to step on nordlead2005's toes, but we need to make progress.
* Use defined constant for TEMPERATURE_HOLD
* Integrate handling of vacation into hold mode. Canceling vacation
hold requires an update to the external pyecobee library. Creation
of vacation is not supported (it would be straightforward in the code,
but a complex user interface would be required, similar to what is
now done in the ecobee thermostat).
* Add capability to retrieve list of defined climates from ecobee.
* The mode() method used to return the system mode in internal
representation. However, the user sees a different notation in
the ecobee thermostat. Seeing some internal name is particularly
weired with user-defined climates, where these are named "smart1",
"smart2", etc., instead of the name the user has defined. Return
the user-defined name instead. This change might break some user
interfaces but is easily remedied (e.g., use "Away" instead of
"away").
* Simplify is_away_mode_on().
* Correction of erroneously indented else statement.
* Change comment as flake8 gets confused.
2017-03-02 07:52:31 +00:00
|
|
|
for event in events:
|
|
|
|
if event['running']:
|
|
|
|
if event['type'] == 'hold':
|
|
|
|
if event['holdClimateRef'] == 'away':
|
|
|
|
if int(event['endDate'][0:4]) - \
|
2018-03-18 16:02:07 +00:00
|
|
|
int(event['startDate'][0:4]) <= 1:
|
2017-04-30 05:04:49 +00:00
|
|
|
# A temporary hold from away climate is a hold
|
Additional support for ecobee hold mode (#6258)
* Integrate suggestion in #5590 by nordlead2005. This change has been
sitting in limbo for over a month, but it is a good idea. I don't
mean to step on nordlead2005's toes, but we need to make progress.
* Use defined constant for TEMPERATURE_HOLD
* Integrate handling of vacation into hold mode. Canceling vacation
hold requires an update to the external pyecobee library. Creation
of vacation is not supported (it would be straightforward in the code,
but a complex user interface would be required, similar to what is
now done in the ecobee thermostat).
* Add capability to retrieve list of defined climates from ecobee.
* The mode() method used to return the system mode in internal
representation. However, the user sees a different notation in
the ecobee thermostat. Seeing some internal name is particularly
weired with user-defined climates, where these are named "smart1",
"smart2", etc., instead of the name the user has defined. Return
the user-defined name instead. This change might break some user
interfaces but is easily remedied (e.g., use "Away" instead of
"away").
* Simplify is_away_mode_on().
* Correction of erroneously indented else statement.
* Change comment as flake8 gets confused.
2017-03-02 07:52:31 +00:00
|
|
|
return 'away'
|
2017-09-29 14:57:31 +00:00
|
|
|
# A permanent hold from away climate
|
|
|
|
return AWAY_MODE
|
2018-07-23 08:16:05 +00:00
|
|
|
if event['holdClimateRef'] != "":
|
2017-04-30 05:04:49 +00:00
|
|
|
# Any other hold based on climate
|
Additional support for ecobee hold mode (#6258)
* Integrate suggestion in #5590 by nordlead2005. This change has been
sitting in limbo for over a month, but it is a good idea. I don't
mean to step on nordlead2005's toes, but we need to make progress.
* Use defined constant for TEMPERATURE_HOLD
* Integrate handling of vacation into hold mode. Canceling vacation
hold requires an update to the external pyecobee library. Creation
of vacation is not supported (it would be straightforward in the code,
but a complex user interface would be required, similar to what is
now done in the ecobee thermostat).
* Add capability to retrieve list of defined climates from ecobee.
* The mode() method used to return the system mode in internal
representation. However, the user sees a different notation in
the ecobee thermostat. Seeing some internal name is particularly
weired with user-defined climates, where these are named "smart1",
"smart2", etc., instead of the name the user has defined. Return
the user-defined name instead. This change might break some user
interfaces but is easily remedied (e.g., use "Away" instead of
"away").
* Simplify is_away_mode_on().
* Correction of erroneously indented else statement.
* Change comment as flake8 gets confused.
2017-03-02 07:52:31 +00:00
|
|
|
return event['holdClimateRef']
|
2017-07-06 06:30:01 +00:00
|
|
|
# Any hold not based on a climate is a temp hold
|
|
|
|
return TEMPERATURE_HOLD
|
2018-07-23 08:16:05 +00:00
|
|
|
if event['type'].startswith('auto'):
|
2017-04-30 05:04:49 +00:00
|
|
|
# All auto modes are treated as holds
|
Additional support for ecobee hold mode (#6258)
* Integrate suggestion in #5590 by nordlead2005. This change has been
sitting in limbo for over a month, but it is a good idea. I don't
mean to step on nordlead2005's toes, but we need to make progress.
* Use defined constant for TEMPERATURE_HOLD
* Integrate handling of vacation into hold mode. Canceling vacation
hold requires an update to the external pyecobee library. Creation
of vacation is not supported (it would be straightforward in the code,
but a complex user interface would be required, similar to what is
now done in the ecobee thermostat).
* Add capability to retrieve list of defined climates from ecobee.
* The mode() method used to return the system mode in internal
representation. However, the user sees a different notation in
the ecobee thermostat. Seeing some internal name is particularly
weired with user-defined climates, where these are named "smart1",
"smart2", etc., instead of the name the user has defined. Return
the user-defined name instead. This change might break some user
interfaces but is easily remedied (e.g., use "Away" instead of
"away").
* Simplify is_away_mode_on().
* Correction of erroneously indented else statement.
* Change comment as flake8 gets confused.
2017-03-02 07:52:31 +00:00
|
|
|
return event['type'][4:].lower()
|
2018-07-23 08:16:05 +00:00
|
|
|
if event['type'] == 'vacation':
|
Additional support for ecobee hold mode (#6258)
* Integrate suggestion in #5590 by nordlead2005. This change has been
sitting in limbo for over a month, but it is a good idea. I don't
mean to step on nordlead2005's toes, but we need to make progress.
* Use defined constant for TEMPERATURE_HOLD
* Integrate handling of vacation into hold mode. Canceling vacation
hold requires an update to the external pyecobee library. Creation
of vacation is not supported (it would be straightforward in the code,
but a complex user interface would be required, similar to what is
now done in the ecobee thermostat).
* Add capability to retrieve list of defined climates from ecobee.
* The mode() method used to return the system mode in internal
representation. However, the user sees a different notation in
the ecobee thermostat. Seeing some internal name is particularly
weired with user-defined climates, where these are named "smart1",
"smart2", etc., instead of the name the user has defined. Return
the user-defined name instead. This change might break some user
interfaces but is easily remedied (e.g., use "Away" instead of
"away").
* Simplify is_away_mode_on().
* Correction of erroneously indented else statement.
* Change comment as flake8 gets confused.
2017-03-02 07:52:31 +00:00
|
|
|
self.vacation = event['name']
|
|
|
|
return VACATION_HOLD
|
|
|
|
return None
|
2017-01-27 16:57:18 +00:00
|
|
|
|
2016-08-28 20:51:56 +00:00
|
|
|
@property
|
|
|
|
def current_operation(self):
|
|
|
|
"""Return current operation."""
|
2016-09-09 17:06:53 +00:00
|
|
|
if self.operation_mode == 'auxHeatOnly' or \
|
2018-03-18 16:02:07 +00:00
|
|
|
self.operation_mode == 'heatPump':
|
2016-09-09 17:06:53 +00:00
|
|
|
return STATE_HEAT
|
2017-07-06 06:30:01 +00:00
|
|
|
return self.operation_mode
|
2016-08-28 20:51:56 +00:00
|
|
|
|
2016-08-30 19:04:53 +00:00
|
|
|
@property
|
|
|
|
def operation_list(self):
|
|
|
|
"""Return the operation modes list."""
|
|
|
|
return self._operation_list
|
|
|
|
|
2016-08-19 07:17:28 +00:00
|
|
|
@property
|
|
|
|
def operation_mode(self):
|
|
|
|
"""Return current operation ie. heat, cool, idle."""
|
2016-08-30 19:04:53 +00:00
|
|
|
return self.thermostat['settings']['hvacMode']
|
2016-08-19 07:17:28 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
def mode(self):
|
Additional support for ecobee hold mode (#6258)
* Integrate suggestion in #5590 by nordlead2005. This change has been
sitting in limbo for over a month, but it is a good idea. I don't
mean to step on nordlead2005's toes, but we need to make progress.
* Use defined constant for TEMPERATURE_HOLD
* Integrate handling of vacation into hold mode. Canceling vacation
hold requires an update to the external pyecobee library. Creation
of vacation is not supported (it would be straightforward in the code,
but a complex user interface would be required, similar to what is
now done in the ecobee thermostat).
* Add capability to retrieve list of defined climates from ecobee.
* The mode() method used to return the system mode in internal
representation. However, the user sees a different notation in
the ecobee thermostat. Seeing some internal name is particularly
weired with user-defined climates, where these are named "smart1",
"smart2", etc., instead of the name the user has defined. Return
the user-defined name instead. This change might break some user
interfaces but is easily remedied (e.g., use "Away" instead of
"away").
* Simplify is_away_mode_on().
* Correction of erroneously indented else statement.
* Change comment as flake8 gets confused.
2017-03-02 07:52:31 +00:00
|
|
|
"""Return current mode, as the user-visible name."""
|
|
|
|
cur = self.thermostat['program']['currentClimateRef']
|
|
|
|
climates = self.thermostat['program']['climates']
|
|
|
|
current = list(filter(lambda x: x['climateRef'] == cur, climates))
|
|
|
|
return current[0]['name']
|
2016-08-19 07:17:28 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
def fan_min_on_time(self):
|
|
|
|
"""Return current fan minimum on time."""
|
|
|
|
return self.thermostat['settings']['fanMinOnTime']
|
|
|
|
|
|
|
|
@property
|
|
|
|
def device_state_attributes(self):
|
|
|
|
"""Return device specific state attributes."""
|
|
|
|
# Move these to Thermostat Device and make them global
|
2016-08-30 19:04:53 +00:00
|
|
|
status = self.thermostat['equipmentStatus']
|
|
|
|
operation = None
|
|
|
|
if status == '':
|
|
|
|
operation = STATE_IDLE
|
|
|
|
elif 'Cool' in status:
|
|
|
|
operation = STATE_COOL
|
|
|
|
elif 'auxHeat' in status:
|
|
|
|
operation = STATE_HEAT
|
|
|
|
elif 'heatPump' in status:
|
|
|
|
operation = STATE_HEAT
|
|
|
|
else:
|
|
|
|
operation = status
|
2018-03-18 16:02:07 +00:00
|
|
|
|
2016-08-19 07:17:28 +00:00
|
|
|
return {
|
2016-09-01 05:13:33 +00:00
|
|
|
"actual_humidity": self.thermostat['runtime']['actualHumidity'],
|
2016-08-19 07:17:28 +00:00
|
|
|
"fan": self.fan,
|
2018-03-18 16:02:07 +00:00
|
|
|
"climate_mode": self.mode,
|
2016-08-30 19:04:53 +00:00
|
|
|
"operation": operation,
|
Additional support for ecobee hold mode (#6258)
* Integrate suggestion in #5590 by nordlead2005. This change has been
sitting in limbo for over a month, but it is a good idea. I don't
mean to step on nordlead2005's toes, but we need to make progress.
* Use defined constant for TEMPERATURE_HOLD
* Integrate handling of vacation into hold mode. Canceling vacation
hold requires an update to the external pyecobee library. Creation
of vacation is not supported (it would be straightforward in the code,
but a complex user interface would be required, similar to what is
now done in the ecobee thermostat).
* Add capability to retrieve list of defined climates from ecobee.
* The mode() method used to return the system mode in internal
representation. However, the user sees a different notation in
the ecobee thermostat. Seeing some internal name is particularly
weired with user-defined climates, where these are named "smart1",
"smart2", etc., instead of the name the user has defined. Return
the user-defined name instead. This change might break some user
interfaces but is easily remedied (e.g., use "Away" instead of
"away").
* Simplify is_away_mode_on().
* Correction of erroneously indented else statement.
* Change comment as flake8 gets confused.
2017-03-02 07:52:31 +00:00
|
|
|
"climate_list": self.climate_list,
|
2016-08-19 07:17:28 +00:00
|
|
|
"fan_min_on_time": self.fan_min_on_time
|
|
|
|
}
|
|
|
|
|
|
|
|
@property
|
|
|
|
def is_away_mode_on(self):
|
|
|
|
"""Return true if away mode is on."""
|
2017-09-29 14:57:31 +00:00
|
|
|
return self._current_hold_mode == AWAY_MODE
|
2016-08-19 07:17:28 +00:00
|
|
|
|
2017-04-28 09:52:48 +00:00
|
|
|
@property
|
|
|
|
def is_aux_heat_on(self):
|
|
|
|
"""Return true if aux heater."""
|
|
|
|
return 'auxHeat' in self.thermostat['equipmentStatus']
|
|
|
|
|
2016-08-19 07:17:28 +00:00
|
|
|
def turn_away_mode_on(self):
|
2017-09-29 14:57:31 +00:00
|
|
|
"""Turn away mode on by setting it on away hold indefinitely."""
|
|
|
|
if self._current_hold_mode != AWAY_MODE:
|
|
|
|
self.data.ecobee.set_climate_hold(self.thermostat_index, 'away',
|
|
|
|
'indefinite')
|
|
|
|
self.update_without_throttle = True
|
2016-08-19 07:17:28 +00:00
|
|
|
|
|
|
|
def turn_away_mode_off(self):
|
|
|
|
"""Turn away off."""
|
2017-09-29 14:57:31 +00:00
|
|
|
if self._current_hold_mode == AWAY_MODE:
|
|
|
|
self.data.ecobee.resume_program(self.thermostat_index)
|
|
|
|
self.update_without_throttle = True
|
2016-08-19 07:17:28 +00:00
|
|
|
|
2017-01-27 16:57:18 +00:00
|
|
|
def set_hold_mode(self, hold_mode):
|
Additional support for ecobee hold mode (#6258)
* Integrate suggestion in #5590 by nordlead2005. This change has been
sitting in limbo for over a month, but it is a good idea. I don't
mean to step on nordlead2005's toes, but we need to make progress.
* Use defined constant for TEMPERATURE_HOLD
* Integrate handling of vacation into hold mode. Canceling vacation
hold requires an update to the external pyecobee library. Creation
of vacation is not supported (it would be straightforward in the code,
but a complex user interface would be required, similar to what is
now done in the ecobee thermostat).
* Add capability to retrieve list of defined climates from ecobee.
* The mode() method used to return the system mode in internal
representation. However, the user sees a different notation in
the ecobee thermostat. Seeing some internal name is particularly
weired with user-defined climates, where these are named "smart1",
"smart2", etc., instead of the name the user has defined. Return
the user-defined name instead. This change might break some user
interfaces but is easily remedied (e.g., use "Away" instead of
"away").
* Simplify is_away_mode_on().
* Correction of erroneously indented else statement.
* Change comment as flake8 gets confused.
2017-03-02 07:52:31 +00:00
|
|
|
"""Set hold mode (away, home, temp, sleep, etc.)."""
|
2017-01-27 16:57:18 +00:00
|
|
|
hold = self.current_hold_mode
|
2017-01-17 01:58:34 +00:00
|
|
|
|
2017-01-27 16:57:18 +00:00
|
|
|
if hold == hold_mode:
|
2017-02-09 04:04:09 +00:00
|
|
|
# no change, so no action required
|
2017-01-17 01:58:34 +00:00
|
|
|
return
|
2018-07-23 08:16:05 +00:00
|
|
|
if hold_mode == 'None' or hold_mode is None:
|
Additional support for ecobee hold mode (#6258)
* Integrate suggestion in #5590 by nordlead2005. This change has been
sitting in limbo for over a month, but it is a good idea. I don't
mean to step on nordlead2005's toes, but we need to make progress.
* Use defined constant for TEMPERATURE_HOLD
* Integrate handling of vacation into hold mode. Canceling vacation
hold requires an update to the external pyecobee library. Creation
of vacation is not supported (it would be straightforward in the code,
but a complex user interface would be required, similar to what is
now done in the ecobee thermostat).
* Add capability to retrieve list of defined climates from ecobee.
* The mode() method used to return the system mode in internal
representation. However, the user sees a different notation in
the ecobee thermostat. Seeing some internal name is particularly
weired with user-defined climates, where these are named "smart1",
"smart2", etc., instead of the name the user has defined. Return
the user-defined name instead. This change might break some user
interfaces but is easily remedied (e.g., use "Away" instead of
"away").
* Simplify is_away_mode_on().
* Correction of erroneously indented else statement.
* Change comment as flake8 gets confused.
2017-03-02 07:52:31 +00:00
|
|
|
if hold == VACATION_HOLD:
|
2017-04-30 05:04:49 +00:00
|
|
|
self.data.ecobee.delete_vacation(
|
|
|
|
self.thermostat_index, self.vacation)
|
Additional support for ecobee hold mode (#6258)
* Integrate suggestion in #5590 by nordlead2005. This change has been
sitting in limbo for over a month, but it is a good idea. I don't
mean to step on nordlead2005's toes, but we need to make progress.
* Use defined constant for TEMPERATURE_HOLD
* Integrate handling of vacation into hold mode. Canceling vacation
hold requires an update to the external pyecobee library. Creation
of vacation is not supported (it would be straightforward in the code,
but a complex user interface would be required, similar to what is
now done in the ecobee thermostat).
* Add capability to retrieve list of defined climates from ecobee.
* The mode() method used to return the system mode in internal
representation. However, the user sees a different notation in
the ecobee thermostat. Seeing some internal name is particularly
weired with user-defined climates, where these are named "smart1",
"smart2", etc., instead of the name the user has defined. Return
the user-defined name instead. This change might break some user
interfaces but is easily remedied (e.g., use "Away" instead of
"away").
* Simplify is_away_mode_on().
* Correction of erroneously indented else statement.
* Change comment as flake8 gets confused.
2017-03-02 07:52:31 +00:00
|
|
|
else:
|
|
|
|
self.data.ecobee.resume_program(self.thermostat_index)
|
2017-01-27 16:57:18 +00:00
|
|
|
else:
|
Additional support for ecobee hold mode (#6258)
* Integrate suggestion in #5590 by nordlead2005. This change has been
sitting in limbo for over a month, but it is a good idea. I don't
mean to step on nordlead2005's toes, but we need to make progress.
* Use defined constant for TEMPERATURE_HOLD
* Integrate handling of vacation into hold mode. Canceling vacation
hold requires an update to the external pyecobee library. Creation
of vacation is not supported (it would be straightforward in the code,
but a complex user interface would be required, similar to what is
now done in the ecobee thermostat).
* Add capability to retrieve list of defined climates from ecobee.
* The mode() method used to return the system mode in internal
representation. However, the user sees a different notation in
the ecobee thermostat. Seeing some internal name is particularly
weired with user-defined climates, where these are named "smart1",
"smart2", etc., instead of the name the user has defined. Return
the user-defined name instead. This change might break some user
interfaces but is easily remedied (e.g., use "Away" instead of
"away").
* Simplify is_away_mode_on().
* Correction of erroneously indented else statement.
* Change comment as flake8 gets confused.
2017-03-02 07:52:31 +00:00
|
|
|
if hold_mode == TEMPERATURE_HOLD:
|
2017-09-29 14:57:31 +00:00
|
|
|
self.set_temp_hold(self.current_temperature)
|
Additional support for ecobee hold mode (#6258)
* Integrate suggestion in #5590 by nordlead2005. This change has been
sitting in limbo for over a month, but it is a good idea. I don't
mean to step on nordlead2005's toes, but we need to make progress.
* Use defined constant for TEMPERATURE_HOLD
* Integrate handling of vacation into hold mode. Canceling vacation
hold requires an update to the external pyecobee library. Creation
of vacation is not supported (it would be straightforward in the code,
but a complex user interface would be required, similar to what is
now done in the ecobee thermostat).
* Add capability to retrieve list of defined climates from ecobee.
* The mode() method used to return the system mode in internal
representation. However, the user sees a different notation in
the ecobee thermostat. Seeing some internal name is particularly
weired with user-defined climates, where these are named "smart1",
"smart2", etc., instead of the name the user has defined. Return
the user-defined name instead. This change might break some user
interfaces but is easily remedied (e.g., use "Away" instead of
"away").
* Simplify is_away_mode_on().
* Correction of erroneously indented else statement.
* Change comment as flake8 gets confused.
2017-03-02 07:52:31 +00:00
|
|
|
else:
|
2017-04-30 05:04:49 +00:00
|
|
|
self.data.ecobee.set_climate_hold(
|
|
|
|
self.thermostat_index, hold_mode, self.hold_preference())
|
Additional support for ecobee hold mode (#6258)
* Integrate suggestion in #5590 by nordlead2005. This change has been
sitting in limbo for over a month, but it is a good idea. I don't
mean to step on nordlead2005's toes, but we need to make progress.
* Use defined constant for TEMPERATURE_HOLD
* Integrate handling of vacation into hold mode. Canceling vacation
hold requires an update to the external pyecobee library. Creation
of vacation is not supported (it would be straightforward in the code,
but a complex user interface would be required, similar to what is
now done in the ecobee thermostat).
* Add capability to retrieve list of defined climates from ecobee.
* The mode() method used to return the system mode in internal
representation. However, the user sees a different notation in
the ecobee thermostat. Seeing some internal name is particularly
weired with user-defined climates, where these are named "smart1",
"smart2", etc., instead of the name the user has defined. Return
the user-defined name instead. This change might break some user
interfaces but is easily remedied (e.g., use "Away" instead of
"away").
* Simplify is_away_mode_on().
* Correction of erroneously indented else statement.
* Change comment as flake8 gets confused.
2017-03-02 07:52:31 +00:00
|
|
|
self.update_without_throttle = True
|
2017-01-27 16:57:18 +00:00
|
|
|
|
|
|
|
def set_auto_temp_hold(self, heat_temp, cool_temp):
|
|
|
|
"""Set temperature hold in auto mode."""
|
2017-11-29 10:01:28 +00:00
|
|
|
if cool_temp is not None:
|
|
|
|
cool_temp_setpoint = cool_temp
|
|
|
|
else:
|
|
|
|
cool_temp_setpoint = (
|
|
|
|
self.thermostat['runtime']['desiredCool'] / 10.0)
|
|
|
|
|
|
|
|
if heat_temp is not None:
|
|
|
|
heat_temp_setpoint = heat_temp
|
|
|
|
else:
|
|
|
|
heat_temp_setpoint = (
|
|
|
|
self.thermostat['runtime']['desiredCool'] / 10.0)
|
|
|
|
|
|
|
|
self.data.ecobee.set_hold_temp(self.thermostat_index,
|
|
|
|
cool_temp_setpoint, heat_temp_setpoint,
|
|
|
|
self.hold_preference())
|
2017-01-27 16:57:18 +00:00
|
|
|
_LOGGER.debug("Setting ecobee hold_temp to: heat=%s, is=%s, "
|
2018-03-18 16:02:07 +00:00
|
|
|
"cool=%s, is=%s", heat_temp,
|
|
|
|
isinstance(heat_temp, (int, float)), cool_temp,
|
2017-01-27 16:57:18 +00:00
|
|
|
isinstance(cool_temp, (int, float)))
|
2017-01-17 01:58:34 +00:00
|
|
|
|
2017-01-27 16:57:18 +00:00
|
|
|
self.update_without_throttle = True
|
2016-09-09 17:06:53 +00:00
|
|
|
|
2018-03-18 16:02:07 +00:00
|
|
|
def set_fan_mode(self, fan_mode):
|
|
|
|
"""Set the fan mode. Valid values are "on" or "auto"."""
|
|
|
|
if (fan_mode.lower() != STATE_ON) and (fan_mode.lower() != STATE_AUTO):
|
|
|
|
error = "Invalid fan_mode value: Valid values are 'on' or 'auto'"
|
|
|
|
_LOGGER.error(error)
|
|
|
|
return
|
|
|
|
|
|
|
|
cool_temp = self.thermostat['runtime']['desiredCool'] / 10.0
|
|
|
|
heat_temp = self.thermostat['runtime']['desiredHeat'] / 10.0
|
|
|
|
self.data.ecobee.set_fan_mode(self.thermostat_index, fan_mode,
|
|
|
|
cool_temp, heat_temp,
|
|
|
|
self.hold_preference())
|
|
|
|
|
|
|
|
_LOGGER.info("Setting fan mode to: %s", fan_mode)
|
|
|
|
|
2017-01-27 16:57:18 +00:00
|
|
|
def set_temp_hold(self, temp):
|
2018-03-18 16:02:07 +00:00
|
|
|
"""Set temperature hold in modes other than auto.
|
|
|
|
|
|
|
|
Ecobee API: It is good practice to set the heat and cool hold
|
|
|
|
temperatures to be the same, if the thermostat is in either heat, cool,
|
|
|
|
auxHeatOnly, or off mode. If the thermostat is in auto mode, an
|
|
|
|
additional rule is required. The cool hold temperature must be greater
|
|
|
|
than the heat hold temperature by at least the amount in the
|
|
|
|
heatCoolMinDelta property.
|
|
|
|
https://www.ecobee.com/home/developer/api/examples/ex5.shtml
|
|
|
|
"""
|
|
|
|
if self.current_operation == STATE_HEAT or self.current_operation == \
|
|
|
|
STATE_COOL:
|
2017-01-27 16:57:18 +00:00
|
|
|
heat_temp = temp
|
|
|
|
cool_temp = temp
|
2017-09-29 14:57:31 +00:00
|
|
|
else:
|
2018-03-18 16:02:07 +00:00
|
|
|
delta = self.thermostat['settings']['heatCoolMinDelta'] / 10
|
|
|
|
heat_temp = temp - delta
|
|
|
|
cool_temp = temp + delta
|
2017-09-29 14:57:31 +00:00
|
|
|
self.set_auto_temp_hold(heat_temp, cool_temp)
|
2016-08-19 07:17:28 +00:00
|
|
|
|
2017-01-27 16:57:18 +00:00
|
|
|
def set_temperature(self, **kwargs):
|
|
|
|
"""Set new target temperature."""
|
|
|
|
low_temp = kwargs.get(ATTR_TARGET_TEMP_LOW)
|
|
|
|
high_temp = kwargs.get(ATTR_TARGET_TEMP_HIGH)
|
|
|
|
temp = kwargs.get(ATTR_TEMPERATURE)
|
|
|
|
|
2018-03-18 16:02:07 +00:00
|
|
|
if self.current_operation == STATE_AUTO and \
|
|
|
|
(low_temp is not None or high_temp is not None):
|
2017-09-29 14:57:31 +00:00
|
|
|
self.set_auto_temp_hold(low_temp, high_temp)
|
2017-01-27 16:57:18 +00:00
|
|
|
elif temp is not None:
|
2017-09-29 14:57:31 +00:00
|
|
|
self.set_temp_hold(temp)
|
2017-01-27 16:57:18 +00:00
|
|
|
else:
|
|
|
|
_LOGGER.error(
|
2017-04-30 05:04:49 +00:00
|
|
|
"Missing valid arguments for set_temperature in %s", kwargs)
|
2017-01-27 16:57:18 +00:00
|
|
|
|
2017-11-28 09:39:30 +00:00
|
|
|
def set_humidity(self, humidity):
|
|
|
|
"""Set the humidity level."""
|
|
|
|
self.data.ecobee.set_humidity(self.thermostat_index, humidity)
|
|
|
|
|
2016-08-19 07:17:28 +00:00
|
|
|
def set_operation_mode(self, operation_mode):
|
|
|
|
"""Set HVAC mode (auto, auxHeatOnly, cool, heat, off)."""
|
|
|
|
self.data.ecobee.set_hvac_mode(self.thermostat_index, operation_mode)
|
2016-09-18 20:20:06 +00:00
|
|
|
self.update_without_throttle = True
|
2016-08-19 07:17:28 +00:00
|
|
|
|
|
|
|
def set_fan_min_on_time(self, fan_min_on_time):
|
|
|
|
"""Set the minimum fan on time."""
|
2017-04-30 05:04:49 +00:00
|
|
|
self.data.ecobee.set_fan_min_on_time(
|
|
|
|
self.thermostat_index, fan_min_on_time)
|
2016-09-18 20:20:06 +00:00
|
|
|
self.update_without_throttle = True
|
2016-08-19 07:17:28 +00:00
|
|
|
|
2016-12-27 20:56:26 +00:00
|
|
|
def resume_program(self, resume_all):
|
|
|
|
"""Resume the thermostat schedule program."""
|
2017-04-30 05:04:49 +00:00
|
|
|
self.data.ecobee.resume_program(
|
2017-09-29 14:57:31 +00:00
|
|
|
self.thermostat_index, 'true' if resume_all else 'false')
|
2016-12-27 20:56:26 +00:00
|
|
|
self.update_without_throttle = True
|
|
|
|
|
2017-01-27 16:57:18 +00:00
|
|
|
def hold_preference(self):
|
|
|
|
"""Return user preference setting for hold time."""
|
|
|
|
# Values returned from thermostat are 'useEndTime4hour',
|
|
|
|
# 'useEndTime2hour', 'nextTransition', 'indefinite', 'askMe'
|
|
|
|
default = self.thermostat['settings']['holdAction']
|
|
|
|
if default == 'nextTransition':
|
|
|
|
return default
|
2017-02-09 04:04:09 +00:00
|
|
|
# add further conditions if other hold durations should be
|
|
|
|
# supported; note that this should not include 'indefinite'
|
|
|
|
# as an indefinite away hold is interpreted as away_mode
|
2017-07-06 06:30:01 +00:00
|
|
|
return 'nextTransition'
|
Additional support for ecobee hold mode (#6258)
* Integrate suggestion in #5590 by nordlead2005. This change has been
sitting in limbo for over a month, but it is a good idea. I don't
mean to step on nordlead2005's toes, but we need to make progress.
* Use defined constant for TEMPERATURE_HOLD
* Integrate handling of vacation into hold mode. Canceling vacation
hold requires an update to the external pyecobee library. Creation
of vacation is not supported (it would be straightforward in the code,
but a complex user interface would be required, similar to what is
now done in the ecobee thermostat).
* Add capability to retrieve list of defined climates from ecobee.
* The mode() method used to return the system mode in internal
representation. However, the user sees a different notation in
the ecobee thermostat. Seeing some internal name is particularly
weired with user-defined climates, where these are named "smart1",
"smart2", etc., instead of the name the user has defined. Return
the user-defined name instead. This change might break some user
interfaces but is easily remedied (e.g., use "Away" instead of
"away").
* Simplify is_away_mode_on().
* Correction of erroneously indented else statement.
* Change comment as flake8 gets confused.
2017-03-02 07:52:31 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
def climate_list(self):
|
|
|
|
"""Return the list of climates currently available."""
|
|
|
|
climates = self.thermostat['program']['climates']
|
|
|
|
return list(map((lambda x: x['name']), climates))
|