mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 05:07:41 +00:00
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,17 +4,34 @@ Support for Nest Thermostat Binary Sensors.
|
|||||||
For more details about this platform, please refer to the documentation at
|
For more details about this platform, please refer to the documentation at
|
||||||
https://home-assistant.io/components/binary_sensor.nest/
|
https://home-assistant.io/components/binary_sensor.nest/
|
||||||
"""
|
"""
|
||||||
|
from itertools import chain
|
||||||
|
import logging
|
||||||
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.components.binary_sensor import (
|
from homeassistant.components.binary_sensor import (
|
||||||
BinarySensorDevice, PLATFORM_SCHEMA)
|
BinarySensorDevice, PLATFORM_SCHEMA)
|
||||||
from homeassistant.components.sensor.nest import NestSensor
|
from homeassistant.components.sensor.nest import NestSensor
|
||||||
from homeassistant.const import (CONF_SCAN_INTERVAL, CONF_MONITORED_CONDITIONS)
|
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
|
import homeassistant.helpers.config_validation as cv
|
||||||
|
|
||||||
DEPENDENCIES = ['nest']
|
DEPENDENCIES = ['nest']
|
||||||
BINARY_TYPES = ['fan',
|
|
||||||
|
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_ac_state',
|
||||||
'hvac_aux_heater_state',
|
'hvac_aux_heater_state',
|
||||||
'hvac_heater_state',
|
'hvac_heater_state',
|
||||||
@ -22,28 +39,62 @@ BINARY_TYPES = ['fan',
|
|||||||
'hvac_heat_x3_state',
|
'hvac_heat_x3_state',
|
||||||
'hvac_alt_heat_state',
|
'hvac_alt_heat_state',
|
||||||
'hvac_alt_heat_x2_state',
|
'hvac_alt_heat_x2_state',
|
||||||
'hvac_emer_heat_state',
|
'hvac_emer_heat_state']
|
||||||
'online']
|
|
||||||
|
_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({
|
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
||||||
vol.Optional(CONF_SCAN_INTERVAL):
|
vol.Optional(CONF_SCAN_INTERVAL):
|
||||||
vol.All(vol.Coerce(int), vol.Range(min=1)),
|
vol.All(vol.Coerce(int), vol.Range(min=1)),
|
||||||
vol.Required(CONF_MONITORED_CONDITIONS):
|
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):
|
def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||||
"""Setup Nest binary sensors."""
|
"""Setup Nest binary sensors."""
|
||||||
nest = hass.data[DATA_NEST]
|
nest = hass.data[DATA_NEST]
|
||||||
|
conf = config.get(CONF_MONITORED_CONDITIONS, _VALID_BINARY_SENSOR_TYPES)
|
||||||
|
|
||||||
all_sensors = []
|
for variable in conf:
|
||||||
for structure, device in nest.devices():
|
if variable in _BINARY_TYPES_DEPRECATED:
|
||||||
all_sensors.extend(
|
wstr = (variable + " is no a longer supported "
|
||||||
[NestBinarySensor(structure, device, variable)
|
"monitored_conditions. See "
|
||||||
for variable in config[CONF_MONITORED_CONDITIONS]])
|
"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):
|
class NestBinarySensor(NestSensor, BinarySensorDevice):
|
||||||
@ -57,3 +108,21 @@ class NestBinarySensor(NestSensor, BinarySensorDevice):
|
|||||||
def update(self):
|
def update(self):
|
||||||
"""Retrieve latest state."""
|
"""Retrieve latest state."""
|
||||||
self._state = bool(getattr(self.device, self.variable))
|
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 = [
|
REQUIREMENTS = [
|
||||||
'git+https://github.com/technicalpickles/python-nest.git'
|
'git+https://github.com/technicalpickles/python-nest.git'
|
||||||
'@nest-cam'
|
'@0be5c8a6307ee81540f21aac4fcd22cc5d98c988' # nest-cam branch
|
||||||
'#python-nest==3.0.0']
|
'#python-nest==3.0.0']
|
||||||
|
|
||||||
DOMAIN = 'nest'
|
DOMAIN = 'nest'
|
||||||
@ -89,6 +89,7 @@ def setup_nest(hass, nest, config, pin=None):
|
|||||||
_LOGGER.debug("proceeding with discovery")
|
_LOGGER.debug("proceeding with discovery")
|
||||||
discovery.load_platform(hass, 'climate', DOMAIN, {}, config)
|
discovery.load_platform(hass, 'climate', DOMAIN, {}, config)
|
||||||
discovery.load_platform(hass, 'sensor', DOMAIN, {}, config)
|
discovery.load_platform(hass, 'sensor', DOMAIN, {}, config)
|
||||||
|
discovery.load_platform(hass, 'binary_sensor', DOMAIN, {}, config)
|
||||||
discovery.load_platform(hass, 'camera', DOMAIN, {}, config)
|
discovery.load_platform(hass, 'camera', DOMAIN, {}, config)
|
||||||
_LOGGER.debug("setup done")
|
_LOGGER.debug("setup done")
|
||||||
|
|
||||||
@ -172,3 +173,18 @@ class NestDevice(object):
|
|||||||
except socket.error:
|
except socket.error:
|
||||||
_LOGGER.error(
|
_LOGGER.error(
|
||||||
"Connection error logging into the nest web service.")
|
"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/
|
https://home-assistant.io/components/sensor.nest/
|
||||||
"""
|
"""
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
|
import logging
|
||||||
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
@ -17,11 +18,13 @@ from homeassistant.const import (
|
|||||||
|
|
||||||
DEPENDENCIES = ['nest']
|
DEPENDENCIES = ['nest']
|
||||||
SENSOR_TYPES = ['humidity',
|
SENSOR_TYPES = ['humidity',
|
||||||
'operation_mode',
|
'operation_mode']
|
||||||
|
|
||||||
|
SENSOR_TYPES_DEPRECATED = ['last_ip',
|
||||||
|
'local_ip',
|
||||||
'last_connection']
|
'last_connection']
|
||||||
|
|
||||||
SENSOR_TYPES_DEPRECATED = ['battery_health',
|
SENSOR_TYPES_DEPRECATED = ['last_ip',
|
||||||
'last_ip',
|
|
||||||
'local_ip']
|
'local_ip']
|
||||||
|
|
||||||
WEATHER_VARS = {}
|
WEATHER_VARS = {}
|
||||||
@ -43,22 +46,48 @@ PROTECT_VARS_DEPRECATED = ['battery_level']
|
|||||||
|
|
||||||
SENSOR_TEMP_TYPES = ['temperature', 'target']
|
SENSOR_TEMP_TYPES = ['temperature', 'target']
|
||||||
|
|
||||||
_VALID_SENSOR_TYPES = SENSOR_TYPES + SENSOR_TEMP_TYPES + PROTECT_VARS + \
|
_SENSOR_TYPES_DEPRECATED = SENSOR_TYPES_DEPRECATED \
|
||||||
list(WEATHER_VARS.keys())
|
+ 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({
|
PLATFORM_SCHEMA = vol.Schema({
|
||||||
vol.Required(CONF_PLATFORM): DOMAIN,
|
vol.Required(CONF_PLATFORM): DOMAIN,
|
||||||
vol.Optional(CONF_SCAN_INTERVAL):
|
vol.Optional(CONF_SCAN_INTERVAL):
|
||||||
vol.All(vol.Coerce(int), vol.Range(min=1)),
|
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):
|
def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||||
"""Setup the Nest Sensor."""
|
"""Setup the Nest Sensor."""
|
||||||
nest = hass.data[DATA_NEST]
|
nest = hass.data[DATA_NEST]
|
||||||
conf = config.get(CONF_MONITORED_CONDITIONS, _VALID_SENSOR_TYPES)
|
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 = []
|
all_sensors = []
|
||||||
for structure, device in chain(nest.devices(), nest.protect_devices()):
|
for structure, device in chain(nest.devices(), nest.protect_devices()):
|
||||||
sensors = [NestBasicSensor(structure, device, variable)
|
sensors = [NestBasicSensor(structure, device, variable)
|
||||||
@ -67,10 +96,6 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
|
|||||||
sensors += [NestTempSensor(structure, device, variable)
|
sensors += [NestTempSensor(structure, device, variable)
|
||||||
for variable in conf
|
for variable in conf
|
||||||
if variable in SENSOR_TEMP_TYPES and is_thermostat(device)]
|
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)
|
sensors += [NestProtectSensor(structure, device, variable)
|
||||||
for variable in conf
|
for variable in conf
|
||||||
if variable in PROTECT_VARS and is_protect(device)]
|
if variable in PROTECT_VARS and is_protect(device)]
|
||||||
@ -100,13 +125,13 @@ class NestSensor(Entity):
|
|||||||
|
|
||||||
# device specific
|
# device specific
|
||||||
self._location = self.device.where
|
self._location = self.device.where
|
||||||
self._name = self.device.name
|
self._name = self.device.name_long
|
||||||
self._state = None
|
self._state = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
"""Return the name of the nest, if any."""
|
"""Return the name of the nest, if any."""
|
||||||
return "{} {}".format(self._name, self.variable)
|
return "{} {}".format(self._name, self.variable.replace("_", " "))
|
||||||
|
|
||||||
|
|
||||||
class NestBasicSensor(NestSensor):
|
class NestBasicSensor(NestSensor):
|
||||||
@ -159,29 +184,6 @@ class NestTempSensor(NestSensor):
|
|||||||
self._state = round(temp, 1)
|
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):
|
class NestProtectSensor(NestSensor):
|
||||||
"""Return the state of nest protect."""
|
"""Return the state of nest protect."""
|
||||||
|
|
||||||
|
@ -131,7 +131,7 @@ fuzzywuzzy==0.14.0
|
|||||||
# gattlib==0.20150805
|
# gattlib==0.20150805
|
||||||
|
|
||||||
# homeassistant.components.nest
|
# 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
|
# homeassistant.components.notify.gntp
|
||||||
gntp==1.0.3
|
gntp==1.0.3
|
||||||
|
Loading…
x
Reference in New Issue
Block a user