initial commit for ecobee thermostat component.
This commit is contained in:
parent
8be53af78f
commit
e317e0798b
3 changed files with 367 additions and 0 deletions
101
homeassistant/components/sensor/ecobee.py
Normal file
101
homeassistant/components/sensor/ecobee.py
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
"""
|
||||||
|
homeassistant.components.sensor.ecobee
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
This sensor component requires that the Ecobee Thermostat
|
||||||
|
component be setup first. This component shows remote
|
||||||
|
ecobee sensor data.
|
||||||
|
|
||||||
|
For more details about this platform, please refer to the documentation at
|
||||||
|
https://home-assistant.io/components/sensor.ecobee/
|
||||||
|
"""
|
||||||
|
from homeassistant.helpers.entity import Entity
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
SENSOR_TYPES = {
|
||||||
|
'temperature': ['Temperature', '°F'],
|
||||||
|
'humidity': ['Humidity', '%'],
|
||||||
|
'occupancy': ['Occupancy', '']
|
||||||
|
}
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
ECOBEE_CONFIG_FILE = 'ecobee.conf'
|
||||||
|
|
||||||
|
|
||||||
|
def config_from_file(filename, config=None):
|
||||||
|
''' Small configuration file management function '''
|
||||||
|
if config:
|
||||||
|
# We're writing configuration
|
||||||
|
try:
|
||||||
|
with open(filename, 'w') as fdesc:
|
||||||
|
fdesc.write(json.dumps(config))
|
||||||
|
except IOError as error:
|
||||||
|
print(error)
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
# We're reading config
|
||||||
|
if os.path.isfile(filename):
|
||||||
|
try:
|
||||||
|
with open(filename, 'r') as fdesc:
|
||||||
|
return json.loads(fdesc.read())
|
||||||
|
except IOError as error:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
|
||||||
|
def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||||
|
""" Sets up the sensors. """
|
||||||
|
config = config_from_file(hass.config.path(ECOBEE_CONFIG_FILE))
|
||||||
|
dev = list()
|
||||||
|
for name, data in config['sensors'].items():
|
||||||
|
if 'temp' in data:
|
||||||
|
dev.append(EcobeeSensor(name, 'temperature', hass))
|
||||||
|
if 'humidity' in data:
|
||||||
|
dev.append(EcobeeSensor(name, 'humidity', hass))
|
||||||
|
if 'occupancy' in data:
|
||||||
|
dev.append(EcobeeSensor(name, 'occupancy', hass))
|
||||||
|
|
||||||
|
add_devices(dev)
|
||||||
|
|
||||||
|
|
||||||
|
class EcobeeSensor(Entity):
|
||||||
|
""" An ecobee sensor. """
|
||||||
|
|
||||||
|
def __init__(self, sensor_name, sensor_type, hass):
|
||||||
|
self._name = sensor_name + ' ' + SENSOR_TYPES[sensor_type][0]
|
||||||
|
self.sensor_name = sensor_name
|
||||||
|
self.hass = hass
|
||||||
|
self.type = sensor_type
|
||||||
|
self._state = None
|
||||||
|
self._unit_of_measurement = SENSOR_TYPES[sensor_type][1]
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
return self._name.rstrip()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def state(self):
|
||||||
|
""" Returns the state of the device. """
|
||||||
|
return self._state
|
||||||
|
|
||||||
|
@property
|
||||||
|
def unit_of_measurement(self):
|
||||||
|
return self._unit_of_measurement
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
config = config_from_file(self.hass.config.path(ECOBEE_CONFIG_FILE))
|
||||||
|
try:
|
||||||
|
data = config['sensors'][self.sensor_name]
|
||||||
|
if self.type == 'temperature':
|
||||||
|
self._state = data['temp']
|
||||||
|
elif self.type == 'humidity':
|
||||||
|
self._state = data['humidity']
|
||||||
|
elif self.type == 'occupancy':
|
||||||
|
self._state = data['occupancy']
|
||||||
|
except KeyError:
|
||||||
|
print("Error updating ecobee sensors.")
|
263
homeassistant/components/thermostat/ecobee.py
Normal file
263
homeassistant/components/thermostat/ecobee.py
Normal file
|
@ -0,0 +1,263 @@
|
||||||
|
#!/usr/local/bin/python3
|
||||||
|
"""
|
||||||
|
homeassistant.components.thermostat.ecobee
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Ecobee Thermostat Component
|
||||||
|
|
||||||
|
This component adds support for Ecobee3 Wireless Thermostats.
|
||||||
|
You will need to setup developer access to your thermostat,
|
||||||
|
and create and API key on the ecobee website.
|
||||||
|
|
||||||
|
The first time you run this component you will see a configuration
|
||||||
|
component card in Home Assistant. This card will contain a PIN code
|
||||||
|
that you will need to use to authorize access to your thermostat. You
|
||||||
|
can do this at https://www.ecobee.com/consumerportal/index.html
|
||||||
|
Click My Apps, Add application, Enter Pin and click Authorize.
|
||||||
|
|
||||||
|
After authorizing the application click the button in the configuration
|
||||||
|
card. Now your thermostat should shown in home-assistant. You will need
|
||||||
|
to restart home assistant to get rid of the configuration card. Once the
|
||||||
|
thermostat has been added you can add the ecobee sensor component
|
||||||
|
to your configuration.yaml.
|
||||||
|
|
||||||
|
thermostat:
|
||||||
|
platform: ecobee
|
||||||
|
api_key: asdfasdfasdfasdfasdfaasdfasdfasdfasdf
|
||||||
|
"""
|
||||||
|
from homeassistant.loader import get_component
|
||||||
|
from homeassistant.components.thermostat import (ThermostatDevice, STATE_COOL,
|
||||||
|
STATE_IDLE, STATE_HEAT)
|
||||||
|
from homeassistant.const import (
|
||||||
|
CONF_API_KEY, TEMP_FAHRENHEIT, STATE_ON, STATE_OFF)
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
REQUIREMENTS = [
|
||||||
|
'https://github.com/nkgilley/home-assistant-ecobee-api/archive/'
|
||||||
|
'c61ee6d456bb5f4ab0c9598804aa9231c3d06f8e.zip#python-ecobee==0.1.1']
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
ECOBEE_CONFIG_FILE = 'ecobee.conf'
|
||||||
|
_CONFIGURING = {}
|
||||||
|
|
||||||
|
|
||||||
|
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
|
||||||
|
""" Setup Platform """
|
||||||
|
# Only act if we are not already configuring this host
|
||||||
|
if 'ecobee' in _CONFIGURING:
|
||||||
|
return
|
||||||
|
|
||||||
|
setup_ecobee(hass, config, add_devices_callback)
|
||||||
|
|
||||||
|
|
||||||
|
def setup_ecobee(hass, config, add_devices_callback):
|
||||||
|
""" Setup ecobee thermostat """
|
||||||
|
from pyecobee import Ecobee, config_from_file
|
||||||
|
# Create ecobee.conf if it doesn't exist
|
||||||
|
if not os.path.isfile(hass.config.path(ECOBEE_CONFIG_FILE)):
|
||||||
|
jsonconfig = {"API_KEY": config[CONF_API_KEY]}
|
||||||
|
config_from_file(hass.config.path(ECOBEE_CONFIG_FILE), jsonconfig)
|
||||||
|
|
||||||
|
ecobee = Ecobee(hass.config.path(ECOBEE_CONFIG_FILE))
|
||||||
|
|
||||||
|
# If ecobee has a PIN then it needs to be configured.
|
||||||
|
if ecobee.pin is not None:
|
||||||
|
# ecobee.request_pin()
|
||||||
|
request_configuration(ecobee, hass, add_devices_callback)
|
||||||
|
return
|
||||||
|
|
||||||
|
if 'ecobee' in _CONFIGURING:
|
||||||
|
_CONFIGURING.pop('ecobee')
|
||||||
|
configurator = get_component('configurator')
|
||||||
|
configurator.request_done('ecobee')
|
||||||
|
|
||||||
|
devices = []
|
||||||
|
for index in range(0, len(ecobee.thermostats)):
|
||||||
|
devices.append(Thermostat(ecobee, index))
|
||||||
|
|
||||||
|
add_devices_callback(devices)
|
||||||
|
|
||||||
|
|
||||||
|
def request_configuration(ecobee, hass, add_devices_callback):
|
||||||
|
""" Request configuration steps from the user. """
|
||||||
|
configurator = get_component('configurator')
|
||||||
|
if 'ecobee' in _CONFIGURING:
|
||||||
|
configurator.notify_errors(
|
||||||
|
_CONFIGURING['ecobee'], "Failed to register, please try again.")
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
# pylint: disable=unused-argument
|
||||||
|
def ecobee_configuration_callback(data):
|
||||||
|
""" Actions to do when our configuration callback is called. """
|
||||||
|
ecobee.request_tokens()
|
||||||
|
ecobee.update()
|
||||||
|
setup_ecobee(hass, None, add_devices_callback)
|
||||||
|
|
||||||
|
_CONFIGURING['ecobee'] = configurator.request_config(
|
||||||
|
hass, "Ecobee", ecobee_configuration_callback,
|
||||||
|
description=(
|
||||||
|
'Please authorize this app at https://www.ecobee.com/consumer'
|
||||||
|
'portal/index.html with pin code: ' + ecobee.pin),
|
||||||
|
description_image='https://goo.gl/6tBkbH',
|
||||||
|
submit_caption="I have authorized the app."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Thermostat(ThermostatDevice):
|
||||||
|
"""docstring for Thermostat"""
|
||||||
|
|
||||||
|
def __init__(self, ecobee, thermostat_index):
|
||||||
|
self.ecobee = ecobee
|
||||||
|
self.thermostat_index = thermostat_index
|
||||||
|
self.thermostat_data = self.ecobee.get_thermostat(
|
||||||
|
self.thermostat_index)
|
||||||
|
self._name = self.thermostat_data['name']
|
||||||
|
if 'away' in self.thermostat_data['program']['currentClimateRef']:
|
||||||
|
self._away = True
|
||||||
|
else:
|
||||||
|
self._away = False
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
self.thermostat_data = self.ecobee.get_thermostat(
|
||||||
|
self.thermostat_index)
|
||||||
|
_LOGGER.info("ecobee data updated successfully.")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
""" Returns the name of the Ecobee Thermostat. """
|
||||||
|
return self.thermostat_data['name']
|
||||||
|
|
||||||
|
@property
|
||||||
|
def unit_of_measurement(self):
|
||||||
|
""" Unit of measurement this thermostat expresses itself in. """
|
||||||
|
return TEMP_FAHRENHEIT
|
||||||
|
|
||||||
|
@property
|
||||||
|
def current_temperature(self):
|
||||||
|
""" Returns the current temperature. """
|
||||||
|
return self.thermostat_data['runtime']['actualTemperature'] / 10
|
||||||
|
|
||||||
|
@property
|
||||||
|
def target_temperature(self):
|
||||||
|
""" Returns the temperature we try to reach. """
|
||||||
|
return (self.target_temperature_low + self.target_temperature_high) / 2
|
||||||
|
|
||||||
|
@property
|
||||||
|
def target_temperature_low(self):
|
||||||
|
""" Returns the lower bound temperature we try to reach. """
|
||||||
|
return int(self.thermostat_data['runtime']['desiredHeat'] / 10)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def target_temperature_high(self):
|
||||||
|
""" Returns the upper bound temperature we try to reach. """
|
||||||
|
return int(self.thermostat_data['runtime']['desiredCool'] / 10)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def humidity(self):
|
||||||
|
""" Returns the current humidity. """
|
||||||
|
return self.thermostat_data['runtime']['actualHumidity']
|
||||||
|
|
||||||
|
@property
|
||||||
|
def desired_fan_mode(self):
|
||||||
|
""" Returns the desired fan mode of operation. """
|
||||||
|
return self.thermostat_data['runtime']['desiredFanMode']
|
||||||
|
|
||||||
|
@property
|
||||||
|
def fan(self):
|
||||||
|
""" Returns the current fan state. """
|
||||||
|
if 'fan' in self.thermostat_data['equipmentStatus']:
|
||||||
|
return STATE_ON
|
||||||
|
else:
|
||||||
|
return STATE_OFF
|
||||||
|
|
||||||
|
@property
|
||||||
|
def operation(self):
|
||||||
|
""" Returns current operation ie. heat, cool, idle """
|
||||||
|
status = self.thermostat_data['equipmentStatus']
|
||||||
|
if status == '':
|
||||||
|
return STATE_IDLE
|
||||||
|
elif 'Cool' in status:
|
||||||
|
return STATE_COOL
|
||||||
|
elif 'auxHeat' in status:
|
||||||
|
return STATE_HEAT
|
||||||
|
elif 'heatPump' in status:
|
||||||
|
return STATE_HEAT
|
||||||
|
else:
|
||||||
|
return status
|
||||||
|
|
||||||
|
@property
|
||||||
|
def mode(self):
|
||||||
|
""" Returns current mode ie. home, away, sleep """
|
||||||
|
mode = self.thermostat_data['program']['currentClimateRef']
|
||||||
|
if 'away' in mode:
|
||||||
|
self._away = True
|
||||||
|
else:
|
||||||
|
self._away = False
|
||||||
|
return mode
|
||||||
|
|
||||||
|
@property
|
||||||
|
def hvac_mode(self):
|
||||||
|
""" Return current hvac mode ie. auto, auxHeatOnly, cool, heat, off """
|
||||||
|
return self.thermostat_data['settings']['hvacMode']
|
||||||
|
|
||||||
|
@property
|
||||||
|
def device_state_attributes(self):
|
||||||
|
""" Returns device specific state attributes. """
|
||||||
|
# Move these to Thermostat Device and make them global
|
||||||
|
return {
|
||||||
|
"humidity": self.humidity,
|
||||||
|
"fan": self.fan,
|
||||||
|
"mode": self.mode,
|
||||||
|
"hvac_mode": self.hvac_mode
|
||||||
|
}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_away_mode_on(self):
|
||||||
|
""" Returns if away mode is on. """
|
||||||
|
return self._away
|
||||||
|
|
||||||
|
def turn_away_mode_on(self):
|
||||||
|
""" Turns away on. """
|
||||||
|
self._away = True
|
||||||
|
self.ecobee.set_climate_hold("away")
|
||||||
|
|
||||||
|
def turn_away_mode_off(self):
|
||||||
|
""" Turns away off. """
|
||||||
|
self._away = False
|
||||||
|
self.ecobee.resume_program()
|
||||||
|
|
||||||
|
def set_temperature(self, temperature):
|
||||||
|
""" Set new target temperature """
|
||||||
|
temperature = int(temperature)
|
||||||
|
low_temp = temperature - 1
|
||||||
|
high_temp = temperature + 1
|
||||||
|
self.ecobee.set_hold_temp(low_temp, high_temp)
|
||||||
|
|
||||||
|
def set_hvac_mode(self, mode):
|
||||||
|
""" Set HVAC mode (auto, auxHeatOnly, cool, heat, off) """
|
||||||
|
self.ecobee.set_hvac_mode(mode)
|
||||||
|
|
||||||
|
# Home and Sleep mode aren't used in UI yet:
|
||||||
|
|
||||||
|
# def turn_home_mode_on(self):
|
||||||
|
# """ Turns home mode on. """
|
||||||
|
# self._away = False
|
||||||
|
# self.ecobee.set_climate_hold("home")
|
||||||
|
|
||||||
|
# def turn_home_mode_off(self):
|
||||||
|
# """ Turns home mode off. """
|
||||||
|
# self._away = False
|
||||||
|
# self.ecobee.resume_program()
|
||||||
|
|
||||||
|
# def turn_sleep_mode_on(self):
|
||||||
|
# """ Turns sleep mode on. """
|
||||||
|
# self._away = False
|
||||||
|
# self.ecobee.set_climate_hold("sleep")
|
||||||
|
|
||||||
|
# def turn_sleep_mode_off(self):
|
||||||
|
# """ Turns sleep mode off. """
|
||||||
|
# self._away = False
|
||||||
|
# self.ecobee.resume_program()
|
|
@ -159,3 +159,6 @@ pushetta==1.0.15
|
||||||
|
|
||||||
# Orvibo S10
|
# Orvibo S10
|
||||||
orvibo==1.0.0
|
orvibo==1.0.0
|
||||||
|
|
||||||
|
# Ecobee (*.ecobee)
|
||||||
|
https://github.com/nkgilley/home-assistant-ecobee-api/archive/e0388659a0f2fc7266485affbd398350cc0b5c58.zip#python-ecobee==0.1.1
|
||||||
|
|
Loading…
Add table
Reference in a new issue