@@ -52,7 +60,9 @@ Polymer({
this.setState(state);
this.setStateData(stateData);
- this.$.dialog.toggle();
+ this.job('showDialogAfterRender', function() {
+ this.$.dialog.toggle();
+ }.bind(this));
},
setEntityId: function(entityId) {
@@ -77,12 +87,18 @@ Polymer({
this.setStateData(state.attributes);
},
- clickSetState: function() {
- this.api.set_state(
- this.$.inputEntityID.value,
- this.$.inputState.value,
- JSON.parse(this.$.inputData.value)
+ clickSetState: function(ev) {
+ try {
+ this.api.set_state(
+ this.$.inputEntityID.value,
+ this.$.inputState.value,
+ this.$.inputData.value ? JSON.parse(this.$.inputData.value) : {}
);
+
+ this.$.dialog.close();
+ } catch (err) {
+ alert("Error parsing JSON: " + err);
+ }
}
});
diff --git a/homeassistant/components/http/www_static/polymer/home-assistant-api.html b/homeassistant/components/http/www_static/polymer/home-assistant-api.html
index d63e16bc40f..5b8be54a1d8 100644
--- a/homeassistant/components/http/www_static/polymer/home-assistant-api.html
+++ b/homeassistant/components/http/www_static/polymer/home-assistant-api.html
@@ -6,7 +6,7 @@
diff --git a/homeassistant/components/http/www_static/polymer/more-infos/more-info-light.html b/homeassistant/components/http/www_static/polymer/more-infos/more-info-light.html
index 6bdf858b10a..7bc28cf5a26 100644
--- a/homeassistant/components/http/www_static/polymer/more-infos/more-info-light.html
+++ b/homeassistant/components/http/www_static/polymer/more-infos/more-info-light.html
@@ -8,6 +8,10 @@
-
@@ -48,7 +68,7 @@ Polymer({
brightnessChanged: function(oldVal, newVal) {
this.ignoreNextBrightnessEvent = true;
- this.$.brightness.value = newVal;
+ this.$.brightness.value = newVal;
},
domReady: function() {
diff --git a/homeassistant/components/http/www_static/polymer/resources/home-assistant-style.html b/homeassistant/components/http/www_static/polymer/resources/home-assistant-style.html
index 1ba3b9b1bc5..7925a711b95 100644
--- a/homeassistant/components/http/www_static/polymer/resources/home-assistant-style.html
+++ b/homeassistant/components/http/www_static/polymer/resources/home-assistant-style.html
@@ -8,6 +8,14 @@
font-family: RobotoDraft, 'Helvetica Neue', Helvetica, Arial;
min-width: 350px;
+ max-width: 700px;
+
+ /* First two are from core-transition-bottom */
+ transition:
+ transform 0.2s ease-in-out,
+ opacity 0.2s ease-in,
+ top .3s,
+ left .3s !important;
}
:host .sidebar {
diff --git a/homeassistant/components/light/__init__.py b/homeassistant/components/light/__init__.py
index b169c0d44d5..75a5f3767da 100644
--- a/homeassistant/components/light/__init__.py
+++ b/homeassistant/components/light/__init__.py
@@ -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
diff --git a/homeassistant/components/light/wink.py b/homeassistant/components/light/wink.py
index 061ff06b7f8..ebfdc44fff1 100644
--- a/homeassistant/components/light/wink.py
+++ b/homeassistant/components/light/wink.py
@@ -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
diff --git a/homeassistant/components/switch/__init__.py b/homeassistant/components/switch/__init__.py
index 13bfa075932..5d772f9444a 100644
--- a/homeassistant/components/switch/__init__.py
+++ b/homeassistant/components/switch/__init__.py
@@ -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)
diff --git a/homeassistant/components/switch/wemo.py b/homeassistant/components/switch/wemo.py
index bb6290526f7..e6dce192e22 100644
--- a/homeassistant/components/switch/wemo.py
+++ b/homeassistant/components/switch/wemo.py
@@ -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)
diff --git a/homeassistant/components/switch/wink.py b/homeassistant/components/switch/wink.py
index edc404781fe..58faed9a2a5 100644
--- a/homeassistant/components/switch/wink.py
+++ b/homeassistant/components/switch/wink.py
@@ -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()]
diff --git a/homeassistant/components/wink.py b/homeassistant/components/wink.py
index ab660281e0e..d049d1ecc26 100644
--- a/homeassistant/components/wink.py
+++ b/homeassistant/components/wink.py
@@ -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 = []
@@ -39,9 +39,7 @@ def setup(hass, config):
# Ensure component is loaded
if component.DOMAIN not in hass.components:
- # Add a worker on succesfull setup
- if bootstrap.setup_component(hass, component.DOMAIN, config):
- hass.pool.add_worker()
+ bootstrap.setup_component(hass, component.DOMAIN, config)
# Fire discovery event
hass.bus.fire(EVENT_PLATFORM_DISCOVERED, {
@@ -50,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()
diff --git a/homeassistant/external/wink/pywink.py b/homeassistant/external/wink/pywink.py
index 3131873a9e2..7d44050f55c 100644
--- a/homeassistant/external/wink/pywink.py
+++ b/homeassistant/external/wink/pywink.py
@@ -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 "
" % (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 "" % (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 "" % (
+ 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()
diff --git a/homeassistant/helpers.py b/homeassistant/helpers.py
index 70a085056a2..e29cf03ed42 100644
--- a/homeassistant/helpers.py
+++ b/homeassistant/helpers.py
@@ -153,11 +153,12 @@ def platform_devices_from_config(config, domain, hass,
no_name_count = 0
for device in devices:
- name = device.name
+ # Get the name or set to default if none given
+ name = device.name or DEVICE_DEFAULT_NAME
if name == DEVICE_DEFAULT_NAME:
no_name_count += 1
- name = "{} #{}".format(domain, no_name_count)
+ name = "{} {}".format(domain, no_name_count)
entity_id = ensure_unique_string(
entity_id_format.format(slugify(name)),