Nest further improvements (#4655)

* Further improvements on nest platform

- fix binary sensor
- add deprecations for monitored_conditions
- better names for sensors (includes device type)

* lint

* Remove unused weather sensor

* Fix to python-nest to a specific commit

* lint

* lint

* lint

* lint
This commit is contained in:
Josh Nichols 2016-12-03 12:26:47 -05:00 committed by Paulus Schoutsen
parent af7de8d5ae
commit 64a5bff5b2
4 changed files with 143 additions and 56 deletions

View file

@ -4,46 +4,97 @@ Support for Nest Thermostat Binary Sensors.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/binary_sensor.nest/
"""
from itertools import chain
import logging
import voluptuous as vol
from homeassistant.components.binary_sensor import (
BinarySensorDevice, PLATFORM_SCHEMA)
from homeassistant.components.sensor.nest import NestSensor
from homeassistant.const import (CONF_SCAN_INTERVAL, CONF_MONITORED_CONDITIONS)
from homeassistant.components.nest import DATA_NEST
from homeassistant.components.nest import (
DATA_NEST, is_thermostat, is_camera)
import homeassistant.helpers.config_validation as cv
DEPENDENCIES = ['nest']
BINARY_TYPES = ['fan',
'hvac_ac_state',
'hvac_aux_heater_state',
'hvac_heater_state',
'hvac_heat_x2_state',
'hvac_heat_x3_state',
'hvac_alt_heat_state',
'hvac_alt_heat_x2_state',
'hvac_emer_heat_state',
'online']
BINARY_TYPES = ['online']
CLIMATE_BINARY_TYPES = ['fan',
'is_using_emergency_heat',
'is_locked',
'has_leaf']
CAMERA_BINARY_TYPES = [
'motion_detected',
'sound_detected',
'person_detected']
_BINARY_TYPES_DEPRECATED = [
'hvac_ac_state',
'hvac_aux_heater_state',
'hvac_heater_state',
'hvac_heat_x2_state',
'hvac_heat_x3_state',
'hvac_alt_heat_state',
'hvac_alt_heat_x2_state',
'hvac_emer_heat_state']
_VALID_BINARY_SENSOR_TYPES = BINARY_TYPES + CLIMATE_BINARY_TYPES \
+ CAMERA_BINARY_TYPES
_VALID_BINARY_SENSOR_TYPES_WITH_DEPRECATED = _VALID_BINARY_SENSOR_TYPES \
+ _BINARY_TYPES_DEPRECATED
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Optional(CONF_SCAN_INTERVAL):
vol.All(vol.Coerce(int), vol.Range(min=1)),
vol.Required(CONF_MONITORED_CONDITIONS):
vol.All(cv.ensure_list, [vol.In(BINARY_TYPES)]),
vol.All(cv.ensure_list,
[vol.In(_VALID_BINARY_SENSOR_TYPES_WITH_DEPRECATED)])
})
_LOGGER = logging.getLogger(__name__)
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Setup Nest binary sensors."""
nest = hass.data[DATA_NEST]
conf = config.get(CONF_MONITORED_CONDITIONS, _VALID_BINARY_SENSOR_TYPES)
all_sensors = []
for structure, device in nest.devices():
all_sensors.extend(
[NestBinarySensor(structure, device, variable)
for variable in config[CONF_MONITORED_CONDITIONS]])
for variable in conf:
if variable in _BINARY_TYPES_DEPRECATED:
wstr = (variable + " is no a longer supported "
"monitored_conditions. See "
"https://home-assistant.io/components/binary_sensor.nest/ "
"for valid options, or remove monitored_conditions "
"entirely to get a reasonable default")
_LOGGER.error(wstr)
add_devices(all_sensors, True)
sensors = []
device_chain = chain(nest.devices(),
nest.protect_devices(),
nest.camera_devices())
for structure, device in device_chain:
sensors += [NestBinarySensor(structure, device, variable)
for variable in conf
if variable in BINARY_TYPES]
sensors += [NestBinarySensor(structure, device, variable)
for variable in conf
if variable in CLIMATE_BINARY_TYPES
and is_thermostat(device)]
if is_camera(device):
sensors += [NestBinarySensor(structure, device, variable)
for variable in conf
if variable in CAMERA_BINARY_TYPES]
for activity_zone in device.activity_zones:
sensors += [NestActivityZoneSensor(structure,
device,
activity_zone)]
add_devices(sensors, True)
class NestBinarySensor(NestSensor, BinarySensorDevice):
@ -57,3 +108,21 @@ class NestBinarySensor(NestSensor, BinarySensorDevice):
def update(self):
"""Retrieve latest state."""
self._state = bool(getattr(self.device, self.variable))
class NestActivityZoneSensor(NestBinarySensor):
"""Represents a Nest binary sensor for activity in a zone."""
def __init__(self, structure, device, zone):
"""Initialize the sensor."""
super(NestActivityZoneSensor, self).__init__(structure, device, None)
self.zone = zone
@property
def name(self):
"""Return the name of the nest, if any."""
return "{} {} activity".format(self._name, self.zone.name)
def update(self):
"""Retrieve latest state."""
self._state = self.device.has_ongoing_motion_in_zone(self.zone.zone_id)

View file

@ -19,7 +19,7 @@ _LOGGER = logging.getLogger(__name__)
REQUIREMENTS = [
'git+https://github.com/technicalpickles/python-nest.git'
'@nest-cam'
'@0be5c8a6307ee81540f21aac4fcd22cc5d98c988' # nest-cam branch
'#python-nest==3.0.0']
DOMAIN = 'nest'
@ -89,6 +89,7 @@ def setup_nest(hass, nest, config, pin=None):
_LOGGER.debug("proceeding with discovery")
discovery.load_platform(hass, 'climate', DOMAIN, {}, config)
discovery.load_platform(hass, 'sensor', DOMAIN, {}, config)
discovery.load_platform(hass, 'binary_sensor', DOMAIN, {}, config)
discovery.load_platform(hass, 'camera', DOMAIN, {}, config)
_LOGGER.debug("setup done")
@ -172,3 +173,18 @@ class NestDevice(object):
except socket.error:
_LOGGER.error(
"Connection error logging into the nest web service.")
def is_thermostat(device):
"""Target devices that are Nest Thermostats."""
return bool(device.__class__.__name__ == 'Device')
def is_protect(device):
"""Target devices that are Nest Protect Smoke Alarms."""
return bool(device.__class__.__name__ == 'ProtectDevice')
def is_camera(device):
"""Target devices that are Nest Protect Smoke Alarms."""
return bool(device.__class__.__name__ == 'CameraDevice')

View file

@ -5,6 +5,7 @@ For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/sensor.nest/
"""
from itertools import chain
import logging
import voluptuous as vol
@ -17,11 +18,13 @@ from homeassistant.const import (
DEPENDENCIES = ['nest']
SENSOR_TYPES = ['humidity',
'operation_mode',
'last_connection']
'operation_mode']
SENSOR_TYPES_DEPRECATED = ['battery_health',
'last_ip',
SENSOR_TYPES_DEPRECATED = ['last_ip',
'local_ip',
'last_connection']
SENSOR_TYPES_DEPRECATED = ['last_ip',
'local_ip']
WEATHER_VARS = {}
@ -43,22 +46,48 @@ PROTECT_VARS_DEPRECATED = ['battery_level']
SENSOR_TEMP_TYPES = ['temperature', 'target']
_VALID_SENSOR_TYPES = SENSOR_TYPES + SENSOR_TEMP_TYPES + PROTECT_VARS + \
list(WEATHER_VARS.keys())
_SENSOR_TYPES_DEPRECATED = SENSOR_TYPES_DEPRECATED \
+ list(DEPRECATED_WEATHER_VARS.keys()) + PROTECT_VARS_DEPRECATED
_VALID_SENSOR_TYPES = SENSOR_TYPES + SENSOR_TEMP_TYPES + PROTECT_VARS \
+ list(WEATHER_VARS.keys())
_VALID_SENSOR_TYPES_WITH_DEPRECATED = _VALID_SENSOR_TYPES \
+ _SENSOR_TYPES_DEPRECATED
PLATFORM_SCHEMA = vol.Schema({
vol.Required(CONF_PLATFORM): DOMAIN,
vol.Optional(CONF_SCAN_INTERVAL):
vol.All(vol.Coerce(int), vol.Range(min=1)),
vol.Required(CONF_MONITORED_CONDITIONS): [vol.In(_VALID_SENSOR_TYPES)],
vol.Required(CONF_MONITORED_CONDITIONS):
[vol.In(_VALID_SENSOR_TYPES_WITH_DEPRECATED)]
})
_LOGGER = logging.getLogger(__name__)
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Setup the Nest Sensor."""
nest = hass.data[DATA_NEST]
conf = config.get(CONF_MONITORED_CONDITIONS, _VALID_SENSOR_TYPES)
for variable in conf:
if variable in _SENSOR_TYPES_DEPRECATED:
if variable in DEPRECATED_WEATHER_VARS:
wstr = ("Nest no longer provides weather data like %s. See "
"https://home-assistant.io/components/#weather "
"for a list of other weather components to use." %
variable)
else:
wstr = (variable + " is no a longer supported "
"monitored_conditions. See "
"https://home-assistant.io/components/"
"binary_sensor.nest/ "
"for valid options, or remove monitored_conditions "
"entirely to get a reasonable default")
_LOGGER.error(wstr)
all_sensors = []
for structure, device in chain(nest.devices(), nest.protect_devices()):
sensors = [NestBasicSensor(structure, device, variable)
@ -67,10 +96,6 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
sensors += [NestTempSensor(structure, device, variable)
for variable in conf
if variable in SENSOR_TEMP_TYPES and is_thermostat(device)]
sensors += [NestWeatherSensor(structure, device,
WEATHER_VARS[variable])
for variable in conf
if variable in WEATHER_VARS and is_thermostat(device)]
sensors += [NestProtectSensor(structure, device, variable)
for variable in conf
if variable in PROTECT_VARS and is_protect(device)]
@ -100,13 +125,13 @@ class NestSensor(Entity):
# device specific
self._location = self.device.where
self._name = self.device.name
self._name = self.device.name_long
self._state = None
@property
def name(self):
"""Return the name of the nest, if any."""
return "{} {}".format(self._name, self.variable)
return "{} {}".format(self._name, self.variable.replace("_", " "))
class NestBasicSensor(NestSensor):
@ -159,29 +184,6 @@ class NestTempSensor(NestSensor):
self._state = round(temp, 1)
class NestWeatherSensor(NestSensor):
"""Representation a basic Nest Weather Conditions sensor."""
@property
def state(self):
"""Return the state of the sensor."""
return self._state
def update(self):
"""Retrieve latest state."""
if self.variable == 'kph' or self.variable == 'direction':
self._state = getattr(self.structure.weather.current.wind,
self.variable)
else:
self._state = getattr(self.structure.weather.current,
self.variable)
@property
def unit_of_measurement(self):
"""Return the unit the value is expressed in."""
return SENSOR_UNITS.get(self.variable, None)
class NestProtectSensor(NestSensor):
"""Return the state of nest protect."""

View file

@ -131,7 +131,7 @@ fuzzywuzzy==0.14.0
# gattlib==0.20150805
# homeassistant.components.nest
git+https://github.com/technicalpickles/python-nest.git@nest-cam#python-nest==3.0.0
git+https://github.com/technicalpickles/python-nest.git@0be5c8a6307ee81540f21aac4fcd22cc5d98c988#python-nest==3.0.0
# homeassistant.components.notify.gntp
gntp==1.0.3