Improvements for zwave group config (#398)

* Improvements for zwave group config

* Apply ha-config-section
This commit is contained in:
Andrey 2017-08-26 19:58:50 +03:00 committed by Paulus Schoutsen
parent 60791ee03d
commit b211894a31
5 changed files with 278 additions and 218 deletions

View File

@ -13,6 +13,9 @@
<link rel="import" href="../../../src/components/buttons/ha-call-service-button.html"> <link rel="import" href="../../../src/components/buttons/ha-call-service-button.html">
<link rel="import" href="../../../src/components/ha-service-description.html"> <link rel="import" href="../../../src/components/ha-service-description.html">
<link rel="import" href="../../../src/resources/ha-style.html"> <link rel="import" href="../../../src/resources/ha-style.html">
<link rel="import" href="../ha-config-section.html">
<link rel="import" href="./zwave-log.html"> <link rel="import" href="./zwave-log.html">
<link rel="import" href="./zwave-network.html"> <link rel="import" href="./zwave-network.html">
<link rel="import" href="./zwave-node-information.html"> <link rel="import" href="./zwave-node-information.html">
@ -84,21 +87,28 @@
hass='[[hass]]' hass='[[hass]]'
></zwave-node-options> ></zwave-node-options>
<div class='content'>
<zwave-network <zwave-network
id='zwave-network' id='zwave-network'
is-wide='[[isWide]]'
hass='[[hass]]' hass='[[hass]]'
></zwave-network> ></zwave-network>
</div>
<!--Node card--> <!--Node card-->
<div class='content'> <ha-config-section is-wide='[[isWide]]'>
<paper-card heading='Z-Wave Node Management'> <div style="position: relative" slot='header'>
<span>Z-Wave Node Management</span>
<paper-icon-button <paper-icon-button
class='toggle-help-icon' class="toggle-help-icon"
on-tap='toggleHelp' on-tap='toggleHelp'
icon='mdi:help-circle' icon='mdi:help-circle'
></paper-icon-button> ></paper-icon-button>
</div>
<span slot='introduction'>
Run Z-Wave commands that affect a single node. Pick a node to see a list of available commands.
</span>
<paper-card class="content">
<div class='device-picker'> <div class='device-picker'>
<paper-dropdown-menu label="Nodes" class="flex"> <paper-dropdown-menu label="Nodes" class="flex">
<paper-listbox <paper-listbox
@ -234,35 +244,32 @@
</template> </template>
</template> </template>
</paper-card> </paper-card>
</div>
<!--Node info card-->
<template is='dom-if' if='[[computeIsNodeSelected(selectedNode)]]'> <template is='dom-if' if='[[computeIsNodeSelected(selectedNode)]]'>
<!--Node info card-->
<zwave-node-information <zwave-node-information
id='zwave-node-information' id='zwave-node-information'
nodes='[[nodes]]' nodes='[[nodes]]'
selected-node='[[selectedNode]]' selected-node='[[selectedNode]]'
></zwave-node-information> ></zwave-node-information>
</template>
<!--Value card--> <!--Value card-->
<template is='dom-if' if='[[computeIsNodeSelected(selectedNode)]]'>
<zwave-values <zwave-values
hass='[[hass]]' hass='[[hass]]'
nodes='[[nodes]]' nodes='[[nodes]]'
selected-node='[[selectedNode]]' selected-node='[[selectedNode]]'
values='[[values]]' values='[[values]]'
></zwave-values> ></zwave-values>
</template>
<!--Group card--> <!--Group card-->
<template is='dom-if' if='[[computeIsNodeSelected(selectedNode)]]'>
<zwave-groups <zwave-groups
hass='[[hass]]' hass='[[hass]]'
nodes='[[nodes]]' nodes='[[nodes]]'
selected-node='[[selectedNode]]' selected-node='[[selectedNode]]'
groups='[[groups]]' groups='[[groups]]'
></zwave-groups> ></zwave-groups>
</template>
<!--Config card--> <!--Config card-->
<template is='dom-if' if='[[computeIsNodeSelected(selectedNode)]]'>
<zwave-node-config <zwave-node-config
hass='[[hass]]' hass='[[hass]]'
nodes='[[nodes]]' nodes='[[nodes]]'
@ -270,6 +277,8 @@
config='[[config]]' config='[[config]]'
></zwave-node-config> ></zwave-node-config>
</template> </template>
</ha-config-section>
<!--User Codes--> <!--User Codes-->
<template is='dom-if' if='{{hasNodeUserCodes}}'> <template is='dom-if' if='{{hasNodeUserCodes}}'>
<zwave-usercodes <zwave-usercodes
@ -280,13 +289,12 @@
selected-node='[[selectedNode]]' selected-node='[[selectedNode]]'
></zwave-usercodes> ></zwave-usercodes>
</template> </template>
<!--Ozw log--> <!--Ozw log-->
<div class='content'>
<ozw-log <ozw-log
id='ozw-log' is-wide='[[isWide]]'
hass='[[hass]]' hass='[[hass]]'
></ozw-log> ></ozw-log>
</div>
</app-header-layout> </app-header-layout>
</template> </template>
@ -406,28 +414,28 @@ Polymer({
this.selectedGroup = -1; this.selectedGroup = -1;
this.hass.callApi('GET', 'zwave/config/' + this.nodes[selectedNode].attributes.node_id).then( this.hass.callApi('GET', 'zwave/config/' + this.nodes[selectedNode].attributes.node_id).then(
function (configs) { (configs) => {
this.config = this._objToArray(configs); this.config = this._objToArray(configs);
}.bind(this)); });
this.hass.callApi('GET', 'zwave/values/' + this.nodes[selectedNode].attributes.node_id).then( this.hass.callApi('GET', 'zwave/values/' + this.nodes[selectedNode].attributes.node_id).then(
function (values) { (values) => {
this.values = this._objToArray(values); this.values = this._objToArray(values);
}.bind(this)); });
this.hass.callApi('GET', 'zwave/groups/' + this.nodes[selectedNode].attributes.node_id).then( this.hass.callApi('GET', 'zwave/groups/' + this.nodes[selectedNode].attributes.node_id).then(
function (groups) { (groups) => {
this.groups = this._objToArray(groups); this.groups = this._objToArray(groups);
}.bind(this)); });
this.hasNodeUserCodes = false; this.hasNodeUserCodes = false;
this.notifyPath('hasNodeUserCodes'); this.notifyPath('hasNodeUserCodes');
this.hass.callApi('GET', 'zwave/usercodes/' + this.nodes[selectedNode].attributes.node_id).then( this.hass.callApi('GET', 'zwave/usercodes/' + this.nodes[selectedNode].attributes.node_id).then(
function (usercodes) { (usercodes) => {
this.userCodes = this._objToArray(usercodes); this.userCodes = this._objToArray(usercodes);
this.hasNodeUserCodes = this.userCodes.length > 0; this.hasNodeUserCodes = this.userCodes.length > 0;
this.notifyPath('hasNodeUserCodes'); this.notifyPath('hasNodeUserCodes');
}.bind(this)); });
}, },
computeSelectedEntityAttrs: function (selectedEntity) { computeSelectedEntityAttrs: function (selectedEntity) {

View File

@ -30,22 +30,10 @@
.help-text { .help-text {
padding-left: 24px; padding-left: 24px;
padding-right: 24px; padding-right: 24px;
padding-bottom: 12px;
} }
</style> </style>
<div class='content'> <paper-card class="content" heading='Node group associations'>
<paper-card heading='Node group associations'>
<div class='device-picker'>
<paper-dropdown-menu label="Node to control" class='flex'>
<paper-listbox
slot="dropdown-content"
selected='{{selectedTargetNode}}'>
<template is='dom-repeat' items='[[nodes]]' as='state'>
<paper-item>[[computeSelectCaption(state)]]</paper-item>
</template>
</paper-listbox>
</paper-dropdown-menu>
</div>
<template is='dom-if' if='[[!computeIsTargetNodeSelected(selectedTargetNode)]]'>
<!--TODO make api for getting groups and members--> <!--TODO make api for getting groups and members-->
<div class='device-picker'> <div class='device-picker'>
<paper-dropdown-menu label="Group" class='flex'> <paper-dropdown-menu label="Group" class='flex'>
@ -58,18 +46,32 @@
</paper-listbox> </paper-listbox>
</paper-dropdown-menu> </paper-dropdown-menu>
</div> </div>
<template is='dom-if' if='[[computeIsGroupSelected(selectedGroup)]]'>
<div class='device-picker'>
<paper-dropdown-menu label="Node to control" class='flex'>
<paper-listbox
slot="dropdown-content"
selected='{{selectedTargetNode}}'>
<template is='dom-repeat' items='[[nodes]]' as='state'>
<paper-item>[[computeSelectCaption(state)]]</paper-item>
</template> </template>
<template is='dom-if' if='[[!computeIsGroupSelected(selectedGroup)]]'> </paper-listbox>
</paper-dropdown-menu>
</div>
<div class='help-text'> <div class='help-text'>
<span>Other Nodes in this group:</span> <span>Other Nodes in this group:</span>
<template is='dom-repeat' items='[[otherGroupNodes]]' as='state'> <template is='dom-repeat' items='[[otherGroupNodes]]' as='state'>
<span>[[state]]</span> <div>[[state]]</div>
</template> </template>
</div> </div>
<div class='help-text'> <div class='help-text'>
<span>Max Associations:</span> <span>Max Associations:</span>
<span>[[maxAssociations]]</span> <span>[[maxAssociations]]</span>
</div> </div>
</template>
<template is='dom-if' if='[[computeIsTargetNodeSelected(selectedTargetNode)]]'>
<div class='card-actions'> <div class='card-actions'>
<template is='dom-if' if='[[!noAssociationsLeft]]'> <template is='dom-if' if='[[!noAssociationsLeft]]'>
<ha-call-service-button <ha-call-service-button
@ -79,16 +81,17 @@
service-data='[[computeAssocServiceData(selectedGroup, "add")]]' service-data='[[computeAssocServiceData(selectedGroup, "add")]]'
>Add To Group</ha-call-service-button> >Add To Group</ha-call-service-button>
</template> </template>
<template is='dom-if' if='[[computeTargetInGroup(selectedGroup, selectedTargetNode)]]'>
<ha-call-service-button <ha-call-service-button
hass='[[hass]]' hass='[[hass]]'
domain='zwave' domain='zwave'
service='change_association' service='change_association'
service-data='[[computeAssocServiceData(selectedGroup, "remove")]]' service-data='[[computeAssocServiceData(selectedGroup, "remove")]]'
>Remove From Group</ha-call-service-button> >Remove From Group</ha-call-service-button>
</template>
</div> </div>
</template> </template>
</paper-card> </paper-card>
</div>
</template> </template>
</dom-module> </dom-module>
@ -164,15 +167,37 @@ Polymer({
computeMaxAssociations: function (selectedGroup) { computeMaxAssociations: function (selectedGroup) {
if (selectedGroup === -1) return -1; if (selectedGroup === -1) return -1;
var maxAssociations = this.groups[selectedGroup].value.max_associations; var maxAssociations = this.groups[selectedGroup].value.max_associations;
if (!maxAssociations) return ['None']; if (!maxAssociations) return 'None';
return maxAssociations; return maxAssociations;
}, },
computeOtherGroupNodes: function (selectedGroup) { computeOtherGroupNodes: function (selectedGroup) {
if (selectedGroup === -1) return -1; if (selectedGroup === -1) return -1;
var associations = Object.values(this.groups[selectedGroup].value.associations); var associations = Object.values(this.groups[selectedGroup].value.association_instances);
if (!associations.length) return ['None']; if (!associations.length) return ['None'];
return associations; return associations.map((assoc) => {
if (!assoc.length || assoc.length !== 2) {
return 'Unknown Node: ' + assoc;
}
const id = assoc[0];
const instance = assoc[1];
const node = this.nodes.find(n => n.attributes.node_id === id);
if (!node) {
return 'Unknown Node (id: ' + (instance ? id + '.' + instance : id) + ')';
}
let caption = this.computeSelectCaption(node);
if (instance) {
caption += '/ Instance: ' + instance;
}
return caption;
});
},
computeTargetInGroup: function (selectedGroup, selectedTargetNode) {
if (selectedGroup === -1 || selectedTargetNode === -1) return false;
const associations = Object.values(this.groups[selectedGroup].value.associations);
if (!associations.length) return false;
return associations.indexOf(this.nodes[selectedTargetNode].attributes.node_id) !== -1;
}, },
computeSelectCaption: function (stateObj) { computeSelectCaption: function (stateObj) {
@ -186,11 +211,11 @@ Polymer({
}, },
computeIsTargetNodeSelected: function (selectedTargetNode) { computeIsTargetNodeSelected: function (selectedTargetNode) {
return (!this.nodes || selectedTargetNode === -1); return this.nodes && selectedTargetNode !== -1;
}, },
computeIsGroupSelected: function (selectedGroup) { computeIsGroupSelected: function (selectedGroup) {
return (!this.nodes || this.selectedNode === -1 || selectedGroup === -1); return this.nodes && this.selectedNode !== -1 && selectedGroup !== -1;
}, },
computeAssocServiceData: function (selectedGroup, type) { computeAssocServiceData: function (selectedGroup, type) {
@ -223,4 +248,3 @@ Polymer({
}, },
}); });
</script> </script>

View File

@ -2,6 +2,8 @@
<link rel="import" href="../../../bower_components/paper-card/paper-card.html"> <link rel="import" href="../../../bower_components/paper-card/paper-card.html">
<link rel="import" href="../../../bower_components/paper-button/paper-button.html"> <link rel="import" href="../../../bower_components/paper-button/paper-button.html">
<link rel="import" href="../ha-config-section.html">
<dom-module id='ozw-log'> <dom-module id='ozw-log'>
<template> <template>
<style include="iron-flex ha-style"> <style include="iron-flex ha-style">
@ -15,7 +17,9 @@
max-width: 600px; max-width: 600px;
} }
</style> </style>
<paper-card heading='OZW Log'> <ha-config-section is-wide='[[isWide]]'>
<span slot='header'>OZW Log</span>
<paper-card>
<div class='help-text'> <div class='help-text'>
<pre>[[ozwLogs]]</pre> <pre>[[ozwLogs]]</pre>
</div> </div>
@ -23,6 +27,7 @@
<paper-button raised on-tap='refreshLog'>Refresh</paper-button> <paper-button raised on-tap='refreshLog'>Refresh</paper-button>
</div> </div>
</paper-card> </paper-card>
</ha-config-section>
</template> </template>
</dom-module> </dom-module>
<script> <script>
@ -35,18 +40,23 @@ Polymer({
type: Object, type: Object,
}, },
isWide: {
type: Boolean,
value: false,
},
ozwLogs: { ozwLogs: {
type: String, type: String,
value: '' value: 'Refresh to pull log'
}, },
}, },
refreshLog: function () { refreshLog: function () {
this.ozwLogs = 'Loading ozw log...'; this.ozwLogs = 'Loading ozw log...';
this.hass.callApi('GET', 'zwave/ozwlog') this.hass.callApi('GET', 'zwave/ozwlog')
.then(function (info) { .then((info) => {
this.ozwLogs = info; this.ozwLogs = info;
}.bind(this)); });
}, },
}); });
</script> </script>

