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:
parent
af7de8d5ae
commit
64a5bff5b2
4 changed files with 143 additions and 56 deletions
|
@ -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)
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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."""
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue