Merge branch 'dev'

* dev:
  Exclude external libraries from code coverage
  Bug fixes for Wink
  Better positioning of dialogs
  Added error handling in frontend debug forms
  Integrate add worker to bootstrap.setup_component
  Conditionally show widgets on light more info
  Rename the edit state button in more info to debug
  Expect devices to have no name
This commit is contained in:
Paulus Schoutsen 2015-01-15 21:39:43 -08:00
commit 93f93aff93
23 changed files with 356 additions and 223 deletions

View File

@ -7,6 +7,6 @@ install:
script:
- flake8 homeassistant --exclude bower_components,external
- pylint homeassistant
- coverage run --source=homeassistant -m unittest discover tests
- coverage run --source=homeassistant --omit "homeassistant/external/*" -m unittest discover tests
after_success:
- coveralls

View File

@ -17,7 +17,7 @@ from collections import defaultdict
import homeassistant
import homeassistant.loader as loader
import homeassistant.components as core_components
import homeassistant.components.group as group
_LOGGER = logging.getLogger(__name__)
@ -35,6 +35,11 @@ def setup_component(hass, domain, config=None):
_LOGGER.info("component %s initialized", domain)
# Assumption: if a component does not depend on groups
# it communicates with devices
if group.DOMAIN not in component.DEPENDENCIES:
hass.pool.add_worker()
return True
else:
@ -75,18 +80,8 @@ def from_config_dict(config, hass=None):
_LOGGER.info("Home Assistant core initialized")
# Setup the components
# We assume that all components that load before the group component loads
# are components that poll devices. As their tasks are IO based, we will
# add an extra worker for each of them.
add_worker = True
for domain in loader.load_order_components(components):
if setup_component(hass, domain, config):
add_worker = add_worker and domain != "group"
if add_worker:
hass.pool.add_worker()
setup_component(hass, domain, config)
return hass

View File

