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,23 +277,24 @@
config='[[config]]' config='[[config]]'
></zwave-node-config> ></zwave-node-config>
</template> </template>
<!--User Codes--> </ha-config-section>
<template is='dom-if' if='{{hasNodeUserCodes}}'>
<zwave-usercodes <!--User Codes-->
id='zwave-usercodes' <template is='dom-if' if='{{hasNodeUserCodes}}'>
hass='[[hass]]' <zwave-usercodes
nodes='[[nodes]]' id='zwave-usercodes'
user-codes='[[userCodes]]' hass='[[hass]]'
selected-node='[[selectedNode]]' nodes='[[nodes]]'
></zwave-usercodes> user-codes='[[userCodes]]'
</template> selected-node='[[selectedNode]]'
<!--Ozw log--> ></zwave-usercodes>
<div class='content'> </template>
<ozw-log
id='ozw-log' <!--Ozw log-->
hass='[[hass]]' <ozw-log
></ozw-log> is-wide='[[isWide]]'
</div> hass='[[hass]]'
></ozw-log>
</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,65 +30,68 @@
.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'> <!--TODO make api for getting groups and members-->
<div class='device-picker'> <div class='device-picker'>
<paper-dropdown-menu label="Group" class='flex'>
<paper-listbox
slot="dropdown-content"
selected='{{selectedGroup}}'>
<template is='dom-repeat' items='[[groups]]' as='state'>
<paper-item>[[computeSelectCaptionGroup(state)]]</paper-item>
</template>
</paper-listbox>
</paper-dropdown-menu>
</div>
<template is='dom-if' if='[[computeIsGroupSelected(selectedGroup)]]'>
<div class='device-picker'>
<paper-dropdown-menu label="Node to control" class='flex'> <paper-dropdown-menu label="Node to control" class='flex'>
<paper-listbox <paper-listbox
slot="dropdown-content" slot="dropdown-content"
selected='{{selectedTargetNode}}'> selected='{{selectedTargetNode}}'>
<template is='dom-repeat' items='[[nodes]]' as='state'> <template is='dom-repeat' items='[[nodes]]' as='state'>
<paper-item>[[computeSelectCaption(state)]]</paper-item> <paper-item>[[computeSelectCaption(state)]]</paper-item>
</template> </template>
</paper-listbox> </paper-listbox>
</paper-dropdown-menu> </paper-dropdown-menu>
</div> </div>
<template is='dom-if' if='[[!computeIsTargetNodeSelected(selectedTargetNode)]]'>
<!--TODO make api for getting groups and members--> <div class='help-text'>
<div class='device-picker'> <span>Other Nodes in this group:</span>
<paper-dropdown-menu label="Group" class='flex'> <template is='dom-repeat' items='[[otherGroupNodes]]' as='state'>
<paper-listbox <div>[[state]]</div>
slot="dropdown-content" </template>
selected='{{selectedGroup}}'> </div>
<template is='dom-repeat' items='[[groups]]' as='state'> <div class='help-text'>
<paper-item>[[computeSelectCaptionGroup(state)]]</paper-item> <span>Max Associations:</span>
</template> <span>[[maxAssociations]]</span>
</paper-listbox> </div>
</paper-dropdown-menu> </template>
</div>
</template> <template is='dom-if' if='[[computeIsTargetNodeSelected(selectedTargetNode)]]'>
<template is='dom-if' if='[[!computeIsGroupSelected(selectedGroup)]]'> <div class='card-actions'>
<div class='help-text'> <template is='dom-if' if='[[!noAssociationsLeft]]'>
<span>Other Nodes in this group:</span> <ha-call-service-button
<template is='dom-repeat' items='[[otherGroupNodes]]' as='state'>
<span>[[state]]</span>
</template>
</div>
<div class='help-text'>
<span>Max Associations:</span>
<span>[[maxAssociations]]</span>
</div>
<div class='card-actions'>
<template is='dom-if' if='[[!noAssociationsLeft]]'>
<ha-call-service-button
hass='[[hass]]' hass='[[hass]]'
domain='zwave' domain='zwave'
service='change_association' service='change_association'
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>
<ha-call-service-button <template is='dom-if' if='[[computeTargetInGroup(selectedGroup, selectedTargetNode)]]'>
hass='[[hass]]' <ha-call-service-button
domain='zwave' hass='[[hass]]'
service='change_association' domain='zwave'
service-data='[[computeAssocServiceData(selectedGroup, "remove")]]' service='change_association'
>Remove From Group</ha-call-service-button> service-data='[[computeAssocServiceData(selectedGroup, "remove")]]'
>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,14 +17,17 @@
max-width: 600px; max-width: 600px;
} }
</style> </style>
<paper-card heading='OZW Log'> <ha-config-section is-wide='[[isWide]]'>
<div class='help-text'> <span slot='header'>OZW Log</span>
<pre>[[ozwLogs]]</pre> <paper-card>
</div> <div class='help-text'>
<div class="card-actions"> <pre>[[ozwLogs]]</pre>
<paper-button raised on-tap='refreshLog'>Refresh</paper-button> </div>
</div> <div class="card-actions">
</paper-card> <paper-button raised on-tap='refreshLog'>Refresh</paper-button>
</div>
</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,121 +39,132 @@
display: none; display: none;
} }
</style> </style>
<paper-card heading='Z-Wave Network Management'> <ha-config-section is-wide='[[isWide]]'>
<paper-icon-button <div style="position: relative" slot='header'>
class="toggle-help-icon" <span>Z-Wave Network Management</span>
on-tap='helpTap' <paper-icon-button
icon='mdi:help-circle' class="toggle-help-icon"
></paper-icon-button> on-tap='helpTap'
<div class='card-actions'> icon='mdi:help-circle'
<ha-call-service-button ></paper-icon-button>
hass='[[hass]]'
domain='zwave'
service='add_node_secure'
>Add Node Secure</ha-call-service-button>
<ha-service-description
hass='[[hass]]'
domain='zwave'
service='add_node_secure'
hidden$='[[!showDescription]]'
></ha-service-description>
<ha-call-service-button
hass='[[hass]]'
domain='zwave'
service='add_node'
>Add Node</ha-call-service-button>
<ha-service-description
hass='[[hass]]'
domain='zwave'
service='add_node'
hidden$='[[!showDescription]]'
></ha-service-description>
<ha-call-service-button
hass='[[hass]]'
domain='zwave'
service='remove_node'
>Remove Node</ha-call-service-button>
<ha-service-description
hass='[[hass]]'
domain='zwave'
service='remove_node'
hidden$='[[!showDescription]]'
></ha-service-description>
</div> </div>
<div class='card-actions warning'> <span slot='introduction'>
<ha-call-service-button 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.
hass='[[hass]]' </span>
domain='zwave'
service='cancel_command'
>Cancel Command</ha-call-service-button>
<ha-service-description
hass='[[hass]]'
domain='zwave'
service='cancel_command'
hidden$='[[!showDescription]]'
></ha-service-description>
</div>
<div class='card-actions'>
<ha-call-service-button
hass='[[hass]]'
domain='zwave'
service='heal_network'
>Heal Network</ha-call-service-button>
<ha-call-service-button <paper-card class="content">
hass='[[hass]]' <div class='card-actions'>
domain='zwave' <ha-call-service-button
service='start_network' hass='[[hass]]'
>Start Network</ha-call-service-button> domain='zwave'
<ha-service-description service='add_node_secure'
hass='[[hass]]' >Add Node Secure</ha-call-service-button>
domain='zwave' <ha-service-description
service='start_network' hass='[[hass]]'
hidden$='[[!showDescription]]' domain='zwave'
></ha-service-description> service='add_node_secure'
hidden$='[[!showDescription]]'
></ha-service-description>
<ha-call-service-button <ha-call-service-button
hass='[[hass]]' hass='[[hass]]'
domain='zwave' domain='zwave'
service='stop_network' service='add_node'
>Stop Network</ha-call-service-button> >Add Node</ha-call-service-button>
<ha-service-description <ha-service-description
hass='[[hass]]' hass='[[hass]]'
domain='zwave' domain='zwave'
service='stop_network' service='add_node'
hidden$='[[!showDescription]]' hidden$='[[!showDescription]]'
></ha-service-description> ></ha-service-description>
<ha-call-service-button <ha-call-service-button
hass='[[hass]]' hass='[[hass]]'
domain='zwave' domain='zwave'
service='soft_reset' service='remove_node'
>Soft Reset</ha-call-service-button> >Remove Node</ha-call-service-button>
<ha-service-description <ha-service-description
hass='[[hass]]' hass='[[hass]]'
domain='zwave' domain='zwave'
service='soft_reset' service='remove_node'
hidden$='[[!showDescription]]' hidden$='[[!showDescription]]'
></ha-service-description> ></ha-service-description>
<ha-call-service-button </div>
hass='[[hass]]' <div class='card-actions warning'>
domain='zwave' <ha-call-service-button
service='test_network' hass='[[hass]]'
>Test Network</ha-call-service-button> domain='zwave'
<ha-service-description service='cancel_command'
hass='[[hass]]' >Cancel Command</ha-call-service-button>
domain='zwave' <ha-service-description
service='test_network' hass='[[hass]]'
hidden$='[[!showDescription]]' domain='zwave'
></ha-service-description> service='cancel_command'
hidden$='[[!showDescription]]'
></ha-service-description>
</div> </div>
</paper-card> <div class='card-actions'>
<ha-call-service-button
hass='[[hass]]'
domain='zwave'
service='heal_network'
>Heal Network</ha-call-service-button>
<ha-call-service-button
hass='[[hass]]'
domain='zwave'
service='start_network'
>Start Network</ha-call-service-button>
<ha-service-description
hass='[[hass]]'
domain='zwave'
service='start_network'
hidden$='[[!showDescription]]'
></ha-service-description>
<ha-call-service-button
hass='[[hass]]'
domain='zwave'
service='stop_network'
>Stop Network</ha-call-service-button>
<ha-service-description
hass='[[hass]]'
domain='zwave'
service='stop_network'
hidden$='[[!showDescription]]'
></ha-service-description>
<ha-call-service-button
hass='[[hass]]'
domain='zwave'
service='soft_reset'
>Soft Reset</ha-call-service-button>
<ha-service-description
hass='[[hass]]'
domain='zwave'
service='soft_reset'
hidden$='[[!showDescription]]'
></ha-service-description>
<ha-call-service-button
hass='[[hass]]'
domain='zwave'
service='test_network'
>Test Network</ha-call-service-button>
<ha-service-description
hass='[[hass]]'
domain='zwave'
service='test_network'
hidden$='[[!showDescription]]'
></ha-service-description>
</div>
</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