mirror of
https://github.com/home-assistant/core.git
synced 2025-07-22 12:47:08 +00:00
Bug fixes for Wink
This commit is contained in:
parent
c116cb095d
commit
702498ca09
@ -178,7 +178,7 @@ def setup(hass, config):
|
||||
_LOGGER.info("Updating light states")
|
||||
|
||||
for light in lights.values():
|
||||
light.update_ha_state(hass)
|
||||
light.update_ha_state(hass, True)
|
||||
|
||||
update_lights_state(None)
|
||||
|
||||
@ -196,7 +196,7 @@ def setup(hass, config):
|
||||
for light in discovered:
|
||||
if light is not None and light not in lights.values():
|
||||
light.entity_id = util.ensure_unique_string(
|
||||
ENTITY_ID_FORMAT.format(util.slugify(light.get_name())),
|
||||
ENTITY_ID_FORMAT.format(util.slugify(light.name)),
|
||||
lights.keys())
|
||||
|
||||
lights[light.entity_id] = light
|
||||
|
@ -4,8 +4,9 @@ import logging
|
||||
# pylint: disable=no-name-in-module, import-error
|
||||
import homeassistant.external.wink.pywink as pywink
|
||||
|
||||
from homeassistant.helpers import ToggleDevice
|
||||
from homeassistant.const import ATTR_FRIENDLY_NAME, CONF_ACCESS_TOKEN
|
||||
from homeassistant.components.light import ATTR_BRIGHTNESS
|
||||
from homeassistant.components.wink import WinkToggleDevice
|
||||
from homeassistant.const import CONF_ACCESS_TOKEN
|
||||
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
@ -35,29 +36,28 @@ def get_lights():
|
||||
return [WinkLight(light) for light in pywink.get_bulbs()]
|
||||
|
||||
|
||||
class WinkLight(ToggleDevice):
|
||||
class WinkLight(WinkToggleDevice):
|
||||
""" Represents a Wink light """
|
||||
|
||||
def __init__(self, wink):
|
||||
self.wink = wink
|
||||
self.state_attr = {ATTR_FRIENDLY_NAME: wink.name()}
|
||||
|
||||
def get_name(self):
|
||||
""" Returns the name of the light if any. """
|
||||
return self.wink.name()
|
||||
|
||||
# pylint: disable=too-few-public-methods
|
||||
def turn_on(self, **kwargs):
|
||||
""" Turns the light on. """
|
||||
self.wink.setState(True)
|
||||
""" Turns the switch on. """
|
||||
brightness = kwargs.get(ATTR_BRIGHTNESS)
|
||||
|
||||
def turn_off(self):
|
||||
""" Turns the light off. """
|
||||
self.wink.setState(False)
|
||||
if brightness is not None:
|
||||
self.wink.setState(True, brightness / 255)
|
||||
|
||||
def is_on(self):
|
||||
""" True if light is on. """
|
||||
return self.wink.state()
|
||||
else:
|
||||
self.wink.setState(True)
|
||||
|
||||
def get_state_attributes(self):
|
||||
""" Returns optional state attributes. """
|
||||
return self.state_attr
|
||||
@property
|
||||
def state_attributes(self):
|
||||
attr = super().state_attributes
|
||||
|
||||
if self.is_on:
|
||||
brightness = self.wink.brightness()
|
||||
|
||||
if brightness is not None:
|
||||
attr[ATTR_BRIGHTNESS] = int(brightness * 255)
|
||||
|
||||
return attr
|
||||
|
@ -73,7 +73,7 @@ def setup(hass, config):
|
||||
logger.info("Updating switch states")
|
||||
|
||||
for switch in switches.values():
|
||||
switch.update_ha_state(hass)
|
||||
switch.update_ha_state(hass, True)
|
||||
|
||||
update_states(None)
|
||||
|
||||
|
@ -86,7 +86,7 @@ class WemoSwitch(ToggleDevice):
|
||||
@property
|
||||
def is_on(self):
|
||||
""" True if switch is on. """
|
||||
return self.wemo.get_state(True)
|
||||
return self.wemo.get_state()
|
||||
|
||||
def turn_on(self, **kwargs):
|
||||
""" Turns the switch on. """
|
||||
@ -95,3 +95,7 @@ class WemoSwitch(ToggleDevice):
|
||||
def turn_off(self):
|
||||
""" Turns the switch off. """
|
||||
self.wemo.off()
|
||||
|
||||
def update(self):
|
||||
""" Update Wemo state. """
|
||||
self.wemo.get_state(True)
|
||||
|
@ -4,8 +4,8 @@ import logging
|
||||
# pylint: disable=no-name-in-module, import-error
|
||||
import homeassistant.external.wink.pywink as pywink
|
||||
|
||||
from homeassistant.helpers import ToggleDevice
|
||||
from homeassistant.const import ATTR_FRIENDLY_NAME, CONF_ACCESS_TOKEN
|
||||
from homeassistant.components.wink import WinkToggleDevice
|
||||
from homeassistant.const import CONF_ACCESS_TOKEN
|
||||
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
@ -32,32 +32,4 @@ def devices_discovered(hass, config, info):
|
||||
|
||||
def get_switches():
|
||||
""" Returns the Wink switches. """
|
||||
return [WinkSwitch(switch) for switch in pywink.get_switches()]
|
||||
|
||||
|
||||
class WinkSwitch(ToggleDevice):
|
||||
""" represents a WeMo switch within home assistant. """
|
||||
|
||||
def __init__(self, wink):
|
||||
self.wink = wink
|
||||
self.state_attr = {ATTR_FRIENDLY_NAME: wink.name()}
|
||||
|
||||
def get_name(self):
|
||||
""" Returns the name of the switch if any. """
|
||||
return self.wink.name()
|
||||
|
||||
def turn_on(self, **kwargs):
|
||||
""" Turns the switch on. """
|
||||
self.wink.setState(True)
|
||||
|
||||
def turn_off(self):
|
||||
""" Turns the switch off. """
|
||||
self.wink.setState(False)
|
||||
|
||||
def is_on(self):
|
||||
""" True if switch is on. """
|
||||
return self.wink.state()
|
||||
|
||||
def get_state_attributes(self):
|
||||
""" Returns optional state attributes. """
|
||||
return self.state_attr
|
||||
return [WinkToggleDevice(switch) for switch in pywink.get_switches()]
|
||||
|
@ -8,10 +8,10 @@ import homeassistant.external.wink.pywink as pywink
|
||||
|
||||
from homeassistant import bootstrap
|
||||
from homeassistant.loader import get_component
|
||||
from homeassistant.helpers import validate_config
|
||||
from homeassistant.helpers import validate_config, ToggleDevice
|
||||
from homeassistant.const import (
|
||||
EVENT_PLATFORM_DISCOVERED, ATTR_SERVICE, ATTR_DISCOVERED,
|
||||
CONF_ACCESS_TOKEN)
|
||||
EVENT_PLATFORM_DISCOVERED, CONF_ACCESS_TOKEN,
|
||||
ATTR_SERVICE, ATTR_DISCOVERED, ATTR_FRIENDLY_NAME)
|
||||
|
||||
DOMAIN = "wink"
|
||||
DEPENDENCIES = []
|
||||
@ -48,3 +48,44 @@ def setup(hass, config):
|
||||
})
|
||||
|
||||
return True
|
||||
|
||||
|
||||
class WinkToggleDevice(ToggleDevice):
|
||||
""" represents a WeMo switch within home assistant. """
|
||||
|
||||
def __init__(self, wink):
|
||||
self.wink = wink
|
||||
|
||||
@property
|
||||
def unique_id(self):
|
||||
""" Returns the id of this WeMo switch """
|
||||
return "{}.{}".format(self.__class__, self.wink.deviceId())
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
""" Returns the name of the light if any. """
|
||||
return self.wink.name()
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
""" True if light is on. """
|
||||
return self.wink.state()
|
||||
|
||||
@property
|
||||
def state_attributes(self):
|
||||
""" Returns optional state attributes. """
|
||||
return {
|
||||
ATTR_FRIENDLY_NAME: self.wink.name()
|
||||
}
|
||||
|
||||
def turn_on(self, **kwargs):
|
||||
""" Turns the switch on. """
|
||||
self.wink.setState(True)
|
||||
|
||||
def turn_off(self):
|
||||
""" Turns the switch off. """
|
||||
self.wink.setState(False)
|
||||
|
||||
def update(self):
|
||||
""" Update state of the light. """
|
||||
self.wink.wait_till_desired_reached()
|
||||
|
196
homeassistant/external/wink/pywink.py
vendored
196
homeassistant/external/wink/pywink.py
vendored
@ -1,21 +1,16 @@
|
||||
__author__ = 'JOHNMCL'
|
||||
|
||||
import json
|
||||
import time
|
||||
|
||||
import requests
|
||||
|
||||
|
||||
baseUrl = "https://winkapi.quirky.com"
|
||||
|
||||
object_type = "light_bulb"
|
||||
object_type_plural = "light_bulbs"
|
||||
|
||||
bearer_token=""
|
||||
|
||||
headers = {}
|
||||
|
||||
|
||||
class wink_binary_switch():
|
||||
class wink_binary_switch(object):
|
||||
""" represents a wink.py switch
|
||||
json_obj holds the json stat at init (and if there is a refresh it's updated
|
||||
it's the native format for this objects methods
|
||||
@ -85,14 +80,11 @@ class wink_binary_switch():
|
||||
}
|
||||
|
||||
"""
|
||||
jsonState = {}
|
||||
|
||||
|
||||
|
||||
def __init__(self, aJSonObj):
|
||||
def __init__(self, aJSonObj, objectprefix="binary_switches"):
|
||||
self.jsonState = aJSonObj
|
||||
self.objectprefix = "binary_switches"
|
||||
|
||||
self.objectprefix = objectprefix
|
||||
# Tuple (desired state, time)
|
||||
self._last_call = (0, None)
|
||||
|
||||
def __str__(self):
|
||||
return "%s %s %s" % (self.name(), self.deviceId(), self.state())
|
||||
@ -100,13 +92,23 @@ class wink_binary_switch():
|
||||
def __repr__(self):
|
||||
return "<Wink switch %s %s %s>" % (self.name(), self.deviceId(), self.state())
|
||||
|
||||
@property
|
||||
def _last_reading(self):
|
||||
return self.jsonState.get('last_reading') or {}
|
||||
|
||||
def name(self):
|
||||
name = self.jsonState.get('name')
|
||||
return name or "Unknown Name"
|
||||
return self.jsonState.get('name', "Unknown Name")
|
||||
|
||||
def state(self):
|
||||
state = self.jsonState.get('desired_state').get('powered')
|
||||
return state
|
||||
# Optimistic approach to setState:
|
||||
# Within 15 seconds of a call to setState we assume it worked.
|
||||
if self._recent_state_set():
|
||||
return self._last_call[1]
|
||||
|
||||
return self._last_reading.get('powered', False)
|
||||
|
||||
def deviceId(self):
|
||||
return self.jsonState.get('binary_switch_id', self.name())
|
||||
|
||||
def setState(self, state):
|
||||
"""
|
||||
@ -115,20 +117,47 @@ class wink_binary_switch():
|
||||
"""
|
||||
urlString = baseUrl + "/%s/%s" % (self.objectprefix, self.deviceId())
|
||||
values = {"desired_state": {"powered": state}}
|
||||
urlString = baseUrl + "/%s/%s" % (self.objectprefix, self.deviceId())
|
||||
arequest = requests.put(urlString, data=json.dumps(values), headers=headers)
|
||||
self._updateStateFromResponse(arequest.json())
|
||||
|
||||
self._last_call = (time.time(), state)
|
||||
|
||||
def deviceId(self):
|
||||
deviceId = self.jsonState.get('binary_switch_id')
|
||||
return deviceId or "Unknown Device ID"
|
||||
def refresh_state_at_hub(self):
|
||||
"""
|
||||
Tell hub to query latest status from device and upload to Wink.
|
||||
PS: Not sure if this even works..
|
||||
"""
|
||||
urlString = baseUrl + "/%s/%s/refresh" % (self.objectprefix, self.deviceId())
|
||||
requests.get(urlString, headers=headers)
|
||||
|
||||
def updateState(self):
|
||||
""" Update state with latest info from Wink API. """
|
||||
urlString = baseUrl + "/%s/%s" % (self.objectprefix, self.deviceId())
|
||||
arequest = requests.get(urlString, headers=headers)
|
||||
self._updateStateFromResponse(arequest.json())
|
||||
|
||||
def wait_till_desired_reached(self):
|
||||
""" Wait till desired state reached. Max 10s. """
|
||||
if self._recent_state_set():
|
||||
return
|
||||
|
||||
# self.refresh_state_at_hub()
|
||||
tries = 1
|
||||
|
||||
while True:
|
||||
self.updateState()
|
||||
last_read = self._last_reading
|
||||
|
||||
if last_read.get('desired_powered') == last_read.get('powered') \
|
||||
or tries == 5:
|
||||
break
|
||||
|
||||
time.sleep(2)
|
||||
|
||||
tries += 1
|
||||
self.updateState()
|
||||
last_read = self._last_reading
|
||||
|
||||
def _updateStateFromResponse(self, response_json):
|
||||
"""
|
||||
:param response_json: the json obj returned from query
|
||||
@ -136,6 +165,10 @@ class wink_binary_switch():
|
||||
"""
|
||||
self.jsonState = response_json.get('data')
|
||||
|
||||
def _recent_state_set(self):
|
||||
return time.time() - self._last_call[0] < 15
|
||||
|
||||
|
||||
class wink_bulb(wink_binary_switch):
|
||||
""" represents a wink.py bulb
|
||||
json_obj holds the json stat at init (and if there is a refresh it's updated
|
||||
@ -143,77 +176,76 @@ class wink_bulb(wink_binary_switch):
|
||||
and looks like so:
|
||||
|
||||
"light_bulb_id": "33990",
|
||||
"name": "downstaurs lamp",
|
||||
"locale": "en_us",
|
||||
"units":{},
|
||||
"created_at": 1410925804,
|
||||
"hidden_at": null,
|
||||
"capabilities":{},
|
||||
"subscription":{},
|
||||
"triggers":[],
|
||||
"desired_state":{"powered": true, "brightness": 1},
|
||||
"manufacturer_device_model": "lutron_p_pkg1_w_wh_d",
|
||||
"manufacturer_device_id": null,
|
||||
"device_manufacturer": "lutron",
|
||||
"model_name": "Caseta Wireless Dimmer & Pico",
|
||||
"upc_id": "3",
|
||||
"hub_id": "11780",
|
||||
"local_id": "8",
|
||||
"radio_type": "lutron",
|
||||
"linked_service_id": null,
|
||||
"last_reading":{
|
||||
"brightness": 1,
|
||||
"brightness_updated_at": 1417823487.490747,
|
||||
"connection": true,
|
||||
"connection_updated_at": 1417823487.4907365,
|
||||
"powered": true,
|
||||
"powered_updated_at": 1417823487.4907532,
|
||||
"desired_powered": true,
|
||||
"desired_powered_updated_at": 1417823485.054675,
|
||||
"desired_brightness": 1,
|
||||
"desired_brightness_updated_at": 1417409293.2591703
|
||||
},
|
||||
"lat_lng":[38.429962, -122.653715],
|
||||
"location": "",
|
||||
"order": 0
|
||||
"name": "downstaurs lamp",
|
||||
"locale": "en_us",
|
||||
"units":{},
|
||||
"created_at": 1410925804,
|
||||
"hidden_at": null,
|
||||
"capabilities":{},
|
||||
"subscription":{},
|
||||
"triggers":[],
|
||||
"desired_state":{"powered": true, "brightness": 1},
|
||||
"manufacturer_device_model": "lutron_p_pkg1_w_wh_d",
|
||||
"manufacturer_device_id": null,
|
||||
"device_manufacturer": "lutron",
|
||||
"model_name": "Caseta Wireless Dimmer & Pico",
|
||||
"upc_id": "3",
|
||||
"hub_id": "11780",
|
||||
"local_id": "8",
|
||||
"radio_type": "lutron",
|
||||
"linked_service_id": null,
|
||||
"last_reading":{
|
||||
"brightness": 1,
|
||||
"brightness_updated_at": 1417823487.490747,
|
||||
"connection": true,
|
||||
"connection_updated_at": 1417823487.4907365,
|
||||
"powered": true,
|
||||
"powered_updated_at": 1417823487.4907532,
|
||||
"desired_powered": true,
|
||||
"desired_powered_updated_at": 1417823485.054675,
|
||||
"desired_brightness": 1,
|
||||
"desired_brightness_updated_at": 1417409293.2591703
|
||||
},
|
||||
"lat_lng":[38.429962, -122.653715],
|
||||
"location": "",
|
||||
"order": 0
|
||||
|
||||
"""
|
||||
jsonState = {}
|
||||
|
||||
def __init__(self, ajsonobj):
|
||||
self.jsonState = ajsonobj
|
||||
self.objectprefix = "light_bulbs"
|
||||
super().__init__(ajsonobj, "light_bulbs")
|
||||
|
||||
def __str__(self):
|
||||
return "%s %s %s" % (self.name(), self.deviceId(), self.state())
|
||||
def deviceId(self):
|
||||
return self.jsonState.get('light_bulb_id', self.name())
|
||||
|
||||
def __repr__(self):
|
||||
return "<Wink Bulb %s %s %s>" % (self.name(), self.deviceId(), self.state())
|
||||
def brightness(self):
|
||||
return self._last_reading.get('brightness')
|
||||
|
||||
def name(self):
|
||||
name = self.jsonState.get('name')
|
||||
return name or "Unknown Name"
|
||||
|
||||
def state(self):
|
||||
state = self.jsonState.get('desired_state').get('powered')
|
||||
return state
|
||||
|
||||
def setState(self, state):
|
||||
def setState(self, state, brightness=None):
|
||||
"""
|
||||
:param state: a boolean of true (on) or false ('off')
|
||||
:return: nothing
|
||||
"""
|
||||
urlString = baseUrl + "/light_bulbs/%s" % self.deviceId()
|
||||
values = {"desired_state": {"desired_powered": state, "powered": state}}
|
||||
values = {
|
||||
"desired_state": {
|
||||
"powered": state
|
||||
}
|
||||
}
|
||||
|
||||
if brightness is not None:
|
||||
values["desired_state"]["brightness"] = brightness
|
||||
|
||||
urlString = baseUrl + "/light_bulbs/%s" % self.deviceId()
|
||||
arequest = requests.put(urlString, data=json.dumps(values), headers=headers)
|
||||
self._updateStateFromResponse(arequest.json())
|
||||
|
||||
self.updateState()
|
||||
self._last_call = (time.time(), state)
|
||||
|
||||
|
||||
def deviceId(self):
|
||||
deviceId = self.jsonState.get('light_bulb_id')
|
||||
return deviceId or "Unknown Device ID"
|
||||
def __repr__(self):
|
||||
return "<Wink Bulb %s %s %s>" % (
|
||||
self.name(), self.deviceId(), self.state())
|
||||
|
||||
|
||||
def get_bulbs_and_switches():
|
||||
@ -243,7 +275,7 @@ def get_bulbs():
|
||||
switches = []
|
||||
for item in items:
|
||||
id = item.get('light_bulb_id')
|
||||
if id != None:
|
||||
if id is not None:
|
||||
switches.append(wink_bulb(item))
|
||||
|
||||
return switches
|
||||
@ -258,15 +290,19 @@ def get_switches():
|
||||
switches = []
|
||||
for item in items:
|
||||
id = item.get('binary_switch_id')
|
||||
if id != None:
|
||||
if id is not None:
|
||||
switches.append(wink_binary_switch(item))
|
||||
|
||||
return switches
|
||||
|
||||
|
||||
def set_bearer_token(token):
|
||||
global headers
|
||||
bearer_token=token
|
||||
headers={"Content-Type": "application/json", "Authorization": "Bearer {}".format(token)}
|
||||
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": "Bearer {}".format(token)
|
||||
}
|
||||
|
||||
if __name__ == "__main__":
|
||||
sw = get_bulbs()
|
||||
|
Loading…
x
Reference in New Issue
Block a user