@ -68,8 +68,7 @@ def setup(hass, config):
logger.info("Found new service: %s %s", service, info)
if component and component not in hass.components:
if bootstrap.setup_component(hass, component, config):
hass.pool.add_worker()
bootstrap.setup_component(hass, component, config)
hass.bus.fire(EVENT_PLATFORM_DISCOVERED, {
ATTR_SERVICE: service,

View File

@ -1,2 +1,2 @@
""" DO NOT MODIFY. Auto-generated by build_frontend script """
VERSION = "b32ea78a1157b29555410384fe251dc9"
VERSION = "a82c6e4bf6b91042a6e891d46464275d"

File diff suppressed because one or more lines are too long

View File

@ -26,7 +26,7 @@
Polymer({
cardClicked: function() {
this.api.showStateCardDialog(this.stateObj.entity_id);
this.api.showmoreInfoDialog(this.stateObj.entity_id);
},
});

View File

@ -10,7 +10,11 @@
<polymer-element name="event-fire-dialog" attributes="api">
<template>
<ha-action-dialog id="dialog" heading="Fire Event" class='two-column'>
<ha-action-dialog
id="dialog"
heading="Fire Event"
class='two-column'
closeSelector='[dismissive]'>
<div layout horizontal>
<div class='ha-form'>
@ -51,7 +55,9 @@ Polymer({
this.setEventType(eventType);
this.setEventData(eventData);
this.$.dialog.toggle();
this.job('showDialogAfterRender', function() {
this.$.dialog.toggle();
}.bind(this));
},
setEventType: function(eventType) {
@ -68,15 +74,15 @@ Polymer({
},
clickFireEvent: function() {
var data;
if(this.$.inputData.value !== "") {
data = JSON.parse(this.$.inputData.value);
} else {
data = {};
try {
this.api.fire_event(
this.$.inputType.value,
this.$.inputData.value ? JSON.parse(this.$.inputData.value) : {});
this.$.dialog.close();
} catch (err) {
alert("Error parsing JSON: " + err);
}
this.api.fire_event(this.$.inputType.value, data);
}
});
</script>

View File

@ -13,12 +13,6 @@
layered: true,
backdrop: true,
transition: 'core-transition-bottom',
domReady: function() {
this.addEventListener('core-overlay-open-completed', function() {
this.resizeHandler();
}.bind(this));
},
});
</script>
</polymer-element>

View File

@ -4,7 +4,7 @@
<link rel="import" href="../cards/state-card-content.html">
<link rel="import" href="../more-infos/more-info-content.html">
<polymer-element name="state-card-dialog" attributes="api">
<polymer-element name="more-info-dialog" attributes="api">
<template>
<ha-action-dialog id="dialog">
@ -20,8 +20,8 @@
<more-info-content stateObj="{{stateObj}}" api="{{api}}"></more-info-content>
</div>
<paper-button dismissive>Dismiss</paper-button>
<paper-button affirmative on-click={{editClicked}}>Edit State</paper-button>
<paper-button dismissive on-click={{editClicked}}>Debug</paper-button>
<paper-button affirmative>Dismiss</paper-button>
</ha-action-dialog>
</template>
@ -29,15 +29,29 @@
Polymer({
stateObj: {},
// domReady: function() {
// this.$.dialog.addEventListener('core-overlay-open-completed', function() {
// this.$.dialog.resizeHandler();
// }.bind(this));
// },
observe: {
'stateObj.attributes': 'reposition'
},
/**
* Whenever the attributes change, the more info component can
* hide or show elements. We will reposition the dialog.
* DISABLED FOR NOW - BAD UX
*/
reposition: function(oldVal, newVal) {
// Only resize if already open
if(this.$.dialog.opened) {
this.job('resizeAfterLayoutChange', function() {
this.$.dialog.resizeHandler();
}.bind(this), 1000);
}
},
show: function(stateObj) {
this.stateObj = stateObj;
this.$.dialog.toggle();
this.job('showDialogAfterRender', function() {
this.$.dialog.toggle();
}.bind(this));
},
editClicked: function(ev) {

View File

@ -10,7 +10,10 @@
<polymer-element name="service-call-dialog" attributes="api">
<template>
<ha-action-dialog id="dialog" heading="Call Service">
<ha-action-dialog
id="dialog"
heading="Call Service"
closeSelector='[dismissive]'>
<core-style ref='ha-dialog'></core-style>
@ -45,14 +48,16 @@
Polymer({
ready: function() {
// to ensure callback methods work..
this.serviceSelected = this.serviceSelected.bind(this)
this.serviceSelected = this.serviceSelected.bind(this);
},
show: function(domain, service, serviceData) {
this.setService(domain, service);
this.$.inputData.value = serviceData;
// this.$.inputDataWrapper.update();
this.$.dialog.toggle();
this.job('showDialogAfterRender', function() {
this.$.dialog.toggle();
}.bind(this));
},
setService: function(domain, service) {
@ -65,16 +70,17 @@ Polymer({
},
clickCallService: function() {
var data;
if(this.$.inputData.value != "") {
data = JSON.parse(this.$.inputData.value);
}
try {
this.api.call_service(
this.$.inputDomain.value,
this.$.inputService.value,
data);
this.$.inputData.value ? JSON.parse(this.$.inputData.value) : {});
this.$.dialog.close();
} catch (err) {
alert("Error parsing JSON: " + err);
}
}
});
</script>

View File

@ -9,10 +9,18 @@
<polymer-element name="state-set-dialog" attributes="api">
<template>
<ha-action-dialog id="dialog" heading="Set State">
<ha-action-dialog
id="dialog"
heading="Set State"
closeSelector='[dismissive]'>
<core-style ref='ha-dialog'></core-style>
<p>
This dialog will update the representation of the device within Home Assistant.<br />
This will not communicate with the actual device.
</p>
<div layout horizontal>
<div class='ha-form'>
<paper-input id="inputEntityID" label="Entity ID" floatingLabel="true" autofocus required></paper-input>
@ -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);
}
}
});
</script>

View File

@ -6,7 +6,7 @@
<link rel="import" href="dialogs/event-fire-dialog.html">
<link rel="import" href="dialogs/service-call-dialog.html">
<link rel="import" href="dialogs/state-set-dialog.html">
<link rel="import" href="dialogs/state-card-dialog.html">
<link rel="import" href="dialogs/more-info-dialog.html">
<script>
var ha = {};
@ -36,7 +36,7 @@
<event-fire-dialog id="eventDialog" api={{api}}></event-fire-dialog>
<service-call-dialog id="serviceDialog" api={{api}}></service-call-dialog>
<state-set-dialog id="stateSetDialog" api={{api}}></state-set-dialog>
<state-card-dialog id="stateCardDialog" api={{api}}></state-card-dialog>
<more-info-dialog id="moreInfoDialog" api={{api}}></more-info-dialog>
</template>
<script>
var domainsWithCard = ['thermostat'];
@ -395,8 +395,8 @@
},
// show dialogs
showStateCardDialog: function(entityId) {
this.$.stateCardDialog.show(this.getState(entityId));
showmoreInfoDialog: function(entityId) {
this.$.moreInfoDialog.show(this.getState(entityId));
},
showEditStateDialog: function(entityId) {

View File

@ -13,10 +13,16 @@
}
</style>
<div id='moreInfo'></div>
<div id='moreInfo' class='{{classNames}}'></div>
</template>
<script>
Polymer({
classNames: '',
observe: {
'stateObj.attributes': 'stateAttributesChanged',
},
stateObjChanged: function() {
while (this.$.moreInfo.lastChild) {
this.$.moreInfo.removeChild(this.$.moreInfo.lastChild);
@ -25,8 +31,14 @@ Polymer({
var moreInfo = document.createElement("more-info-" + this.stateObj.moreInfoType);
moreInfo.api = this.api;
moreInfo.stateObj = this.stateObj;
this.$.moreInfo.appendChild(moreInfo);
}
this.$.moreInfo.appendChild(moreInfo);
},
stateAttributesChanged: function(oldVal, newVal) {
this.classNames = Object.keys(newVal).map(
function(key) { return "has-" + key; }).join(' ');
},
});
</script>
</polymer-element>

View File

@ -8,6 +8,10 @@
<style>
.brightness {
margin-bottom: 8px;
max-height: 0px;
overflow: hidden;
transition: max-height .5s ease-in;
}
.brightness paper-slider::shadow #sliderKnobInner,
@ -19,16 +23,32 @@
display: block;
width: 350px;
margin: 0 auto;
max-height: 0px;
overflow: hidden;
transition: max-height .5s ease-in .3s;
}
:host-context(.has-brightness) .brightness {
max-height: 500px;
}
:host-context(.has-xy_color) color-picker {
max-height: 500px;
}
</style>
<div>
<div center horizontal layout class='brightness'>
<div>Brightness</div>
<paper-slider
max="255" flex id='brightness'
on-core-change="{{brightnessSliderChanged}}">
</paper-slider>
<div class='brightness'>
<div center horizontal layout>
<div>Brightness</div>
<paper-slider
max="255" flex id='brightness'
on-core-change="{{brightnessSliderChanged}}">
</paper-slider>
</div>
</div>
<color-picker id="colorpicker" width="350" height="200">
</color-picker>
</div>
@ -48,7 +68,7 @@ Polymer({
brightnessChanged: function(oldVal, newVal) {
this.ignoreNextBrightnessEvent = true;
this.$.brightness.value = newVal;
this.$.brightness.value = newVal;
},
domReady: function() {

View File

@ -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 {

View File

@ -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

View File

@ -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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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)),