From 7fbd36ccad06c2d54ce34d6e0a31cd96d6ab69a0 Mon Sep 17 00:00:00 2001 From: Geoff Norton Date: Tue, 20 Jan 2015 01:16:04 +0000 Subject: [PATCH] Add a new sensor component Hook up to scan sensor_pod_id's from Wink and report their status. --- homeassistant/components/sensor/__init__.py | 89 +++++++++++++++++++++ homeassistant/components/sensor/wink.py | 35 ++++++++ homeassistant/components/wink.py | 33 +++++++- homeassistant/const.py | 2 + 4 files changed, 156 insertions(+), 3 deletions(-) create mode 100644 homeassistant/components/sensor/__init__.py create mode 100644 homeassistant/components/sensor/wink.py diff --git a/homeassistant/components/sensor/__init__.py b/homeassistant/components/sensor/__init__.py new file mode 100644 index 00000000000..925e3bf9bec --- /dev/null +++ b/homeassistant/components/sensor/__init__.py @@ -0,0 +1,89 @@ +""" +homeassistant.components.sensor +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Component to interface with various sensors that can be monitored. +""" +import logging +from datetime import timedelta + +from homeassistant.loader import get_component +import homeassistant.util as util +from homeassistant.const import ( + STATE_OPEN, ATTR_ENTITY_ID) +from homeassistant.helpers import ( + extract_entity_ids, platform_devices_from_config) +from homeassistant.components import group, discovery, wink + +DOMAIN = 'sensor' +DEPENDENCIES = [] + +GROUP_NAME_ALL_SENSORS = 'all_sensors' +ENTITY_ID_ALL_SENSORS = group.ENTITY_ID_FORMAT.format( + GROUP_NAME_ALL_SENSORS) + +ENTITY_ID_FORMAT = DOMAIN + '.{}' + +MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10) + +# Maps discovered services to their platforms +DISCOVERY_PLATFORMS = { + wink.DISCOVER_SENSORS: 'wink', +} + +_LOGGER = logging.getLogger(__name__) + + +def is_on(hass, entity_id=None): + """ Returns if the sensor is open based on the statemachine. """ + entity_id = entity_id or ENTITY_ID_ALL_SENSORS + + return hass.states.is_state(entity_id, STATE_OPEN) + +def setup(hass, config): + """ Track states and offer events for sensors. """ + logger = logging.getLogger(__name__) + + sensors = platform_devices_from_config( + config, DOMAIN, hass, ENTITY_ID_FORMAT, logger) + + # pylint: disable=unused-argument + @util.Throttle(MIN_TIME_BETWEEN_SCANS) + def update_states(now): + """ Update states of all sensors. """ + if sensors: + logger.info("Updating sensors states") + + for sensor in sensors.values(): + sensor.update_ha_state(hass, True) + + update_states(None) + + # Track all sensors in a group + sensor_group = group.Group( + hass, GROUP_NAME_ALL_SENSORS, sensors.keys(), False) + + def sensor_discovered(service, info): + """ Called when a sensor is discovered. """ + platform = get_component("{}.{}".format( + DOMAIN, DISCOVERY_PLATFORMS[service])) + + discovered = platform.devices_discovered(hass, config, info) + + for sensor in discovered: + if sensor is not None and sensor not in sensors.values(): + sensor.entity_id = util.ensure_unique_string( + ENTITY_ID_FORMAT.format(util.slugify(sensor.name)), + sensors.keys()) + + sensors[sensor.entity_id] = sensor + + sensor.update_ha_state(hass) + + sensor_group.update_tracked_entity_ids(sensors.keys()) + + discovery.listen(hass, DISCOVERY_PLATFORMS.keys(), sensor_discovered) + + # Update state every 30 seconds + hass.track_time_change(update_states, second=[0, 30]) + + return True diff --git a/homeassistant/components/sensor/wink.py b/homeassistant/components/sensor/wink.py new file mode 100644 index 00000000000..99303d3ef56 --- /dev/null +++ b/homeassistant/components/sensor/wink.py @@ -0,0 +1,35 @@ +""" Support for Wink sensors. """ +import logging + +# pylint: disable=no-name-in-module, import-error +import homeassistant.external.wink.pywink as pywink + +from homeassistant.components.wink import WinkSensorDevice +from homeassistant.const import CONF_ACCESS_TOKEN + + +# pylint: disable=unused-argument +def get_devices(hass, config): + """ Find and return Wink sensors. """ + token = config.get(CONF_ACCESS_TOKEN) + + if token is None: + logging.getLogger(__name__).error( + "Missing wink access_token - " + "get one at https://winkbearertoken.appspot.com/") + return [] + + pywink.set_bearer_token(token) + + return get_sensors() + + +# pylint: disable=unused-argument +def devices_discovered(hass, config, info): + """ Called when a device is discovered. """ + return get_sensors() + + +def get_sensors(): + """ Returns the Wink sensors. """ + return [WinkSensorDevice(sensor) for sensor in pywink.get_sensors()] diff --git a/homeassistant/components/wink.py b/homeassistant/components/wink.py index d049d1ecc26..dba73dc1dae 100644 --- a/homeassistant/components/wink.py +++ b/homeassistant/components/wink.py @@ -8,7 +8,7 @@ import homeassistant.external.wink.pywink as pywink from homeassistant import bootstrap from homeassistant.loader import get_component -from homeassistant.helpers import validate_config, ToggleDevice +from homeassistant.helpers import validate_config, ToggleDevice, Device from homeassistant.const import ( EVENT_PLATFORM_DISCOVERED, CONF_ACCESS_TOKEN, ATTR_SERVICE, ATTR_DISCOVERED, ATTR_FRIENDLY_NAME) @@ -18,7 +18,7 @@ DEPENDENCIES = [] DISCOVER_LIGHTS = "wink.lights" DISCOVER_SWITCHES = "wink.switches" - +DISCOVER_SENSORS = "wink.sensors" def setup(hass, config): """ Sets up the Wink component. """ @@ -32,7 +32,8 @@ def setup(hass, config): # Load components for the devices in the Wink that we support for component_name, func_exists, discovery_type in ( ('light', pywink.get_bulbs, DISCOVER_LIGHTS), - ('switch', pywink.get_switches, DISCOVER_SWITCHES)): + ('switch', pywink.get_switches, DISCOVER_SWITCHES), + ('sensor', pywink.get_sensors, DISCOVER_SENSORS)): if func_exists(): component = get_component(component_name) @@ -49,6 +50,32 @@ def setup(hass, config): return True +class WinkSensorDevice(Device): + """ represents a wink sensor within home assistant. """ + + def __init__(self, wink): + self.wink = wink + + @property + def unique_id(self): + """ Returns the id of this wink switch """ + return "{}.{}".format(self.__class__, self.wink.deviceId()) + + @property + def name(self): + """ Returns the name of the sensor if any. """ + return self.wink.name() + + @property + def state_attributes(self): + """ Returns optional state attributes. """ + return { + ATTR_FRIENDLY_NAME: self.wink.name() + } + + def update(self): + """ Update state of the sensor. """ + self.wink.updateState() class WinkToggleDevice(ToggleDevice): """ represents a WeMo switch within home assistant. """ diff --git a/homeassistant/const.py b/homeassistant/const.py index 39089ae84cb..31c575b96c7 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -35,6 +35,8 @@ STATE_OFF = 'off' STATE_HOME = 'home' STATE_NOT_HOME = 'not_home' STATE_UNKNOWN = "unknown" +STATE_OPEN = 'open' +STATE_CLOSED = 'closed' # #### STATE AND EVENT ATTRIBUTES #### # Contains current time for a TIME_CHANGED event