diff --git a/homeassistant/components/garage_door/__init__.py b/homeassistant/components/garage_door/__init__.py new file mode 100644 index 00000000000..572dd27cd90 --- /dev/null +++ b/homeassistant/components/garage_door/__init__.py @@ -0,0 +1,112 @@ +""" +homeassistant.components.garage_door +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Component to interface with garage doors that can be controlled remotely. + +For more details about this component, please refer to the documentation +at https://home-assistant.io/components/garage_door/ +""" +from datetime import timedelta +import logging +import os + +from homeassistant.config import load_yaml_config_file +from homeassistant.helpers.entity_component import EntityComponent +from homeassistant.helpers.entity import Entity + +from homeassistant.const import ( + STATE_CLOSED, STATE_OPEN, STATE_UNKNOWN, SERVICE_CLOSE, SERVICE_OPEN, + ATTR_ENTITY_ID) +from homeassistant.components import (group, wink) + +DOMAIN = 'garage_door' +SCAN_INTERVAL = 30 + +GROUP_NAME_ALL_GARAGE_DOORS = 'all garage doors' +ENTITY_ID_ALL_GARAGE_DOORS = group.ENTITY_ID_FORMAT.format('all_garage_doors') + +ENTITY_ID_FORMAT = DOMAIN + '.{}' + +ATTR_CLOSED = "closed" + +MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10) + +# Maps discovered services to their platforms +DISCOVERY_PLATFORMS = { + wink.DISCOVER_GARAGE_DOORS: 'wink' +} + +_LOGGER = logging.getLogger(__name__) + + +def is_closed(hass, entity_id=None): + """ Returns if the garage door is closed based on the statemachine. """ + entity_id = entity_id or ENTITY_ID_ALL_GARAGE_DOORS + return hass.states.is_state(entity_id, STATE_CLOSED) + + +def close(hass, entity_id=None): + """ Closes all or specified garage door. """ + data = {ATTR_ENTITY_ID: entity_id} if entity_id else None + hass.services.call(DOMAIN, SERVICE_CLOSE, data) + + +def open(hass, entity_id=None): + """ Open all or specified garage door. """ + data = {ATTR_ENTITY_ID: entity_id} if entity_id else None + hass.services.call(DOMAIN, SERVICE_OPEN, data) + + +def setup(hass, config): + """ Track states and offer events for garage door. """ + component = EntityComponent( + _LOGGER, DOMAIN, hass, SCAN_INTERVAL, DISCOVERY_PLATFORMS, + GROUP_NAME_ALL_GARAGE_DOORS) + component.setup(config) + + def handle_garage_door_service(service): + """ Handles calls to the garage door services. """ + target_locks = component.extract_from_service(service) + + for item in target_locks: + if service.service == SERVICE_CLOSE: + item.close() + else: + item.open() + + if item.should_poll: + item.update_ha_state(True) + + descriptions = load_yaml_config_file( + os.path.join(os.path.dirname(__file__), 'services.yaml')) + hass.services.register(DOMAIN, SERVICE_OPEN, handle_garage_door_service, + descriptions.get(SERVICE_OPEN)) + hass.services.register(DOMAIN, SERVICE_CLOSE, handle_garage_door_service, + descriptions.get(SERVICE_CLOSE)) + + return True + + +class GarageDoorDevice(Entity): + """ Represents a garage door within Home Assistant. """ + # pylint: disable=no-self-use + + @property + def is_closed(self): + """ Is the garage door closed or opened. """ + return None + + def close(self): + """ Closes the garage door. """ + raise NotImplementedError() + + def open(self): + """ Opens the garage door. """ + raise NotImplementedError() + + @property + def state(self): + closed = self.is_closed + if closed is None: + return STATE_UNKNOWN + return STATE_CLOSED if closed else STATE_OPEN diff --git a/homeassistant/components/garage_door/demo.py b/homeassistant/components/garage_door/demo.py new file mode 100644 index 00000000000..30935a0d3ef --- /dev/null +++ b/homeassistant/components/garage_door/demo.py @@ -0,0 +1,49 @@ +""" +homeassistant.components.garage_door.demo +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Demo platform that has two fake garage doors. +""" +from homeassistant.components.garage_door import GarageDoorDevice +from homeassistant.const import STATE_CLOSED, STATE_OPEN + + +# pylint: disable=unused-argument +def setup_platform(hass, config, add_devices_callback, discovery_info=None): + """ Find and return demo garage doors. """ + add_devices_callback([ + DemoGarageDoor('Left Garage Door', STATE_CLOSED), + DemoGarageDoor('Right Garage Door', STATE_OPEN) + ]) + + +class DemoGarageDoor(GarageDoorDevice): + """ Provides a demo garage door. """ + def __init__(self, name, state): + self._name = name + self._state = state + + @property + def should_poll(self): + """ No polling needed for a demo garage door. """ + return False + + @property + def name(self): + """ Returns the name of the device if any. """ + return self._name + + @property + def is_closed(self): + """ True if device is closed. """ + return self._state == STATE_CLOSED + + def close(self, **kwargs): + """ Close the device. """ + self._state = STATE_CLOSED + self.update_ha_state() + + def open(self, **kwargs): + """ Open the device. """ + self._state = STATE_OPEN + self.update_ha_state() diff --git a/homeassistant/components/garage_door/services.yaml b/homeassistant/components/garage_door/services.yaml new file mode 100644 index 00000000000..e69de29bb2d diff --git a/homeassistant/components/garage_door/wink.py b/homeassistant/components/garage_door/wink.py new file mode 100644 index 00000000000..8283575f19d --- /dev/null +++ b/homeassistant/components/garage_door/wink.py @@ -0,0 +1,67 @@ +""" +homeassistant.components.garage_door.wink +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Support for Wink garage doors. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/garage_door.wink/ +""" +import logging + +from homeassistant.components.garage_door import GarageDoorDevice +from homeassistant.const import CONF_ACCESS_TOKEN + +REQUIREMENTS = ['python-wink==0.4.2'] + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """ Sets up the Wink platform. """ + import pywink + + if discovery_info is None: + 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) + + add_devices(WinkGarageDoorDevice(door) for door in + pywink.get_garage_doors()) + + +class WinkGarageDoorDevice(GarageDoorDevice): + """ Represents a Wink garage door. """ + + def __init__(self, wink): + self.wink = wink + + @property + def unique_id(self): + """ Returns the id of this wink garage door """ + return "{}.{}".format(self.__class__, self.wink.device_id()) + + @property + def name(self): + """ Returns the name of the garage door if any. """ + return self.wink.name() + + def update(self): + """ Update the state of the garage door. """ + self.wink.update_state() + + @property + def is_closed(self): + """ True if device is closed. """ + return self.wink.state() == 0 + + def close(self): + """ Close the device. """ + self.wink.set_state(0) + + def open(self): + """ Open the device. """ + self.wink.set_state(1) diff --git a/homeassistant/components/wink.py b/homeassistant/components/wink.py index 88881ad1ab7..6fa2b9287e9 100644 --- a/homeassistant/components/wink.py +++ b/homeassistant/components/wink.py @@ -22,6 +22,7 @@ DISCOVER_LIGHTS = "wink.lights" DISCOVER_SWITCHES = "wink.switches" DISCOVER_SENSORS = "wink.sensors" DISCOVER_LOCKS = "wink.locks" +DISCOVER_GARAGE_DOORS = "wink.garage_doors" def setup(hass, config): @@ -42,7 +43,8 @@ def setup(hass, config): pywink.get_powerstrip_outlets, DISCOVER_SWITCHES), ('sensor', lambda: pywink.get_sensors or pywink.get_eggtrays, DISCOVER_SENSORS), - ('lock', pywink.get_locks, DISCOVER_LOCKS)): + ('lock', pywink.get_locks, DISCOVER_LOCKS), + ('garage_door', pywink.get_garage_doors, DISCOVER_GARAGE_DOORS)): if func_exists(): component = get_component(component_name) diff --git a/homeassistant/const.py b/homeassistant/const.py index 42146895a01..d89b4021180 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -151,6 +151,9 @@ SERVICE_ALARM_TRIGGER = "alarm_trigger" SERVICE_LOCK = "lock" SERVICE_UNLOCK = "unlock" +SERVICE_OPEN = "open" +SERVICE_CLOSE = "close" + SERVICE_MOVE_UP = 'move_up' SERVICE_MOVE_DOWN = 'move_down' SERVICE_STOP = 'stop' diff --git a/requirements_all.txt b/requirements_all.txt index f72daaecccf..b0c07fa9ee1 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -6,150 +6,17 @@ pip>=7.0.0 vincenty==0.1.3 jinja2>=2.8 -# homeassistant.components.isy994 -PyISY==1.0.5 +# homeassistant.components.alarm_control_panel.alarmdotcom +https://github.com/Xorso/pyalarmdotcom/archive/0.0.7.zip#pyalarmdotcom==0.0.7 # homeassistant.components.arduino PyMata==2.07a -# homeassistant.components.rpi_gpio -# RPi.GPIO==0.6.1 - -# homeassistant.components.media_player.sonos -SoCo==0.11.1 - -# homeassistant.components.notify.twitter -TwitterAPI==2.3.6 - -# homeassistant.components.sun -astral==0.9 - -# homeassistant.components.light.blinksticklight -blinkstick==1.1.7 - -# homeassistant.components.sensor.bitcoin -blockchain==1.2.1 - -# homeassistant.components.notify.xmpp -dnspython3==1.12.0 - -# homeassistant.components.sensor.dweet -dweepy==0.2.0 - -# homeassistant.components.sensor.eliqonline -eliqonline==1.0.11 - -# homeassistant.components.thermostat.honeywell -evohomeclient==0.2.4 - -# homeassistant.components.notify.free_mobile -freesms==0.1.0 - -# homeassistant.components.device_tracker.fritz -# fritzconnection==0.4.6 - # homeassistant.components.conversation fuzzywuzzy==0.8.0 -# homeassistant.components.thermostat.heatmiser -heatmiserV3==0.9.1 - -# homeassistant.components.switch.hikvisioncam -hikvision==0.4 - -# homeassistant.components.sensor.dht -# http://github.com/mala-zaba/Adafruit_Python_DHT/archive/4101340de8d2457dd194bca1e8d11cbfc237e919.zip#Adafruit_DHT==1.1.0 - -# homeassistant.components.rfxtrx -https://github.com/Danielhiversen/pyRFXtrx/archive/0.2.zip#RFXtrx==0.2 - -# homeassistant.components.sensor.netatmo -https://github.com/HydrelioxGitHub/netatmo-api-python/archive/43ff238a0122b0939a0dc4e8836b6782913fb6e2.zip#lnetatmo==0.4.0 - -# homeassistant.components.alarm_control_panel.alarmdotcom -https://github.com/Xorso/pyalarmdotcom/archive/0.0.7.zip#pyalarmdotcom==0.0.7 - -# homeassistant.components.modbus -https://github.com/bashwork/pymodbus/archive/d7fc4f1cc975631e0a9011390e8017f64b612661.zip#pymodbus==1.2.0 - -# homeassistant.components.sensor.sabnzbd -https://github.com/jamespcole/home-assistant-nzb-clients/archive/616cad59154092599278661af17e2a9f2cf5e2a9.zip#python-sabnzbd==0.1 - -# homeassistant.components.ecobee -https://github.com/nkgilley/python-ecobee-api/archive/92a2f330cbaf601d0618456fdd97e5a8c42c1c47.zip#python-ecobee==0.0.4 - -# homeassistant.components.switch.edimax -https://github.com/rkabadi/pyedimax/archive/365301ce3ff26129a7910c501ead09ea625f3700.zip#pyedimax==0.1 - -# homeassistant.components.sensor.temper -https://github.com/rkabadi/temper-python/archive/3dbdaf2d87b8db9a3cd6e5585fc704537dd2d09b.zip#temperusb==1.2.3 - -# homeassistant.components.mysensors -https://github.com/theolind/pymysensors/archive/005bff4c5ca7a56acd30e816bc3bcdb5cb2d46fd.zip#pymysensors==0.4 - -# homeassistant.components.notify.googlevoice -https://github.com/w1ll1am23/pygooglevoice-sms/archive/7c5ee9969b97a7992fc86a753fe9f20e3ffa3f7c.zip#pygooglevoice-sms==0.0.1 - -# homeassistant.components.influxdb -influxdb==2.12.0 - -# homeassistant.components.insteon_hub -insteon_hub==0.4.5 - -# homeassistant.components.media_player.kodi -jsonrpc-requests==0.1 - -# homeassistant.components.light.lifx -liffylights==0.9.4 - -# homeassistant.components.light.limitlessled -limitlessled==1.0.0 - -# homeassistant.components.sensor.mfi -# homeassistant.components.switch.mfi -mficlient==0.2.2 - -# homeassistant.components.discovery -netdisco==0.5.2 - -# homeassistant.components.switch.orvibo -orvibo==1.1.1 - -# homeassistant.components.mqtt -paho-mqtt==1.1 - -# homeassistant.components.device_tracker.aruba -pexpect==4.0.1 - -# homeassistant.components.light.hue -phue==0.8 - -# homeassistant.components.media_player.plex -plexapi==1.1.0 - -# homeassistant.components.thermostat.proliphix -proliphix==0.1.0 - -# homeassistant.components.sensor.systemmonitor -psutil==3.4.2 - -# homeassistant.components.notify.pushbullet -pushbullet.py==0.9.0 - -# homeassistant.components.notify.pushetta -pushetta==1.0.15 - -# homeassistant.components.sensor.cpuspeed -py-cpuinfo==0.1.8 - -# homeassistant.components.media_player.cast -pychromecast==0.7.1 - -# homeassistant.components.zwave -pydispatcher==2.0.5 - -# homeassistant.components.ifttt -pyfttt==0.3 +# homeassistant.components.device_tracker.fritz +# fritzconnection==0.4.6 # homeassistant.components.device_tracker.icloud pyicloud==0.7.2 @@ -157,86 +24,207 @@ pyicloud==0.7.2 # homeassistant.components.device_tracker.netgear pynetgear==0.3.2 -# homeassistant.components.alarm_control_panel.nx584 -pynx584==0.1 - -# homeassistant.components.sensor.openweathermap -pyowm==2.3.0 +# homeassistant.components.device_tracker.nmap_tracker +python-nmap==0.4.3 # homeassistant.components.device_tracker.snmp pysnmp==4.2.5 -# homeassistant.components.sensor.forecast -python-forecastio==1.3.3 +# homeassistant.components.discovery +netdisco==0.5.2 -# homeassistant.components.media_player.mpd -python-mpd2==0.5.4 +# homeassistant.components.ecobee +https://github.com/nkgilley/python-ecobee-api/archive/92a2f330cbaf601d0618456fdd97e5a8c42c1c47.zip#python-ecobee==0.0.4 -# homeassistant.components.nest -python-nest==2.6.0 +# homeassistant.components.ifttt +pyfttt==0.3 -# homeassistant.components.device_tracker.nmap_tracker -python-nmap==0.4.3 +# homeassistant.components.influxdb +influxdb==2.11.0 -# homeassistant.components.notify.pushover -python-pushover==0.2 +# homeassistant.components.insteon_hub +insteon_hub==0.4.5 -# homeassistant.components.statsd -python-statsd==1.7.2 - -# homeassistant.components.notify.telegram -python-telegram-bot==3.2.0 - -# homeassistant.components.sensor.twitch -python-twitch==1.2.0 - -# homeassistant.components.wink -# homeassistant.components.light.wink -# homeassistant.components.lock.wink -# homeassistant.components.sensor.wink -# homeassistant.components.switch.wink -python-wink==0.5.0 +# homeassistant.components.isy994 +PyISY==1.0.5 # homeassistant.components.keyboard pyuserinput==0.1.9 -# homeassistant.components.light.vera -# homeassistant.components.sensor.vera -# homeassistant.components.switch.vera -pyvera==0.2.8 +# homeassistant.components.light.blinksticklight +blinkstick==1.1.7 -# homeassistant.components.switch.wemo -pywemo==0.3.9 +# homeassistant.components.light.hue +phue==0.8 -# homeassistant.components.thermostat.radiotherm -radiotherm==1.2 +# homeassistant.components.light.lifx +liffylights==0.9.3 -# homeassistant.components.media_player.samsungtv -samsungctl==0.5.1 - -# homeassistant.components.scsgate -scsgate==0.1.0 - -# homeassistant.components.notify.slack -slacker==0.6.8 - -# homeassistant.components.notify.xmpp -sleekxmpp==1.3.1 +# homeassistant.components.light.limitlessled +limitlessled==1.0.0 # homeassistant.components.light.tellstick # homeassistant.components.sensor.tellstick # homeassistant.components.switch.tellstick tellcore-py==1.1.2 -# homeassistant.components.tellduslive -tellive-py==0.5.2 +# homeassistant.components.light.vera +# homeassistant.components.sensor.vera +# homeassistant.components.switch.vera +pyvera==0.2.7 + +# homeassistant.components.wink +# homeassistant.components.light.wink +# homeassistant.components.lock.wink +# homeassistant.components.sensor.wink +# homeassistant.components.switch.wink +# homeassistant.components.garage_door.wink +python-wink==0.4.2 + +# homeassistant.components.media_player.cast +pychromecast==0.7.1 + +# homeassistant.components.media_player.kodi +jsonrpc-requests==0.1 + +# homeassistant.components.media_player.mpd +python-mpd2==0.5.4 + +# homeassistant.components.media_player.plex +plexapi==1.1.0 + +# homeassistant.components.media_player.samsungtv +samsungctl==0.5.1 + +# homeassistant.components.media_player.sonos +SoCo==0.11.1 + +# homeassistant.components.modbus +https://github.com/bashwork/pymodbus/archive/d7fc4f1cc975631e0a9011390e8017f64b612661.zip#pymodbus==1.2.0 + +# homeassistant.components.mqtt +paho-mqtt==1.1 + +# homeassistant.components.mysensors +https://github.com/theolind/pymysensors/archive/005bff4c5ca7a56acd30e816bc3bcdb5cb2d46fd.zip#pymysensors==0.4 + +# homeassistant.components.nest +python-nest==2.6.0 + +# homeassistant.components.notify.free_mobile +freesms==0.1.0 + +# homeassistant.components.notify.googlevoice +https://github.com/w1ll1am23/pygooglevoice-sms/archive/7c5ee9969b97a7992fc86a753fe9f20e3ffa3f7c.zip#pygooglevoice-sms==0.0.1 + +# homeassistant.components.notify.pushbullet +pushbullet.py==0.9.0 + +# homeassistant.components.notify.pushetta +pushetta==1.0.15 + +# homeassistant.components.notify.pushover +python-pushover==0.2 + +# homeassistant.components.notify.slack +slacker==0.6.8 + +# homeassistant.components.notify.telegram +python-telegram-bot==3.2.0 + +# homeassistant.components.notify.twitter +TwitterAPI==2.3.6 + +# homeassistant.components.notify.xmpp +sleekxmpp==1.3.1 + +# homeassistant.components.notify.xmpp +dnspython3==1.12.0 + +# homeassistant.components.rfxtrx +https://github.com/Danielhiversen/pyRFXtrx/archive/0.2.zip#RFXtrx==0.2 + +# homeassistant.components.rpi_gpio +# RPi.GPIO==0.6.1 + +# homeassistant.components.scsgate +scsgate==0.1.0 + +# homeassistant.components.sensor.bitcoin +blockchain==1.2.1 + +# homeassistant.components.sensor.cpuspeed +py-cpuinfo==0.1.8 + +# homeassistant.components.sensor.dht +# http://github.com/mala-zaba/Adafruit_Python_DHT/archive/4101340de8d2457dd194bca1e8d11cbfc237e919.zip#Adafruit_DHT==1.1.0 + +# homeassistant.components.sensor.dweet +dweepy==0.2.0 + +# homeassistant.components.sensor.eliqonline +eliqonline==1.0.11 + +# homeassistant.components.sensor.forecast +python-forecastio==1.3.3 + +# homeassistant.components.sensor.netatmo +https://github.com/HydrelioxGitHub/netatmo-api-python/archive/43ff238a0122b0939a0dc4e8836b6782913fb6e2.zip#lnetatmo==0.4.0 + +# homeassistant.components.sensor.openweathermap +pyowm==2.3.0 + +# homeassistant.components.sensor.sabnzbd +https://github.com/jamespcole/home-assistant-nzb-clients/archive/616cad59154092599278661af17e2a9f2cf5e2a9.zip#python-sabnzbd==0.1 + +# homeassistant.components.sensor.systemmonitor +psutil==3.4.2 + +# homeassistant.components.sensor.temper +https://github.com/rkabadi/temper-python/archive/3dbdaf2d87b8db9a3cd6e5585fc704537dd2d09b.zip#temperusb==1.2.3 # homeassistant.components.sensor.transmission # homeassistant.components.switch.transmission transmissionrpc==0.11 -# homeassistant.components.camera.uvc -uvcclient==0.5 +# homeassistant.components.sensor.twitch +python-twitch==1.2.0 + +# homeassistant.components.sensor.yr +xmltodict + +# homeassistant.components.statsd +python-statsd==1.7.2 + +# homeassistant.components.sun +astral==0.9 + +# homeassistant.components.switch.edimax +https://github.com/rkabadi/pyedimax/archive/365301ce3ff26129a7910c501ead09ea625f3700.zip#pyedimax==0.1 + +# homeassistant.components.switch.hikvisioncam +hikvision==0.4 + +# homeassistant.components.switch.orvibo +orvibo==1.1.1 + +# homeassistant.components.switch.wemo +pywemo==0.3.8 + +# homeassistant.components.tellduslive +tellive-py==0.5.2 + +# homeassistant.components.thermostat.heatmiser +heatmiserV3==0.9.1 + +# homeassistant.components.thermostat.honeywell +evohomeclient==0.2.4 + +# homeassistant.components.thermostat.proliphix +proliphix==0.1.0 + +# homeassistant.components.thermostat.radiotherm +radiotherm==1.2 # homeassistant.components.verisure vsure==0.5.0 @@ -244,5 +232,5 @@ vsure==0.5.0 # homeassistant.components.zigbee xbee-helper==0.0.6 -# homeassistant.components.sensor.yr -xmltodict +# homeassistant.components.zwave +pydispatcher==2.0.5