diff --git a/homeassistant/components/binary_sensor/nest.py b/homeassistant/components/binary_sensor/nest.py index 65fe6041f34..d78e33c9f95 100644 --- a/homeassistant/components/binary_sensor/nest.py +++ b/homeassistant/components/binary_sensor/nest.py @@ -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) diff --git a/homeassistant/components/nest.py b/homeassistant/components/nest.py index 10310390dfe..a606cb488d4 100644 --- a/homeassistant/components/nest.py +++ b/homeassistant/components/nest.py @@ -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') diff --git a/homeassistant/components/sensor/nest.py b/homeassistant/components/sensor/nest.py index 1173fcedd57..b4909aebae3 100644 --- a/homeassistant/components/sensor/nest.py +++ b/homeassistant/components/sensor/nest.py @@ -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.""" diff --git a/requirements_all.txt b/requirements_all.txt index 0d3709509fb..82dce9a1d39 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -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