Support for python-wink 1.0.0 (#5534)

This commit is contained in:
William Scanlon 2017-01-25 00:11:18 -05:00 committed by Paulus Schoutsen
parent 794852f76f
commit 47bbfc309c
7 changed files with 177 additions and 74 deletions

View file

@ -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()
}

View file

@ -8,7 +8,6 @@ at https://home-assistant.io/components/binary_sensor.wink/
from homeassistant.components.binary_sensor import BinarySensorDevice from homeassistant.components.binary_sensor import BinarySensorDevice
from homeassistant.components.sensor.wink import WinkDevice from homeassistant.components.sensor.wink import WinkDevice
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
from homeassistant.loader import get_component
DEPENDENCIES = ['wink'] DEPENDENCIES = ['wink']
@ -43,6 +42,15 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
for hub in pywink.get_hubs(): for hub in pywink.get_hubs():
add_devices([WinkHub(hub, hass)]) 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): class WinkBinarySensorDevice(WinkDevice, BinarySensorDevice, Entity):
"""Representation of a Wink binary sensor.""" """Representation of a Wink binary sensor."""
@ -50,33 +58,13 @@ class WinkBinarySensorDevice(WinkDevice, BinarySensorDevice, Entity):
def __init__(self, wink, hass): def __init__(self, wink, hass):
"""Initialize the Wink binary sensor.""" """Initialize the Wink binary sensor."""
super().__init__(wink, hass) 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() self.capability = self.wink.capability()
@property @property
def is_on(self): def is_on(self):
"""Return true if the binary sensor is on.""" """Return true if the binary sensor is on."""
if self.capability == "loudness": return self.wink.state()
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
@property @property
def sensor_class(self): def sensor_class(self):
@ -91,6 +79,11 @@ class WinkHub(WinkDevice, BinarySensorDevice, Entity):
"""Initialize the hub sensor.""" """Initialize the hub sensor."""
WinkDevice.__init__(self, wink, hass) WinkDevice.__init__(self, wink, hass)
@property
def is_on(self):
"""Return true if the binary sensor is on."""
return self.wink.state()
@property @property
def device_state_attributes(self): def device_state_attributes(self):
"""Return the state attributes.""" """Return the state attributes."""
@ -99,7 +92,59 @@ class WinkHub(WinkDevice, BinarySensorDevice, Entity):
'firmware version': self.wink.firmware_version() '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 @property
def is_on(self): def is_on(self):
"""Return true if the binary sensor is on.""" """Return true if the binary sensor is on."""
return self.wink.state() 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()

View file

@ -23,7 +23,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
"""Setup the Wink lights.""" """Setup the Wink lights."""
import pywink 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): class WinkLight(WinkDevice, Light):

View file

@ -25,7 +25,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
add_devices([WinkSensorDevice(sensor, hass)]) add_devices([WinkSensorDevice(sensor, hass)])
for eggtray in pywink.get_eggtrays(): for eggtray in pywink.get_eggtrays():
add_devices([WinkEggMinder(eggtray, hass)]) add_devices([WinkSensorDevice(eggtray, hass)])
for piggy_bank in pywink.get_piggy_banks(): for piggy_bank in pywink.get_piggy_banks():
try: try:
@ -43,53 +43,32 @@ class WinkSensorDevice(WinkDevice, Entity):
super().__init__(wink, hass) super().__init__(wink, hass)
wink = get_component('wink') wink = get_component('wink')
self.capability = self.wink.capability() self.capability = self.wink.capability()
if self.wink.UNIT == '°': if self.wink.unit() == '°':
self._unit_of_measurement = TEMP_CELSIUS self._unit_of_measurement = TEMP_CELSIUS
else: else:
self._unit_of_measurement = self.wink.UNIT self._unit_of_measurement = self.wink.unit()
@property @property
def state(self): def state(self):
"""Return the state.""" """Return the state."""
state = None state = None
if self.capability == 'humidity': if self.capability == 'humidity':
if self.wink.humidity_percentage() is not None: if self.wink.state() is not None:
state = round(self.wink.humidity_percentage()) state = round(self.wink.state())
elif self.capability == 'temperature': elif self.capability == 'temperature':
if self.wink.temperature_float() is not None: if self.wink.state() is not None:
state = round(self.wink.temperature_float(), 1) state = round(self.wink.state(), 1)
elif self.capability == 'balance': elif self.capability == 'balance':
if self.wink.balance() is not None: if self.wink.state() is not None:
state = round(self.wink.balance() / 100, 2) state = round(self.wink.state() / 100, 2)
elif self.capability == 'proximity': elif self.capability == 'proximity':
if self.wink.proximity_float() is not None: if self.wink.state() is not None:
state = self.wink.proximity_float() state = self.wink.state()
else: else:
# A sensor should never get here, anything that does state = self.wink.state()
# will require an update to python-wink
logging.getLogger(__name__).error("Please report this as an issue")
state = None
return state return state
@property
def available(self):
"""True if connection == True."""
return self.wink.available
@property @property
def unit_of_measurement(self): def unit_of_measurement(self):
"""Return the unit of measurement of this entity, if any.""" """Return the unit of measurement of this entity, if any."""
return self._unit_of_measurement 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()