View File

@ -4,6 +4,8 @@
<link rel="import" href="../../../src/components/buttons/ha-call-service-button.html"> <link rel="import" href="../../../src/components/buttons/ha-call-service-button.html">
<link rel="import" href="../../../src/components/ha-service-description.html"> <link rel="import" href="../../../src/components/ha-service-description.html">
<link rel="import" href="../ha-config-section.html">
<dom-module id='zwave-network'> <dom-module id='zwave-network'>
<template> <template>
<style include="iron-flex ha-style"> <style include="iron-flex ha-style">
@ -23,7 +25,7 @@
.toggle-help-icon { .toggle-help-icon {
position: absolute; position: absolute;
top: 6px; top: -6px;
right: 0; right: 0;
color: var(--primary-color); color: var(--primary-color);
} }
@ -37,12 +39,22 @@
display: none; display: none;
} }
</style> </style>
<paper-card heading='Z-Wave Network Management'> <ha-config-section is-wide='[[isWide]]'>
<div style="position: relative" slot='header'>
<span>Z-Wave Network Management</span>
<paper-icon-button <paper-icon-button
class="toggle-help-icon" class="toggle-help-icon"
on-tap='helpTap' on-tap='helpTap'
icon='mdi:help-circle' icon='mdi:help-circle'
></paper-icon-button> ></paper-icon-button>
</div>
<span slot='introduction'>
Run commands that affect the Z-Wave network. You won't get feedback on whether the command succeeded, but you can look in the OZW Log to try to figure out.
</span>
<paper-card class="content">
<div class='card-actions'> <div class='card-actions'>
<ha-call-service-button <ha-call-service-button
hass='[[hass]]' hass='[[hass]]'
@ -152,6 +164,7 @@
</div> </div>
</paper-card> </paper-card>
</ha-config-section>
</template> </template>
</dom-module> </dom-module>
<script> <script>
@ -164,6 +177,11 @@ Polymer({
type: Object, type: Object,
}, },
isWide: {
type: Boolean,
value: false,
},
showDescription: { showDescription: {
type: Boolean, type: Boolean,
value: false, value: false,

View File

@ -17,9 +17,9 @@
<dom-module id="zwave-node-options"> <dom-module id="zwave-node-options">
<template> <template>
<ha-config-section is-wide='[[isWide]]'> <ha-config-section is-wide='[[isWide]]'>
<span slot='header'>Z-Wave</span> <span slot='header'>Z-Wave entities</span>
<span slot='introduction'> <span slot='introduction'>
Z-Wave devices contain a lot of options. These controls will allow you to get into the nitty gritty details. Z-Wave entities contain a lot of options. These controls will allow you to get into the nitty gritty details.
</span> </span>
<ha-entity-config <ha-entity-config