mirror of
https://github.com/home-assistant/core.git
synced 2025-04-23 16:57:53 +00:00
More material love for interface
This commit is contained in:
parent
3bab3f4be1
commit
30ba447c64
@ -9,9 +9,11 @@ Bare minimum what is needed for a component to be valid.
|
||||
DOMAIN = "example"
|
||||
|
||||
# List of component names (string) your component depends upon
|
||||
# If you are setting up a group but not using a group for anything, don't depend on group
|
||||
# If you are setting up a group but not using a group for anything,
|
||||
# don't depend on group
|
||||
DEPENDENCIES = []
|
||||
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
def setup(hass, config):
|
||||
""" Register services or listen for events that your component needs. """
|
||||
|
@ -143,7 +143,8 @@ class DeviceTracker(object):
|
||||
|
||||
self.update_devices()
|
||||
|
||||
group.setup_group(hass, GROUP_NAME_ALL_DEVICES, self.device_entity_ids)
|
||||
group.setup_group(
|
||||
hass, GROUP_NAME_ALL_DEVICES, self.device_entity_ids, False)
|
||||
|
||||
@property
|
||||
def device_entity_ids(self):
|
||||
|
@ -17,6 +17,8 @@ DEPENDENCIES = []
|
||||
|
||||
ENTITY_ID_FORMAT = DOMAIN + ".{}"
|
||||
|
||||
ATTR_AUTO = "auto"
|
||||
|
||||
_GROUP_TYPES = {
|
||||
"on_off": (STATE_ON, STATE_OFF),
|
||||
"home_not_home": (STATE_HOME, STATE_NOT_HOME)
|
||||
@ -100,7 +102,7 @@ def setup(hass, config):
|
||||
|
||||
|
||||
# pylint: disable=too-many-branches
|
||||
def setup_group(hass, name, entity_ids):
|
||||
def setup_group(hass, name, entity_ids, user_defined=True):
|
||||
""" Sets up a group state that is the combined state of
|
||||
several states. Supports ON/OFF and DEVICE_HOME/DEVICE_NOT_HOME. """
|
||||
|
||||
@ -161,7 +163,7 @@ def setup_group(hass, name, entity_ids):
|
||||
|
||||
else:
|
||||
group_entity_id = ENTITY_ID_FORMAT.format(name)
|
||||
state_attr = {ATTR_ENTITY_ID: entity_ids}
|
||||
state_attr = {ATTR_ENTITY_ID: entity_ids, ATTR_AUTO: not user_defined}
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
def update_group_state(entity_id, old_state, new_state):
|
||||
|
@ -1,2 +1,2 @@
|
||||
""" DO NOT MODIFY. Auto-generated by build_polymer script """
|
||||
VERSION = "460fa7f075841b858b102678f13fb070"
|
||||
VERSION = "57f41262ccbd90c2e988e5be0a5dab59"
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -29,6 +29,9 @@
|
||||
"moment": "~2.8.3",
|
||||
"paper-input": "Polymer/paper-input#~0.4.2",
|
||||
"core-menu": "Polymer/core-menu#~0.4.2",
|
||||
"core-item": "Polymer/core-item#~0.4.2"
|
||||
"core-item": "Polymer/core-item#~0.4.2",
|
||||
"core-icons": "polymer/core-icons#~0.4.2",
|
||||
"paper-toggle-button": "polymer/paper-toggle-button#~0.4.2",
|
||||
"paper-tabs": "polymer/paper-tabs#~0.4.2"
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,47 @@
|
||||
<link rel="import" href="bower_components/polymer/polymer.html">
|
||||
|
||||
<link rel="import" href="bower_components/core-icon/core-icon.html">
|
||||
<link rel="import" href="bower_components/core-icons/device-icons.html">
|
||||
<link rel="import" href="bower_components/core-icons/social-icons.html">
|
||||
<link rel="import" href="bower_components/core-icons/image-icons.html">
|
||||
<link rel="import" href="bower_components/core-icons/hardware-icons.html">
|
||||
|
||||
<polymer-element name="domain-icon" attributes="domain">
|
||||
<template>
|
||||
<core-icon icon="{{icon(domain)}}"></core-icon>
|
||||
</template>
|
||||
<script>
|
||||
Polymer({
|
||||
|
||||
icon: function() {
|
||||
switch(this.domain) {
|
||||
case "group":
|
||||
return "social:communities";
|
||||
|
||||
case "device_tracker":
|
||||
return "social:person";
|
||||
|
||||
case "wemo":
|
||||
return "settings-input-svideo";
|
||||
|
||||
case "chromecast":
|
||||
// hardware:cast-connected
|
||||
return "hardware:cast";
|
||||
|
||||
case "process":
|
||||
return "hardware:memory"
|
||||
|
||||
case "sun":
|
||||
return "device:brightness-low"
|
||||
|
||||
case "light":
|
||||
return "image:wb-incandescent"
|
||||
|
||||
default:
|
||||
return "bookmark-outline";
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
</script>
|
||||
</polymer-element>
|
@ -153,6 +153,12 @@
|
||||
}
|
||||
},
|
||||
|
||||
getCustomGroups: function() {
|
||||
return this.states.filter(function(state) {
|
||||
return state.entity_id.lastIndexOf("group.") == 0;
|
||||
})
|
||||
},
|
||||
|
||||
turn_on: function(entity_id) {
|
||||
this.call_service("homeassistant", "turn_on", {entity_id: entity_id});
|
||||
},
|
||||
|
@ -2,6 +2,8 @@
|
||||
<link rel="import" href="bower_components/core-toolbar/core-toolbar.html">
|
||||
<link rel="import" href="bower_components/core-icon-button/core-icon-button.html">
|
||||
<link rel="import" href="bower_components/paper-fab/paper-fab.html">
|
||||
<link rel="import" href="bower_components/paper-tabs/paper-tabs.html">
|
||||
<link rel="import" href="bower_components/paper-tabs/paper-tab.html">
|
||||
|
||||
<link rel="import" href="home-assistant-api.html">
|
||||
<link rel="import" href="states-cards.html">
|
||||
@ -25,6 +27,7 @@
|
||||
background: #03a9f4;
|
||||
font-size: 1.4rem;
|
||||
color: white;
|
||||
height: 95px;
|
||||
}
|
||||
|
||||
.content {
|
||||
@ -51,10 +54,25 @@
|
||||
<core-icon-button icon="refresh" on-click="{{handleRefreshClick}}"></core-icon-button>
|
||||
<core-icon-button icon="developer-mode-tv" on-click="{{handleEventClick}}"></core-icon-button>
|
||||
<core-icon-button icon="settings-remote" on-click="{{handleServiceClick}}"></core-icon-button>
|
||||
|
||||
<div class="bottom fit" horizontal layout>
|
||||
<paper-tabs id="tabsHolder" noink flex
|
||||
selected="0" on-core-select="{{tabClicked}}">
|
||||
|
||||
<paper-tab>ALL</paper-tab>
|
||||
|
||||
<template repeat="{{state in api.states}}">
|
||||
<template if="{{isCustomGroup(state)}}">
|
||||
<paper-tab data-entity="{{state.entity_id}}">{{state.entity_id | groupName}}</paper-tab>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
</paper-tabs>
|
||||
</div>
|
||||
</core-toolbar>
|
||||
|
||||
<div class="content" flex>
|
||||
<states-cards api="{{api}}"></states-cards>
|
||||
<states-cards api="{{api}}" filter="{{selectedTab}}"></states-cards>
|
||||
<paper-fab icon="add" on-click={{handleAddStateClick}}></paper-fab>
|
||||
</div>
|
||||
|
||||
@ -63,11 +81,28 @@
|
||||
</template>
|
||||
<script>
|
||||
Polymer({
|
||||
selectedTab: null,
|
||||
|
||||
ready: function() {
|
||||
this.api = this.$.api;
|
||||
},
|
||||
|
||||
isCustomGroup: function(state) {
|
||||
return (state.entity_id.lastIndexOf('group.') == 0 &&
|
||||
!state.attributes.auto);
|
||||
},
|
||||
|
||||
groupName: function(entity_id) {
|
||||
return entity_id.substring(6).toUpperCase().replace(/_/g, " ");
|
||||
},
|
||||
|
||||
tabClicked: function(ev) {
|
||||
if(ev.detail.isSelected) {
|
||||
// will be null for ALL tab
|
||||
this.selectedTab = ev.detail.item.getAttribute('data-entity');
|
||||
}
|
||||
},
|
||||
|
||||
handleRefreshClick: function() {
|
||||
this.api.fetchStates();
|
||||
},
|
||||
|
@ -0,0 +1,34 @@
|
||||
<link rel="import" href="bower_components/polymer/polymer.html">
|
||||
|
||||
<link rel="import" href="domain-icon.html">
|
||||
|
||||
<polymer-element name="state-badge" attributes="domain state">
|
||||
<template>
|
||||
<style>
|
||||
:host {
|
||||
display: inline-block;
|
||||
width: 45px;
|
||||
background-color: #4fc3f7;
|
||||
color: white;
|
||||
border-radius: 23px;
|
||||
}
|
||||
div {
|
||||
height: 45px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
domain-icon {
|
||||
margin: 0 auto;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div horizontal layout center>
|
||||
<domain-icon domain="{{domain}}"></domain-icon>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
<script>
|
||||
Polymer({
|
||||
});
|
||||
</script>
|
||||
</polymer-element>
|
@ -2,104 +2,106 @@
|
||||
<link rel="import" href="bower_components/polymer/polymer.html">
|
||||
<link rel="import" href="bower_components/core-tooltip/core-tooltip.html">
|
||||
<link rel="import" href="bower_components/paper-button/paper-button.html">
|
||||
<link rel="import" href="bower_components/paper-toggle-button/paper-toggle-button.html">
|
||||
|
||||
<link rel="import" href="state-badge.html">
|
||||
|
||||
<polymer-element name="state-card"
|
||||
attributes="entity state last_changed state_attr cb_turn_on, cb_turn_off cb_edit">
|
||||
<template>
|
||||
<style>
|
||||
:host {
|
||||
background-color: #fff;
|
||||
border-radius: 2px;
|
||||
box-shadow: rgba(0, 0, 0, 0.098) 0px 2px 4px, rgba(0, 0, 0, 0.098) 0px 0px 3px;
|
||||
/* transition */
|
||||
-webkit-transition: all 0.30s ease-out;
|
||||
transition: all 0.30s ease-out;
|
||||
|
||||
position: relative;
|
||||
background-color: white;
|
||||
padding: 20px 20px 55px 20px;
|
||||
padding: 15px;
|
||||
width: 100%;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-transform: capitalize;
|
||||
|
||||
font-weight: 300;
|
||||
state-badge {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.name, .state.text {
|
||||
text-transform: capitalize;
|
||||
font-weight: 300;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.header .state {
|
||||
.state {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.subheader {
|
||||
margin-top: -5px;
|
||||
.info {
|
||||
margin-left: 60px;
|
||||
}
|
||||
|
||||
.time-ago {
|
||||
color: darkgrey;
|
||||
margin-top: -2px;
|
||||
}
|
||||
|
||||
.state-attributes {
|
||||
margin-top: 10px;
|
||||
font-size: 1rem;
|
||||
/* the splash while enabling */
|
||||
paper-toggle-button::shadow paper-radio-button::shadow #ink[checked] {
|
||||
color: #0091ea;
|
||||
}
|
||||
|
||||
.state-attributes .key {
|
||||
white-space: nowrap;
|
||||
width: 85px;
|
||||
float: left;
|
||||
clear: left;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.state-attributes .value {
|
||||
margin-left: 95px;
|
||||
}
|
||||
|
||||
.actions {
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
left: 20px;
|
||||
right: 20px;
|
||||
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
paper-button.toggle {
|
||||
color: #03a9f4;
|
||||
/* filling of circle when checked */
|
||||
paper-toggle-button::shadow paper-radio-button::shadow #onRadio {
|
||||
background-color: #0091ea;
|
||||
}
|
||||
|
||||
/* line when checked */
|
||||
paper-toggle-button::shadow #toggleBar[checked] {
|
||||
background-color: #0091ea;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="header" horizontal justified layout>
|
||||
<span class="entity_id">
|
||||
<template if="{{state_attr['friendly_name']}}">{{state_attr['friendly_name']}}</template>
|
||||
<template if="{{!state_attr['friendly_name']}}">{{entity_id | makeReadable}}</template>
|
||||
</span>
|
||||
<span class='state'>{{state | makeReadable}}</span>
|
||||
</div>
|
||||
<div horizontal justified layout>
|
||||
|
||||
<div class="entity">
|
||||
<state-badge
|
||||
domain="{{domain}}"
|
||||
state="{{state}}"
|
||||
on-click="{{editClicked}}">
|
||||
</state-badge>
|
||||
|
||||
<div class="subheader" horizontal justified layout>
|
||||
<span class="domain">{{domain}}</span>
|
||||
<core-tooltip label="{{last_changed}}" position="bottom">
|
||||
<span class="last_changed_from_now">{{last_changed_from_now}}</span>
|
||||
</core-tooltip>
|
||||
</div>
|
||||
|
||||
<div class='info'>
|
||||
<div class='name'>
|
||||
<template if="{{state_attr['friendly_name']}}">{{state_attr['friendly_name']}}</template>
|
||||
<template if="{{!state_attr['friendly_name']}}">{{entity_id | makeReadable}}</template>
|
||||
</div>
|
||||
|
||||
<div class="state-attributes">
|
||||
<template repeat="{{key in objectKeys(state_attr)}}">
|
||||
<template if="{{key != 'friendly_name'}}">
|
||||
<div class='key'>{{key | makeReadable}}</div>
|
||||
<div class='value'>{{state_attr[key] | makeReadable}}</div>
|
||||
</template>
|
||||
<div class="time-ago">
|
||||
<core-tooltip label="{{last_changed}}" position="bottom">
|
||||
{{last_changed_from_now}}
|
||||
</core-tooltip>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template if="{{state == 'on' || state == 'off'}}">
|
||||
<div class='state toggle' self-center flex>
|
||||
<paper-toggle-button
|
||||
id="toggleButton"
|
||||
on-change="{{toggle}}">
|
||||
</paper-toggle-button>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<paper-button class='edit' on-click="{{editClicked}}">EDIT</paper-button>
|
||||
|
||||
<template if="{{state == 'on'}}">
|
||||
<paper-button class="toggle" on-click="{{turn_off}}">TURN OFF</paper-button>
|
||||
<template if="{{state != 'on' && state != 'off'}}">
|
||||
<div class='state text'>
|
||||
{{state | makeReadable}}
|
||||
</div>
|
||||
</template>
|
||||
<template if="{{state == 'off'}}">
|
||||
<paper-button class="toggle" on-click="{{turn_on}}">TURN ON</paper-button>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</template>
|
||||
<script>
|
||||
@ -117,6 +119,12 @@
|
||||
domain: "",
|
||||
entity_id: "",
|
||||
|
||||
stateChanged: function() {
|
||||
if(this.$.toggleButton) {
|
||||
this.$.toggleButton.checked = this.state == 'on';
|
||||
}
|
||||
},
|
||||
|
||||
entityChanged: function(oldVal, newVal) {
|
||||
var parts = newVal.split(".")
|
||||
|
||||
@ -133,6 +141,14 @@
|
||||
this.last_changed_from_now = moment(this.last_changed, "HH:mm:ss DD-MM-YYYY").fromNow()
|
||||
},
|
||||
|
||||
toggle: function(ev) {
|
||||
if(this.$.toggleButton.checked) {
|
||||
this.turn_on();
|
||||
} else {
|
||||
this.turn_off();
|
||||
}
|
||||
},
|
||||
|
||||
turn_on: function() {
|
||||
if(this.cb_turn_on) {
|
||||
this.cb_turn_on(this.entity);
|
||||
@ -162,10 +178,6 @@
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
},
|
||||
|
||||
objectKeys: function(obj) {
|
||||
return obj ? Object.keys(obj) : [];
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<link rel="import" href="bower_components/polymer/polymer.html">
|
||||
<link rel="import" href="state-card.html">
|
||||
|
||||
<polymer-element name="states-cards" attributes="api">
|
||||
<polymer-element name="states-cards" attributes="api filter">
|
||||
<template>
|
||||
<style>
|
||||
:host {
|
||||
@ -22,6 +22,17 @@
|
||||
</style>
|
||||
|
||||
<div horizontal layout wrap>
|
||||
<template if="{{filter != null}}">
|
||||
<state-card
|
||||
entity="{{filter_state.entity_id}}"
|
||||
state="{{filter_state.state}}"
|
||||
last_changed="{{filter_state.last_changed}}"
|
||||
state_attr="{{filter_state.attributes}}"
|
||||
cb_turn_on="{{api.turn_on}}"
|
||||
cb_turn_off="{{api.turn_off}}"
|
||||
cb_edit={{editCallback}}>
|
||||
</state-card>
|
||||
</template>
|
||||
|
||||
<template repeat="{{state in states}}">
|
||||
<state-card
|
||||
@ -39,7 +50,15 @@
|
||||
</template>
|
||||
<script>
|
||||
Polymer({
|
||||
raw_states: [],
|
||||
states: [],
|
||||
filter: null,
|
||||
filter_state: null,
|
||||
filter_substates: null,
|
||||
|
||||
filterChanged: function(oldVal, newVal) {
|
||||
this.refilterStates();
|
||||
},
|
||||
|
||||
ready: function() {
|
||||
this.editCallback = this.editCallback.bind(this);
|
||||
@ -52,7 +71,24 @@
|
||||
},
|
||||
|
||||
statesUpdated: function() {
|
||||
this.states = this.api.states;
|
||||
this.raw_states = this.api.states;
|
||||
|
||||
this.refilterStates();
|
||||
},
|
||||
|
||||
refilterStates: function() {
|
||||
if(this.filter == null) {
|
||||
this.filter_state = null;
|
||||
this.states = this.raw_states;
|
||||
} else {
|
||||
this.filter_state = this.api.getState(this.filter);
|
||||
|
||||
var map_states = function(entity_id) {
|
||||
return this.api.getState(entity_id);
|
||||
}.bind(this)
|
||||
|
||||
this.states = this.filter_state.attributes.entity_id.map(map_states)
|
||||
}
|
||||
},
|
||||
|
||||
editCallback: function(entityId) {
|
||||
|
@ -224,7 +224,8 @@ def setup(hass, config):
|
||||
return False
|
||||
|
||||
# Track all lights in a group
|
||||
group.setup_group(hass, GROUP_NAME_ALL_LIGHTS, light_to_ent.values())
|
||||
group.setup_group(
|
||||
hass, GROUP_NAME_ALL_LIGHTS, light_to_ent.values(), False)
|
||||
|
||||
# Load built-in profiles and custom profiles
|
||||
profile_paths = [os.path.join(os.path.dirname(__file__),
|
||||
|
@ -139,8 +139,8 @@ def setup(hass, config):
|
||||
|
||||
update_wemos_state(None, True)
|
||||
|
||||
# Track all lights in a group
|
||||
group.setup_group(hass, GROUP_NAME_ALL_WEMOS, sno_to_ent.values())
|
||||
# Track all wemos in a group
|
||||
group.setup_group(hass, GROUP_NAME_ALL_WEMOS, sno_to_ent.values(), False)
|
||||
|
||||
def handle_wemo_service(service):
|
||||
""" Handles calls to the WeMo service. """
|
||||
|
Loading…
x
Reference in New Issue
Block a user