From 47bbfc309c8d1fd500a40230076a8f6851a6b38a Mon Sep 17 00:00:00 2001 From: William Scanlon Date: Wed, 25 Jan 2017 00:11:18 -0500 Subject: [PATCH] Support for python-wink 1.0.0 (#5534) --- .../components/alarm_control_panel/wink.py | 68 ++++++++++++++ .../components/binary_sensor/wink.py | 91 ++++++++++++++----- homeassistant/components/light/wink.py | 2 +- homeassistant/components/sensor/wink.py | 45 +++------ homeassistant/components/switch/wink.py | 4 +- homeassistant/components/wink.py | 37 +++++--- requirements_all.txt | 4 +- 7 files changed, 177 insertions(+), 74 deletions(-) create mode 100644 homeassistant/components/alarm_control_panel/wink.py diff --git a/homeassistant/components/alarm_control_panel/wink.py b/homeassistant/components/alarm_control_panel/wink.py new file mode 100644 index 00000000000..2a600fe70a9 --- /dev/null +++ b/homeassistant/components/alarm_control_panel/wink.py @@ -0,0 +1,68 @@ +""" +Interfaces with Wink Cameras. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/alarm_control_panel.wink/ +""" +import logging + +import homeassistant.components.alarm_control_panel as alarm +from homeassistant.const import (STATE_UNKNOWN, + STATE_ALARM_DISARMED, + STATE_ALARM_ARMED_HOME, + STATE_ALARM_ARMED_AWAY) +from homeassistant.components.wink import WinkDevice + +_LOGGER = logging.getLogger(__name__) + +DEPENDENCIES = ['wink'] +STATE_ALARM_PRIVACY = 'Private' + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """Setup the Wink platform.""" + import pywink + + for camera in pywink.get_cameras(): + add_devices([WinkCameraDevice(camera, hass)]) + + +class WinkCameraDevice(WinkDevice, alarm.AlarmControlPanel): + """Representation a Wink camera alarm.""" + + def __init__(self, wink, hass): + """Initialize the Wink alarm.""" + WinkDevice.__init__(self, wink, hass) + + @property + def state(self): + """Return the state of the device.""" + wink_state = self.wink.state() + if wink_state == "away": + state = STATE_ALARM_ARMED_AWAY + elif wink_state == "home": + state = STATE_ALARM_DISARMED + elif wink_state == "night": + state = STATE_ALARM_ARMED_HOME + else: + state = STATE_UNKNOWN + return state + + def alarm_disarm(self, code=None): + """Send disarm command.""" + self.wink.set_mode("home") + + def alarm_arm_home(self, code=None): + """Send arm home command.""" + self.wink.set_mode("night") + + def alarm_arm_away(self, code=None): + """Send arm away command.""" + self.wink.set_mode("away") + + @property + def device_state_attributes(self): + """Return the state attributes.""" + return { + 'private': self.wink.private() + } diff --git a/homeassistant/components/binary_sensor/wink.py b/homeassistant/components/binary_sensor/wink.py index b129b5f24d4..19ecb853536 100644 --- a/homeassistant/components/binary_sensor/wink.py +++ b/homeassistant/components/binary_sensor/wink.py @@ -8,7 +8,6 @@ at https://home-assistant.io/components/binary_sensor.wink/ from homeassistant.components.binary_sensor import BinarySensorDevice from homeassistant.components.sensor.wink import WinkDevice from homeassistant.helpers.entity import Entity -from homeassistant.loader import get_component DEPENDENCIES = ['wink'] @@ -43,6 +42,15 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for hub in pywink.get_hubs(): add_devices([WinkHub(hub, hass)]) + for remote in pywink.get_remotes(): + add_devices([WinkRemote(remote, hass)]) + + for button in pywink.get_buttons(): + add_devices([WinkButton(button, hass)]) + + for gang in pywink.get_gangs(): + add_devices([WinkGang(gang, hass)]) + class WinkBinarySensorDevice(WinkDevice, BinarySensorDevice, Entity): """Representation of a Wink binary sensor.""" @@ -50,33 +58,13 @@ class WinkBinarySensorDevice(WinkDevice, BinarySensorDevice, Entity): def __init__(self, wink, hass): """Initialize the Wink binary sensor.""" super().__init__(wink, hass) - wink = get_component('wink') - self._unit_of_measurement = self.wink.UNIT + self._unit_of_measurement = self.wink.unit() self.capability = self.wink.capability() @property def is_on(self): """Return true if the binary sensor is on.""" - if self.capability == "loudness": - state = self.wink.loudness_boolean() - elif self.capability == "vibration": - state = self.wink.vibration_boolean() - elif self.capability == "brightness": - state = self.wink.brightness_boolean() - elif self.capability == "liquid_detected": - state = self.wink.liquid_boolean() - elif self.capability == "motion": - state = self.wink.motion_boolean() - elif self.capability == "presence": - state = self.wink.presence_boolean() - elif self.capability == "co_detected": - state = self.wink.co_detected_boolean() - elif self.capability == "smoke_detected": - state = self.wink.smoke_detected_boolean() - else: - state = self.wink.state() - - return state + return self.wink.state() @property def sensor_class(self): @@ -91,6 +79,11 @@ class WinkHub(WinkDevice, BinarySensorDevice, Entity): """Initialize the hub sensor.""" WinkDevice.__init__(self, wink, hass) + @property + def is_on(self): + """Return true if the binary sensor is on.""" + return self.wink.state() + @property def device_state_attributes(self): """Return the state attributes.""" @@ -99,7 +92,59 @@ class WinkHub(WinkDevice, BinarySensorDevice, Entity): 'firmware version': self.wink.firmware_version() } + +class WinkRemote(WinkDevice, BinarySensorDevice, Entity): + """Representation of a Wink Lutron Connected bulb remote.""" + + def __init(self, wink, hass): + """Initialize the hub sensor.""" + WinkDevice.__init__(self, wink, hass) + @property def is_on(self): """Return true if the binary sensor is on.""" return self.wink.state() + + @property + def device_state_attributes(self): + """Return the state attributes.""" + return { + 'button_on_pressed': self.wink.button_on_pressed(), + 'button_off_pressed': self.wink.button_off_pressed(), + 'button_up_pressed': self.wink.button_up_pressed(), + 'button_down_pressed': self.wink.button_down_pressed() + } + + +class WinkButton(WinkDevice, BinarySensorDevice, Entity): + """Representation of a Wink Relay button.""" + + def __init(self, wink, hass): + """Initialize the hub sensor.""" + WinkDevice.__init__(self, wink, hass) + + @property + def is_on(self): + """Return true if the binary sensor is on.""" + return self.wink.state() + + @property + def device_state_attributes(self): + """Return the state attributes.""" + return { + 'pressed': self.wink.pressed(), + 'long_pressed': self.wink.long_pressed() + } + + +class WinkGang(WinkDevice, BinarySensorDevice, Entity): + """Representation of a Wink Relay gang.""" + + def __init(self, wink, hass): + """Initialize the gang sensor.""" + WinkDevice.__init__(self, wink, hass) + + @property + def is_on(self): + """Return true if the gang is connected.""" + return self.wink.state() diff --git a/homeassistant/components/light/wink.py b/homeassistant/components/light/wink.py index 1a4556ee46b..dcff4b31a5c 100644 --- a/homeassistant/components/light/wink.py +++ b/homeassistant/components/light/wink.py @@ -23,7 +23,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): """Setup the Wink lights.""" import pywink - add_devices(WinkLight(light, hass) for light in pywink.get_bulbs()) + add_devices(WinkLight(light, hass) for light in pywink.get_light_bulbs()) class WinkLight(WinkDevice, Light): diff --git a/homeassistant/components/sensor/wink.py b/homeassistant/components/sensor/wink.py index 379d9ac43e5..b43952e6330 100644 --- a/homeassistant/components/sensor/wink.py +++ b/homeassistant/components/sensor/wink.py @@ -25,7 +25,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): add_devices([WinkSensorDevice(sensor, hass)]) for eggtray in pywink.get_eggtrays(): - add_devices([WinkEggMinder(eggtray, hass)]) + add_devices([WinkSensorDevice(eggtray, hass)]) for piggy_bank in pywink.get_piggy_banks(): try: @@ -43,53 +43,32 @@ class WinkSensorDevice(WinkDevice, Entity): super().__init__(wink, hass) wink = get_component('wink') self.capability = self.wink.capability() - if self.wink.UNIT == '°': + if self.wink.unit() == '°': self._unit_of_measurement = TEMP_CELSIUS else: - self._unit_of_measurement = self.wink.UNIT + self._unit_of_measurement = self.wink.unit() @property def state(self): """Return the state.""" state = None if self.capability == 'humidity': - if self.wink.humidity_percentage() is not None: - state = round(self.wink.humidity_percentage()) + if self.wink.state() is not None: + state = round(self.wink.state()) elif self.capability == 'temperature': - if self.wink.temperature_float() is not None: - state = round(self.wink.temperature_float(), 1) + if self.wink.state() is not None: + state = round(self.wink.state(), 1) elif self.capability == 'balance': - if self.wink.balance() is not None: - state = round(self.wink.balance() / 100, 2) + if self.wink.state() is not None: + state = round(self.wink.state() / 100, 2) elif self.capability == 'proximity': - if self.wink.proximity_float() is not None: - state = self.wink.proximity_float() + if self.wink.state() is not None: + state = self.wink.state() else: - # A sensor should never get here, anything that does - # will require an update to python-wink - logging.getLogger(__name__).error("Please report this as an issue") - state = None + state = self.wink.state() return state - @property - def available(self): - """True if connection == True.""" - return self.wink.available - @property def unit_of_measurement(self): """Return the unit of measurement of this entity, if any.""" return self._unit_of_measurement - - -class WinkEggMinder(WinkDevice, Entity): - """Representation of a Wink Egg Minder.""" - - def __init__(self, wink, hass): - """Initialize the sensor.""" - WinkDevice.__init__(self, wink, hass) - - @property - def state(self): - """Return the state.""" - return self.wink.state() diff --git a/homeassistant/components/switch/wink.py b/homeassistant/components/switch/wink.py index 22793d81f3f..5df37d87b53 100644 --- a/homeassistant/components/switch/wink.py +++ b/homeassistant/components/switch/wink.py @@ -17,10 +17,12 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for switch in pywink.get_switches(): add_devices([WinkToggleDevice(switch, hass)]) - for switch in pywink.get_powerstrip_outlets(): + for switch in pywink.get_powerstrips(): add_devices([WinkToggleDevice(switch, hass)]) for switch in pywink.get_sirens(): add_devices([WinkToggleDevice(switch, hass)]) + for sprinkler in pywink.get_sprinklers(): + add_devices([WinkToggleDevice(sprinkler, hass)]) class WinkToggleDevice(WinkDevice, ToggleEntity): diff --git a/homeassistant/components/wink.py b/homeassistant/components/wink.py index 39c4c21aaa5..2ef80c8058b 100644 --- a/homeassistant/components/wink.py +++ b/homeassistant/components/wink.py @@ -15,7 +15,7 @@ from homeassistant.const import ( from homeassistant.helpers.entity import Entity import homeassistant.helpers.config_validation as cv -REQUIREMENTS = ['python-wink==0.12.0', 'pubnubsub-handler==0.0.7'] +REQUIREMENTS = ['python-wink==1.0.0', 'pubnubsub-handler==0.0.7'] _LOGGER = logging.getLogger(__name__) @@ -28,14 +28,16 @@ CONF_CLIENT_ID = 'client_id' CONF_CLIENT_SECRET = 'client_secret' CONF_USER_AGENT = 'user_agent' CONF_OATH = 'oath' +CONF_APPSPOT = 'appspot' CONF_DEFINED_BOTH_MSG = 'Remove access token to use oath2.' CONF_MISSING_OATH_MSG = 'Missing oath2 credentials.' +CONF_TOKEN_URL = "https://winkbearertoken.appspot.com/token" CONFIG_SCHEMA = vol.Schema({ DOMAIN: vol.Schema({ - vol.Inclusive(CONF_EMAIL, CONF_OATH, + vol.Inclusive(CONF_EMAIL, CONF_APPSPOT, msg=CONF_MISSING_OATH_MSG): cv.string, - vol.Inclusive(CONF_PASSWORD, CONF_OATH, + vol.Inclusive(CONF_PASSWORD, CONF_APPSPOT, msg=CONF_MISSING_OATH_MSG): cv.string, vol.Inclusive(CONF_CLIENT_ID, CONF_OATH, msg=CONF_MISSING_OATH_MSG): cv.string, @@ -45,19 +47,22 @@ CONFIG_SCHEMA = vol.Schema({ msg=CONF_DEFINED_BOTH_MSG): cv.string, vol.Exclusive(CONF_ACCESS_TOKEN, CONF_OATH, msg=CONF_DEFINED_BOTH_MSG): cv.string, + vol.Exclusive(CONF_ACCESS_TOKEN, CONF_APPSPOT, + msg=CONF_DEFINED_BOTH_MSG): cv.string, vol.Optional(CONF_USER_AGENT, default=None): cv.string }) }, extra=vol.ALLOW_EXTRA) WINK_COMPONENTS = [ 'binary_sensor', 'sensor', 'light', 'switch', 'lock', 'cover', 'climate', - 'fan' + 'fan', 'alarm_control_panel' ] def setup(hass, config): """Set up the Wink component.""" import pywink + import requests from pubnubsubhandler import PubNubSubscriptionHandler user_agent = config[DOMAIN].get(CONF_USER_AGENT) @@ -66,16 +71,24 @@ def setup(hass, config): pywink.set_user_agent(user_agent) access_token = config[DOMAIN].get(CONF_ACCESS_TOKEN) + client_id = config[DOMAIN].get('client_id') if access_token: pywink.set_bearer_token(access_token) - else: + elif client_id: email = config[DOMAIN][CONF_EMAIL] password = config[DOMAIN][CONF_PASSWORD] client_id = config[DOMAIN]['client_id'] client_secret = config[DOMAIN]['client_secret'] pywink.set_wink_credentials(email, password, client_id, client_secret) + else: + email = config[DOMAIN][CONF_EMAIL] + password = config[DOMAIN][CONF_PASSWORD] + payload = {'username': email, 'password': password} + token_response = requests.post(CONF_TOKEN_URL, data=payload) + token = token_response.text.split(':')[1].split()[0].rstrip('