mirror of
https://github.com/home-assistant/core.git
synced 2025-07-17 10:17:09 +00:00
Added support for entity pictures
This commit is contained in:
parent
f9462613f5
commit
1bab576be7
@ -27,6 +27,9 @@ ATTR_ENTITY_ID = 'entity_id'
|
|||||||
# String with a friendly name for the entity
|
# String with a friendly name for the entity
|
||||||
ATTR_FRIENDLY_NAME = "friendly_name"
|
ATTR_FRIENDLY_NAME = "friendly_name"
|
||||||
|
|
||||||
|
# A picture to represent entity
|
||||||
|
ATTR_ENTITY_PICTURE = "entity_picture"
|
||||||
|
|
||||||
STATE_ON = 'on'
|
STATE_ON = 'on'
|
||||||
STATE_OFF = 'off'
|
STATE_OFF = 'off'
|
||||||
STATE_HOME = 'home'
|
STATE_HOME = 'home'
|
||||||
|
@ -9,8 +9,8 @@ import random
|
|||||||
import homeassistant as ha
|
import homeassistant as ha
|
||||||
import homeassistant.components.group as group
|
import homeassistant.components.group as group
|
||||||
from homeassistant.components import (SERVICE_TURN_ON, SERVICE_TURN_OFF,
|
from homeassistant.components import (SERVICE_TURN_ON, SERVICE_TURN_OFF,
|
||||||
STATE_ON, STATE_OFF, get_component,
|
STATE_ON, STATE_OFF, ATTR_ENTITY_PICTURE,
|
||||||
extract_entity_ids)
|
get_component, extract_entity_ids)
|
||||||
from homeassistant.components.light import (ATTR_XY_COLOR, ATTR_BRIGHTNESS,
|
from homeassistant.components.light import (ATTR_XY_COLOR, ATTR_BRIGHTNESS,
|
||||||
GROUP_NAME_ALL_LIGHTS)
|
GROUP_NAME_ALL_LIGHTS)
|
||||||
from homeassistant.util import split_entity_id
|
from homeassistant.util import split_entity_id
|
||||||
@ -92,8 +92,13 @@ def setup(hass, config):
|
|||||||
hass.states.set("process.XBMC", STATE_ON)
|
hass.states.set("process.XBMC", STATE_ON)
|
||||||
|
|
||||||
# Setup device tracker
|
# Setup device tracker
|
||||||
hass.states.set("device_tracker.Paulus", "home")
|
hass.states.set("device_tracker.Paulus", "home",
|
||||||
hass.states.set("device_tracker.Anne_Therese", "not_home")
|
{ATTR_ENTITY_PICTURE:
|
||||||
|
"http://graph.facebook.com/schoutsen/picture"})
|
||||||
|
hass.states.set("device_tracker.Anne_Therese", "not_home",
|
||||||
|
{ATTR_ENTITY_PICTURE:
|
||||||
|
"http://graph.facebook.com/anne.t.frederiksen/picture"})
|
||||||
|
|
||||||
hass.states.set("group.all_devices", "home",
|
hass.states.set("group.all_devices", "home",
|
||||||
{
|
{
|
||||||
"auto": True,
|
"auto": True,
|
||||||
|
@ -61,7 +61,7 @@ def setup(hass, config):
|
|||||||
|
|
||||||
conf = config[DOMAIN]
|
conf = config[DOMAIN]
|
||||||
|
|
||||||
if not ha.CONF_TYPE in conf:
|
if ha.CONF_TYPE not in conf:
|
||||||
logger.error(
|
logger.error(
|
||||||
'Missing required configuration item in {}: {}'.format(
|
'Missing required configuration item in {}: {}'.format(
|
||||||
DOMAIN, ha.CONF_TYPE))
|
DOMAIN, ha.CONF_TYPE))
|
||||||
@ -175,7 +175,8 @@ class DeviceTracker(object):
|
|||||||
known_dev[device]['last_seen'] = now
|
known_dev[device]['last_seen'] = now
|
||||||
|
|
||||||
self.states.set(
|
self.states.set(
|
||||||
known_dev[device]['entity_id'], components.STATE_HOME)
|
known_dev[device]['entity_id'], components.STATE_HOME,
|
||||||
|
known_dev[device]['default_state_attr'])
|
||||||
|
|
||||||
# For all devices we did not find, set state to NH
|
# For all devices we did not find, set state to NH
|
||||||
# But only if they have been gone for longer then the error time span
|
# But only if they have been gone for longer then the error time span
|
||||||
@ -185,7 +186,8 @@ class DeviceTracker(object):
|
|||||||
if now - known_dev[device]['last_seen'] > self.error_scanning:
|
if now - known_dev[device]['last_seen'] > self.error_scanning:
|
||||||
|
|
||||||
self.states.set(known_dev[device]['entity_id'],
|
self.states.set(known_dev[device]['entity_id'],
|
||||||
components.STATE_NOT_HOME)
|
components.STATE_NOT_HOME,
|
||||||
|
known_dev[device]['default_state_attr'])
|
||||||
|
|
||||||
# If we come along any unknown devices we will write them to the
|
# If we come along any unknown devices we will write them to the
|
||||||
# known devices file but only if we did not encounter an invalid
|
# known devices file but only if we did not encounter an invalid
|
||||||
@ -211,7 +213,8 @@ class DeviceTracker(object):
|
|||||||
writer = csv.writer(outp)
|
writer = csv.writer(outp)
|
||||||
|
|
||||||
if is_new_file:
|
if is_new_file:
|
||||||
writer.writerow(("device", "name", "track"))
|
writer.writerow((
|
||||||
|
"device", "name", "track", "picture"))
|
||||||
|
|
||||||
for device in unknown_devices:
|
for device in unknown_devices:
|
||||||
# See if the device scanner knows the name
|
# See if the device scanner knows the name
|
||||||
@ -219,9 +222,10 @@ class DeviceTracker(object):
|
|||||||
name = (self.device_scanner.get_device_name(device)
|
name = (self.device_scanner.get_device_name(device)
|
||||||
or "unknown_device")
|
or "unknown_device")
|
||||||
|
|
||||||
writer.writerow((device, name, 0))
|
writer.writerow((device, name, 0, ""))
|
||||||
known_dev[device] = {'name': name,
|
known_dev[device] = {'name': name,
|
||||||
'track': False}
|
'track': False,
|
||||||
|
'picture': ""}
|
||||||
|
|
||||||
except IOError:
|
except IOError:
|
||||||
self.logger.exception((
|
self.logger.exception((
|
||||||
@ -253,6 +257,13 @@ class DeviceTracker(object):
|
|||||||
|
|
||||||
row['track'] = True if row['track'] == '1' else False
|
row['track'] = True if row['track'] == '1' else False
|
||||||
|
|
||||||
|
if row['picture']:
|
||||||
|
row['default_state_attr'] = {
|
||||||
|
components.ATTR_ENTITY_PICTURE: row['picture']}
|
||||||
|
|
||||||
|
else:
|
||||||
|
row['default_state_attr'] = None
|
||||||
|
|
||||||
# If we track this device setup tracking variables
|
# If we track this device setup tracking variables
|
||||||
if row['track']:
|
if row['track']:
|
||||||
row['last_seen'] = default_last_seen
|
row['last_seen'] = default_last_seen
|
||||||
@ -276,6 +287,8 @@ class DeviceTracker(object):
|
|||||||
row['entity_id'] = entity_id
|
row['entity_id'] = entity_id
|
||||||
used_entity_ids.append(entity_id)
|
used_entity_ids.append(entity_id)
|
||||||
|
|
||||||
|
row['picture'] = row['picture']
|
||||||
|
|
||||||
known_devices[device] = row
|
known_devices[device] = row
|
||||||
|
|
||||||
if not known_devices:
|
if not known_devices:
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
""" DO NOT MODIFY. Auto-generated by build_polymer script """
|
""" DO NOT MODIFY. Auto-generated by build_polymer script """
|
||||||
VERSION = "0be01a612c785f83a9631d97b54d069a"
|
VERSION = "a460b05ee24f1e2372c820c552e815c3"
|
||||||
|
@ -17780,11 +17780,13 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||||||
<template>
|
<template>
|
||||||
<style>
|
<style>
|
||||||
:host {
|
:host {
|
||||||
|
position: relative;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 45px;
|
width: 45px;
|
||||||
background-color: #4fc3f7;
|
background-color: #4fc3f7;
|
||||||
color: white;
|
color: white;
|
||||||
border-radius: 23px;
|
border-radius: 50%;
|
||||||
|
transition: all .3s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
div {
|
div {
|
||||||
@ -17792,18 +17794,76 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#picture {
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
domain-icon {
|
domain-icon {
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Color the icon if light or sun is on */
|
||||||
|
domain-icon[data-domain=light][data-state=on],
|
||||||
|
domain-icon[data-domain=sun][data-state=above_horizon] {
|
||||||
|
color: #fff176;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<div horizontal="" layout="" center="">
|
<div horizontal="" layout="" center="">
|
||||||
<domain-icon domain="{{stateObj.domain}}" state="{{stateObj.state}}">
|
<domain-icon id="icon" domain="{{stateObj.domain}}" state="{{stateObj.state}}">
|
||||||
</domain-icon>
|
</domain-icon>
|
||||||
|
<div fit="" id="picture" style="{{'background-image: url('+stateObj.attributes.entity_picture+')'}}"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
<script>Polymer('state-badge');</script></polymer-element>
|
<script>
|
||||||
|
Polymer('state-badge',{
|
||||||
|
observe: {
|
||||||
|
'stateObj.state': 'stateChanged',
|
||||||
|
'stateObj.attributes.entity_picture': 'entityPictureChanged'
|
||||||
|
},
|
||||||
|
|
||||||
|
stateChanged: function(oldVal, newVal) {
|
||||||
|
var state = this.stateObj;
|
||||||
|
|
||||||
|
// for domain light, set color of icon to light color if available
|
||||||
|
if(state.domain == "light" && newVal == "on" &&
|
||||||
|
state.attributes.brightness && state.attributes.xy_color) {
|
||||||
|
|
||||||
|
var rgb = this.xyBriToRgb(state.attributes.xy_color[0],
|
||||||
|
state.attributes.xy_color[1],
|
||||||
|
state.attributes.brightness);
|
||||||
|
this.style.color = "rgb(" + rgb.map(Math.floor).join(",") + ")";
|
||||||
|
} else {
|
||||||
|
this.style.color = 'white';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// from http://stackoverflow.com/questions/22894498/philips-hue-convert-xy-from-api-to-hex-or-rgb
|
||||||
|
xyBriToRgb: function (x, y, bri) {
|
||||||
|
z = 1.0 - x - y;
|
||||||
|
Y = bri / 255.0; // Brightness of lamp
|
||||||
|
X = (Y / y) * x;
|
||||||
|
Z = (Y / y) * z;
|
||||||
|
r = X * 1.612 - Y * 0.203 - Z * 0.302;
|
||||||
|
g = -X * 0.509 + Y * 1.412 + Z * 0.066;
|
||||||
|
b = X * 0.026 - Y * 0.072 + Z * 0.962;
|
||||||
|
r = r <= 0.0031308 ? 12.92 * r : (1.0 + 0.055) * Math.pow(r, (1.0 / 2.4)) - 0.055;
|
||||||
|
g = g <= 0.0031308 ? 12.92 * g : (1.0 + 0.055) * Math.pow(g, (1.0 / 2.4)) - 0.055;
|
||||||
|
b = b <= 0.0031308 ? 12.92 * b : (1.0 + 0.055) * Math.pow(b, (1.0 / 2.4)) - 0.055;
|
||||||
|
maxValue = Math.max(r,g,b);
|
||||||
|
r /= maxValue;
|
||||||
|
g /= maxValue;
|
||||||
|
b /= maxValue;
|
||||||
|
r = r * 255; if (r < 0) { r = 255 };
|
||||||
|
g = g * 255; if (g < 0) { g = 255 };
|
||||||
|
b = b * 255; if (b < 0) { b = 255 };
|
||||||
|
return [r, g, b]
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</polymer-element>
|
||||||
|
|
||||||
|
|
||||||
<polymer-element name="state-card" attributes="stateObj cb_turn_on, cb_turn_off cb_edit" assetpath="polymer/">
|
<polymer-element name="state-card" attributes="stateObj cb_turn_on, cb_turn_off cb_edit" assetpath="polymer/">
|
||||||
@ -17826,19 +17886,12 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||||||
state-badge {
|
state-badge {
|
||||||
float: left;
|
float: left;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: background-color .2s ease-in-out, color .5s ease-in-out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
state-badge:hover {
|
state-badge:hover {
|
||||||
background-color: #039be5;
|
background-color: #039be5;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Color the icon if light or sun is on */
|
|
||||||
state-badge[data-domain=light][data-state=on],
|
|
||||||
state-badge[data-domain=sun][data-state=above_horizon] {
|
|
||||||
color: #fff176;
|
|
||||||
}
|
|
||||||
|
|
||||||
.name, .state.text {
|
.name, .state.text {
|
||||||
text-transform: capitalize;
|
text-transform: capitalize;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
@ -17877,7 +17930,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||||||
<div horizontal="" justified="" layout="">
|
<div horizontal="" justified="" layout="">
|
||||||
|
|
||||||
<div class="entity">
|
<div class="entity">
|
||||||
<state-badge id="badge" stateobj="{{stateObj}}" data-domain="{{stateObj.domain}}" data-state="{{stateObj.state}}" on-click="{{editClicked}}">
|
<state-badge stateobj="{{stateObj}}" on-click="{{editClicked}}">
|
||||||
</state-badge>
|
</state-badge>
|
||||||
|
|
||||||
<div class="info">
|
<div class="info">
|
||||||
@ -17952,20 +18005,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||||||
stateChanged: function(oldVal, newVal) {
|
stateChanged: function(oldVal, newVal) {
|
||||||
this.stateUnknown = newVal == null;
|
this.stateUnknown = newVal == null;
|
||||||
this.toggleChecked = newVal == "on"
|
this.toggleChecked = newVal == "on"
|
||||||
|
|
||||||
var state = this.stateObj;
|
|
||||||
|
|
||||||
// for domain light, set color of icon to light color if available
|
|
||||||
if(state.domain == "light" && newVal == "on" &&
|
|
||||||
state.attributes.brightness && state.attributes.xy_color) {
|
|
||||||
|
|
||||||
var rgb = this.xyBriToRgb(state.attributes.xy_color[0],
|
|
||||||
state.attributes.xy_color[1],
|
|
||||||
state.attributes.brightness);
|
|
||||||
this.$.badge.style.color = "rgb(" + rgb.map(Math.floor).join(",") + ")";
|
|
||||||
} else {
|
|
||||||
this.$.badge.style.color = null;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
turn_on: function() {
|
turn_on: function() {
|
||||||
@ -17998,27 +18037,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// from http://stackoverflow.com/questions/22894498/philips-hue-convert-xy-from-api-to-hex-or-rgb
|
|
||||||
xyBriToRgb: function (x, y, bri) {
|
|
||||||
z = 1.0 - x - y;
|
|
||||||
Y = bri / 255.0; // Brightness of lamp
|
|
||||||
X = (Y / y) * x;
|
|
||||||
Z = (Y / y) * z;
|
|
||||||
r = X * 1.612 - Y * 0.203 - Z * 0.302;
|
|
||||||
g = -X * 0.509 + Y * 1.412 + Z * 0.066;
|
|
||||||
b = X * 0.026 - Y * 0.072 + Z * 0.962;
|
|
||||||
r = r <= 0.0031308 ? 12.92 * r : (1.0 + 0.055) * Math.pow(r, (1.0 / 2.4)) - 0.055;
|
|
||||||
g = g <= 0.0031308 ? 12.92 * g : (1.0 + 0.055) * Math.pow(g, (1.0 / 2.4)) - 0.055;
|
|
||||||
b = b <= 0.0031308 ? 12.92 * b : (1.0 + 0.055) * Math.pow(b, (1.0 / 2.4)) - 0.055;
|
|
||||||
maxValue = Math.max(r,g,b);
|
|
||||||
r /= maxValue;
|
|
||||||
g /= maxValue;
|
|
||||||
b /= maxValue;
|
|
||||||
r = r * 255; if (r < 0) { r = 255 };
|
|
||||||
g = g * 255; if (g < 0) { g = 255 };
|
|
||||||
b = b * 255; if (b < 0) { b = 255 };
|
|
||||||
return [r, g, b]
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</polymer-element>
|
</polymer-element>
|
||||||
@ -18198,7 +18216,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||||||
},
|
},
|
||||||
|
|
||||||
handleRefreshClick: function() {
|
handleRefreshClick: function() {
|
||||||
this.api.fetchStates();
|
this.api.fetchAll();
|
||||||
},
|
},
|
||||||
|
|
||||||
handleEventClick: function() {
|
handleEventClick: function() {
|
||||||
@ -19977,11 +19995,55 @@ core-item {
|
|||||||
<state-set-dialog id="stateDialog" api="{{api}}"></state-set-dialog>
|
<state-set-dialog id="stateDialog" api="{{api}}"></state-set-dialog>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
|
State = function(json, api) {
|
||||||
|
this.api = api;
|
||||||
|
|
||||||
|
this.attributes = json.attributes;
|
||||||
|
|
||||||
|
this.entity_id = json.entity_id;
|
||||||
|
var parts = json.entity_id.split(".");
|
||||||
|
this.domain = parts[0];
|
||||||
|
this.entity = parts[1];
|
||||||
|
|
||||||
|
if(this.attributes.friendly_name) {
|
||||||
|
this.entityDisplay = this.attributes.friendly_name;
|
||||||
|
} else {
|
||||||
|
this.entityDisplay = this.entity.replace(/_/g, " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.state = json.state;
|
||||||
|
this.last_changed = json.last_changed;
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.defineProperties(State.prototype, {
|
||||||
|
"stateDisplay": {
|
||||||
|
get: function() {
|
||||||
|
return this.state.replace(/_/g, " ");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"isCustomGroup": {
|
||||||
|
get: function() {
|
||||||
|
return this.domain == "group" && !this.attributes.auto;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"canToggle": {
|
||||||
|
get: function() {
|
||||||
|
// groups that have the on/off state or if there is a turn_on service
|
||||||
|
return ((this.domain == 'group' &&
|
||||||
|
(this.state == 'on' || this.state == 'off')) ||
|
||||||
|
this.api.hasService(this.domain, 'turn_on'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Polymer('home-assistant-api',{
|
Polymer('home-assistant-api',{
|
||||||
auth: "not-set",
|
auth: "not-set",
|
||||||
states: [],
|
states: [],
|
||||||
services: {},
|
services: [],
|
||||||
events: {},
|
events: [],
|
||||||
stateUpdateTimeout: null,
|
stateUpdateTimeout: null,
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
@ -19998,11 +20060,19 @@ core-item {
|
|||||||
|
|
||||||
// local methods
|
// local methods
|
||||||
getState: function(entityId) {
|
getState: function(entityId) {
|
||||||
for(var i = 0; i < this.states.length; i++) {
|
var found = this.states.filter(function(state) {
|
||||||
if(this.states[i].entity_id == entityId) {
|
return state.entity_id == entityId;
|
||||||
return this.states[i];
|
}, this);
|
||||||
}
|
|
||||||
}
|
return found.length > 0 ? found[0] : null;
|
||||||
|
},
|
||||||
|
|
||||||
|
hasService: function(domain, service) {
|
||||||
|
var found = this.services.filter(function(serv) {
|
||||||
|
return serv.domain == domain && serv.services.indexOf(service) !== -1;
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
return found.length > 0;
|
||||||
},
|
},
|
||||||
|
|
||||||
_laterFetchStates: function() {
|
_laterFetchStates: function() {
|
||||||
@ -20043,30 +20113,20 @@ core-item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(!stateFound) {
|
if(!stateFound) {
|
||||||
this._enhanceState(state);
|
this.states.push(new State(new_state, this));
|
||||||
this.states.push(new_state);
|
|
||||||
this._sortStates(this.states);
|
this._sortStates(this.states);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.fire('states-updated')
|
this.fire('states-updated')
|
||||||
},
|
},
|
||||||
|
|
||||||
_enhanceState: function(state) {
|
// call api methods
|
||||||
var parts = state.entity_id.split(".");
|
fetchAll: function() {
|
||||||
state.domain = parts[0];
|
this.fetchStates();
|
||||||
state.entity = parts[1];
|
this.fetchServices();
|
||||||
state.stateDisplay = state.state.replace(/_/g, " ");
|
this.fetchEvents();
|
||||||
state.canToggle = state.state == "on" || state.state == "off";
|
|
||||||
state.isCustomGroup = state.domain == "group" && !state.attributes.auto;
|
|
||||||
|
|
||||||
if(state.attributes.friendly_name) {
|
|
||||||
state.entityDisplay = state.attributes.friendly_name;
|
|
||||||
} else {
|
|
||||||
state.entityDisplay = state.entity.replace(/_/g, " ");
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// call api methods
|
|
||||||
fetchState: function(entityId) {
|
fetchState: function(entityId) {
|
||||||
var successStateUpdate = function(new_state) {
|
var successStateUpdate = function(new_state) {
|
||||||
this._pushNewState(new_state);
|
this._pushNewState(new_state);
|
||||||
@ -20078,40 +20138,52 @@ core-item {
|
|||||||
fetchStates: function(onSuccess, onError) {
|
fetchStates: function(onSuccess, onError) {
|
||||||
var successStatesUpdate = function(newStates) {
|
var successStatesUpdate = function(newStates) {
|
||||||
this._sortStates(newStates);
|
this._sortStates(newStates);
|
||||||
newStates.map(this._enhanceState);
|
|
||||||
this.states = newStates;
|
this.states = newStates.map(function(json) {
|
||||||
|
return new State(json, this);
|
||||||
|
}.bind(this));
|
||||||
|
|
||||||
this.fire('states-updated')
|
this.fire('states-updated')
|
||||||
|
|
||||||
this._laterFetchStates();
|
this._laterFetchStates();
|
||||||
|
|
||||||
if(onSuccess) {
|
if(onSuccess) {
|
||||||
onSuccess(newStates);
|
onSuccess(this.states);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.call_api("GET", "states", null, successStatesUpdate.bind(this), onError);
|
this.call_api(
|
||||||
|
"GET", "states", null, successStatesUpdate.bind(this), onError);
|
||||||
},
|
},
|
||||||
|
|
||||||
fetchEvents: function() {
|
fetchEvents: function(onSuccess, onError) {
|
||||||
var successEventsUpdated = function(events) {
|
var successEventsUpdated = function(events) {
|
||||||
this.events = events;
|
this.events = this.events;
|
||||||
|
|
||||||
this.fire('events-updated')
|
this.fire('events-updated')
|
||||||
|
|
||||||
|
if(onSuccess) {
|
||||||
|
onSuccess(events);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.call_api("GET", "events", null, successEventsUpdated.bind(this));
|
this.call_api(
|
||||||
|
"GET", "events", null, successEventsUpdated.bind(this), onError);
|
||||||
},
|
},
|
||||||
|
|
||||||
fetchServices: function() {
|
fetchServices: function(onSuccess, onError) {
|
||||||
var successServicesUpdated = function(services) {
|
var successServicesUpdated = function(services) {
|
||||||
this.services = services;
|
this.services = services;
|
||||||
|
|
||||||
this.fire('services-updated')
|
this.fire('services-updated')
|
||||||
|
|
||||||
|
if(onSuccess) {
|
||||||
|
onSuccess(this.services);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.call_api("GET", "services", null,
|
this.call_api(
|
||||||
successServicesUpdated.bind(this));
|
"GET", "services", null, successServicesUpdated.bind(this), onError);
|
||||||
},
|
},
|
||||||
|
|
||||||
turn_on: function(entity_id) {
|
turn_on: function(entity_id) {
|
||||||
@ -20327,6 +20399,7 @@ core-item {
|
|||||||
// log out functionality
|
// log out functionality
|
||||||
if(newVal == "" && this.state == "valid_auth") {
|
if(newVal == "" && this.state == "valid_auth") {
|
||||||
this.state = "no_auth";
|
this.state = "no_auth";
|
||||||
|
this.$.validateMessage.innerHTML = "Validating password...";
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -20342,10 +20415,12 @@ core-item {
|
|||||||
this.$.validateMessage.removeAttribute('hidden');
|
this.$.validateMessage.removeAttribute('hidden');
|
||||||
|
|
||||||
var passwordValid = function(result) {
|
var passwordValid = function(result) {
|
||||||
this.api.fetchServices();
|
this.$.validateMessage.innerHTML = "Loading data...";
|
||||||
this.api.fetchEvents();
|
this.api.fetchEvents();
|
||||||
|
|
||||||
this.state = "valid_auth";
|
this.api.fetchStates(function() {
|
||||||
|
this.state = "valid_auth";
|
||||||
|
}.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
var passwordInvalid = function(result) {
|
var passwordInvalid = function(result) {
|
||||||
@ -20361,7 +20436,7 @@ core-item {
|
|||||||
this.$.passwordInput.focus();
|
this.$.passwordInput.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.api.fetchStates(passwordValid.bind(this), passwordInvalid.bind(this));
|
this.api.fetchServices(passwordValid.bind(this), passwordInvalid.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -49,7 +49,10 @@
|
|||||||
|
|
||||||
"canToggle": {
|
"canToggle": {
|
||||||
get: function() {
|
get: function() {
|
||||||
return this.api.hasService(this.domain, 'turn_on');
|
// groups that have the on/off state or if there is a turn_on service
|
||||||
|
return ((this.domain == 'group' &&
|
||||||
|
(this.state == 'on' || this.state == 'off')) ||
|
||||||
|
this.api.hasService(this.domain, 'turn_on'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -2,15 +2,17 @@
|
|||||||
|
|
||||||
<link rel="import" href="domain-icon.html">
|
<link rel="import" href="domain-icon.html">
|
||||||
|
|
||||||
<polymer-element name="state-badge" attributes="stateObj" noscript>
|
<polymer-element name="state-badge" attributes="stateObj">
|
||||||
<template>
|
<template>
|
||||||
<style>
|
<style>
|
||||||
:host {
|
:host {
|
||||||
|
position: relative;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 45px;
|
width: 45px;
|
||||||
background-color: #4fc3f7;
|
background-color: #4fc3f7;
|
||||||
color: white;
|
color: white;
|
||||||
border-radius: 23px;
|
border-radius: 50%;
|
||||||
|
transition: all .3s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
div {
|
div {
|
||||||
@ -18,15 +20,75 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#picture {
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
domain-icon {
|
domain-icon {
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Color the icon if light or sun is on */
|
||||||
|
domain-icon[data-domain=light][data-state=on],
|
||||||
|
domain-icon[data-domain=sun][data-state=above_horizon] {
|
||||||
|
color: #fff176;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<div horizontal layout center>
|
<div horizontal layout center>
|
||||||
<domain-icon domain="{{stateObj.domain}}" state="{{stateObj.state}}">
|
<domain-icon id="icon"
|
||||||
|
domain="{{stateObj.domain}}" state="{{stateObj.state}}">
|
||||||
</domain-icon>
|
</domain-icon>
|
||||||
|
<div fit id="picture"
|
||||||
|
style="{{'background-image: url('+stateObj.attributes.entity_picture+')'}}"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
<script>
|
||||||
|
Polymer({
|
||||||
|
observe: {
|
||||||
|
'stateObj.state': 'stateChanged',
|
||||||
|
'stateObj.attributes.entity_picture': 'entityPictureChanged'
|
||||||
|
},
|
||||||
|
|
||||||
|
stateChanged: function(oldVal, newVal) {
|
||||||
|
var state = this.stateObj;
|
||||||
|
|
||||||
|
// for domain light, set color of icon to light color if available
|
||||||
|
if(state.domain == "light" && newVal == "on" &&
|
||||||
|
state.attributes.brightness && state.attributes.xy_color) {
|
||||||
|
|
||||||
|
var rgb = this.xyBriToRgb(state.attributes.xy_color[0],
|
||||||
|
state.attributes.xy_color[1],
|
||||||
|
state.attributes.brightness);
|
||||||
|
this.style.color = "rgb(" + rgb.map(Math.floor).join(",") + ")";
|
||||||
|
} else {
|
||||||
|
this.style.color = 'white';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// from http://stackoverflow.com/questions/22894498/philips-hue-convert-xy-from-api-to-hex-or-rgb
|
||||||
|
xyBriToRgb: function (x, y, bri) {
|
||||||
|
z = 1.0 - x - y;
|
||||||
|
Y = bri / 255.0; // Brightness of lamp
|
||||||
|
X = (Y / y) * x;
|
||||||
|
Z = (Y / y) * z;
|
||||||
|
r = X * 1.612 - Y * 0.203 - Z * 0.302;
|
||||||
|
g = -X * 0.509 + Y * 1.412 + Z * 0.066;
|
||||||
|
b = X * 0.026 - Y * 0.072 + Z * 0.962;
|
||||||
|
r = r <= 0.0031308 ? 12.92 * r : (1.0 + 0.055) * Math.pow(r, (1.0 / 2.4)) - 0.055;
|
||||||
|
g = g <= 0.0031308 ? 12.92 * g : (1.0 + 0.055) * Math.pow(g, (1.0 / 2.4)) - 0.055;
|
||||||
|
b = b <= 0.0031308 ? 12.92 * b : (1.0 + 0.055) * Math.pow(b, (1.0 / 2.4)) - 0.055;
|
||||||
|
maxValue = Math.max(r,g,b);
|
||||||
|
r /= maxValue;
|
||||||
|
g /= maxValue;
|
||||||
|
b /= maxValue;
|
||||||
|
r = r * 255; if (r < 0) { r = 255 };
|
||||||
|
g = g * 255; if (g < 0) { g = 255 };
|
||||||
|
b = b * 255; if (b < 0) { b = 255 };
|
||||||
|
return [r, g, b]
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
</polymer-element>
|
</polymer-element>
|
||||||
|
@ -27,19 +27,12 @@
|
|||||||
state-badge {
|
state-badge {
|
||||||
float: left;
|
float: left;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: background-color .2s ease-in-out, color .5s ease-in-out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
state-badge:hover {
|
state-badge:hover {
|
||||||
background-color: #039be5;
|
background-color: #039be5;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Color the icon if light or sun is on */
|
|
||||||
state-badge[data-domain=light][data-state=on],
|
|
||||||
state-badge[data-domain=sun][data-state=above_horizon] {
|
|
||||||
color: #fff176;
|
|
||||||
}
|
|
||||||
|
|
||||||
.name, .state.text {
|
.name, .state.text {
|
||||||
text-transform: capitalize;
|
text-transform: capitalize;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
@ -79,10 +72,7 @@
|
|||||||
|
|
||||||
<div class="entity">
|
<div class="entity">
|
||||||
<state-badge
|
<state-badge
|
||||||
id="badge"
|
|
||||||
stateObj="{{stateObj}}"
|
stateObj="{{stateObj}}"
|
||||||
data-domain="{{stateObj.domain}}"
|
|
||||||
data-state="{{stateObj.state}}"
|
|
||||||
on-click="{{editClicked}}">
|
on-click="{{editClicked}}">
|
||||||
</state-badge>
|
</state-badge>
|
||||||
|
|
||||||
@ -158,20 +148,6 @@
|
|||||||
stateChanged: function(oldVal, newVal) {
|
stateChanged: function(oldVal, newVal) {
|
||||||
this.stateUnknown = newVal == null;
|
this.stateUnknown = newVal == null;
|
||||||
this.toggleChecked = newVal == "on"
|
this.toggleChecked = newVal == "on"
|
||||||
|
|
||||||
var state = this.stateObj;
|
|
||||||
|
|
||||||
// for domain light, set color of icon to light color if available
|
|
||||||
if(state.domain == "light" && newVal == "on" &&
|
|
||||||
state.attributes.brightness && state.attributes.xy_color) {
|
|
||||||
|
|
||||||
var rgb = this.xyBriToRgb(state.attributes.xy_color[0],
|
|
||||||
state.attributes.xy_color[1],
|
|
||||||
state.attributes.brightness);
|
|
||||||
this.$.badge.style.color = "rgb(" + rgb.map(Math.floor).join(",") + ")";
|
|
||||||
} else {
|
|
||||||
this.$.badge.style.color = null;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
turn_on: function() {
|
turn_on: function() {
|
||||||
@ -204,27 +180,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// from http://stackoverflow.com/questions/22894498/philips-hue-convert-xy-from-api-to-hex-or-rgb
|
|
||||||
xyBriToRgb: function (x, y, bri) {
|
|
||||||
z = 1.0 - x - y;
|
|
||||||
Y = bri / 255.0; // Brightness of lamp
|
|
||||||
X = (Y / y) * x;
|
|
||||||
Z = (Y / y) * z;
|
|
||||||
r = X * 1.612 - Y * 0.203 - Z * 0.302;
|
|
||||||
g = -X * 0.509 + Y * 1.412 + Z * 0.066;
|
|
||||||
b = X * 0.026 - Y * 0.072 + Z * 0.962;
|
|
||||||
r = r <= 0.0031308 ? 12.92 * r : (1.0 + 0.055) * Math.pow(r, (1.0 / 2.4)) - 0.055;
|
|
||||||
g = g <= 0.0031308 ? 12.92 * g : (1.0 + 0.055) * Math.pow(g, (1.0 / 2.4)) - 0.055;
|
|
||||||
b = b <= 0.0031308 ? 12.92 * b : (1.0 + 0.055) * Math.pow(b, (1.0 / 2.4)) - 0.055;
|
|
||||||
maxValue = Math.max(r,g,b);
|
|
||||||
r /= maxValue;
|
|
||||||
g /= maxValue;
|
|
||||||
b /= maxValue;
|
|
||||||
r = r * 255; if (r < 0) { r = 255 };
|
|
||||||
g = g * 255; if (g < 0) { g = 255 };
|
|
||||||
b = b * 255; if (b < 0) { b = 255 };
|
|
||||||
return [r, g, b]
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</polymer-element>
|
</polymer-element>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user