View file

@ -17,10 +17,12 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
for switch in pywink.get_switches(): for switch in pywink.get_switches():
add_devices([WinkToggleDevice(switch, hass)]) add_devices([WinkToggleDevice(switch, hass)])
for switch in pywink.get_powerstrip_outlets(): for switch in pywink.get_powerstrips():
add_devices([WinkToggleDevice(switch, hass)]) add_devices([WinkToggleDevice(switch, hass)])
for switch in pywink.get_sirens(): for switch in pywink.get_sirens():
add_devices([WinkToggleDevice(switch, hass)]) add_devices([WinkToggleDevice(switch, hass)])
for sprinkler in pywink.get_sprinklers():
add_devices([WinkToggleDevice(sprinkler, hass)])
class WinkToggleDevice(WinkDevice, ToggleEntity): class WinkToggleDevice(WinkDevice, ToggleEntity):

View file

@ -15,7 +15,7 @@ from homeassistant.const import (
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
import homeassistant.helpers.config_validation as cv 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__) _LOGGER = logging.getLogger(__name__)
@ -28,14 +28,16 @@ CONF_CLIENT_ID = 'client_id'
CONF_CLIENT_SECRET = 'client_secret' CONF_CLIENT_SECRET = 'client_secret'
CONF_USER_AGENT = 'user_agent' CONF_USER_AGENT = 'user_agent'
CONF_OATH = 'oath' CONF_OATH = 'oath'
CONF_APPSPOT = 'appspot'
CONF_DEFINED_BOTH_MSG = 'Remove access token to use oath2.' CONF_DEFINED_BOTH_MSG = 'Remove access token to use oath2.'
CONF_MISSING_OATH_MSG = 'Missing oath2 credentials.' CONF_MISSING_OATH_MSG = 'Missing oath2 credentials.'
CONF_TOKEN_URL = "https://winkbearertoken.appspot.com/token"
CONFIG_SCHEMA = vol.Schema({ CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({ DOMAIN: vol.Schema({
vol.Inclusive(CONF_EMAIL, CONF_OATH, vol.Inclusive(CONF_EMAIL, CONF_APPSPOT,
msg=CONF_MISSING_OATH_MSG): cv.string, 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, msg=CONF_MISSING_OATH_MSG): cv.string,
vol.Inclusive(CONF_CLIENT_ID, CONF_OATH, vol.Inclusive(CONF_CLIENT_ID, CONF_OATH,
msg=CONF_MISSING_OATH_MSG): cv.string, msg=CONF_MISSING_OATH_MSG): cv.string,
@ -45,19 +47,22 @@ CONFIG_SCHEMA = vol.Schema({
msg=CONF_DEFINED_BOTH_MSG): cv.string, msg=CONF_DEFINED_BOTH_MSG): cv.string,
vol.Exclusive(CONF_ACCESS_TOKEN, CONF_OATH, vol.Exclusive(CONF_ACCESS_TOKEN, CONF_OATH,
msg=CONF_DEFINED_BOTH_MSG): cv.string, 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 vol.Optional(CONF_USER_AGENT, default=None): cv.string
}) })
}, extra=vol.ALLOW_EXTRA) }, extra=vol.ALLOW_EXTRA)
WINK_COMPONENTS = [ WINK_COMPONENTS = [
'binary_sensor', 'sensor', 'light', 'switch', 'lock', 'cover', 'climate', 'binary_sensor', 'sensor', 'light', 'switch', 'lock', 'cover', 'climate',
'fan' 'fan', 'alarm_control_panel'
] ]
def setup(hass, config): def setup(hass, config):
"""Set up the Wink component.""" """Set up the Wink component."""
import pywink import pywink
import requests
from pubnubsubhandler import PubNubSubscriptionHandler from pubnubsubhandler import PubNubSubscriptionHandler
user_agent = config[DOMAIN].get(CONF_USER_AGENT) user_agent = config[DOMAIN].get(CONF_USER_AGENT)
@ -66,16 +71,24 @@ def setup(hass, config):
pywink.set_user_agent(user_agent) pywink.set_user_agent(user_agent)
access_token = config[DOMAIN].get(CONF_ACCESS_TOKEN) access_token = config[DOMAIN].get(CONF_ACCESS_TOKEN)
client_id = config[DOMAIN].get('client_id')
if access_token: if access_token:
pywink.set_bearer_token(access_token) pywink.set_bearer_token(access_token)
else: elif client_id:
email = config[DOMAIN][CONF_EMAIL] email = config[DOMAIN][CONF_EMAIL]
password = config[DOMAIN][CONF_PASSWORD] password = config[DOMAIN][CONF_PASSWORD]
client_id = config[DOMAIN]['client_id'] client_id = config[DOMAIN]['client_id']
client_secret = config[DOMAIN]['client_secret'] client_secret = config[DOMAIN]['client_secret']
pywink.set_wink_credentials(email, password, client_id, pywink.set_wink_credentials(email, password, client_id,
client_secret) 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('<br')
pywink.set_bearer_token(token)
hass.data[DOMAIN] = {} hass.data[DOMAIN] = {}
hass.data[DOMAIN]['entities'] = [] hass.data[DOMAIN]['entities'] = []
@ -112,8 +125,9 @@ class WinkDevice(Entity):
def __init__(self, wink, hass): def __init__(self, wink, hass):
"""Initialize the Wink device.""" """Initialize the Wink device."""
self.hass = hass
self.wink = wink self.wink = wink
self._battery = self.wink.battery_level self._battery = self.wink.battery_level()
hass.data[DOMAIN]['pubnub'].add_subscription( hass.data[DOMAIN]['pubnub'].add_subscription(
self.wink.pubnub_channel, self._pubnub_update) self.wink.pubnub_channel, self._pubnub_update)
hass.data[DOMAIN]['entities'].append(self) hass.data[DOMAIN]['entities'].append(self)
@ -132,11 +146,6 @@ class WinkDevice(Entity):
"polling API for current state", self.name) "polling API for current state", self.name)
self.update_ha_state(True) self.update_ha_state(True)
@property
def unique_id(self):
"""Return the ID of this Wink device."""
return '{}.{}'.format(self.__class__, self.wink.device_id())
@property @property
def name(self): def name(self):
"""Return the name of the device.""" """Return the name of the device."""
@ -145,7 +154,7 @@ class WinkDevice(Entity):
@property @property
def available(self): def available(self):
"""True if connection == True.""" """True if connection == True."""
return self.wink.available return self.wink.available()
def update(self): def update(self):
"""Update state of the device.""" """Update state of the device."""
@ -167,5 +176,5 @@ class WinkDevice(Entity):
@property @property
def _battery_level(self): def _battery_level(self):
"""Return the battery level.""" """Return the battery level."""
if self.wink.battery_level is not None: if self.wink.battery_level() is not None:
return self.wink.battery_level * 100 return self.wink.battery_level() * 100

View file

@ -369,7 +369,7 @@ proliphix==0.4.1
psutil==5.0.1 psutil==5.0.1
# homeassistant.components.wink # homeassistant.components.wink
pubnubsub-handler==0.0.7 pubnubsub-handler==1.0.0
# homeassistant.components.notify.pushbullet # homeassistant.components.notify.pushbullet
pushbullet.py==0.10.0 pushbullet.py==0.10.0
@ -528,7 +528,7 @@ python-twitch==1.3.0
python-vlc==1.1.2 python-vlc==1.1.2
# homeassistant.components.wink # homeassistant.components.wink
python-wink==0.12.0 python-wink==1.0.0
# homeassistant.components.device_tracker.trackr # homeassistant.components.device_tracker.trackr
pytrackr==0.0.5 pytrackr==0.0.5