From 424077fdbc51f87738a166d16570b10f23282088 Mon Sep 17 00:00:00 2001 From: Fabio Manganiello Date: Sat, 22 Feb 2020 01:00:52 +0100 Subject: [PATCH] Completed ZWave web panel (see #123) --- .../source/webpanel/plugins/zwave/index.scss | 2 +- .../http/static/js/plugins/zwave/index.js | 104 ++++++++++ .../http/static/js/plugins/zwave/value.js | 22 +- .../http/templates/plugins/zwave/index.html | 87 ++++++-- .../http/templates/plugins/zwave/node.html | 7 + .../http/templates/plugins/zwave/value.html | 190 +++++++++--------- platypush/plugins/zwave/__init__.py | 22 +- 7 files changed, 302 insertions(+), 132 deletions(-) diff --git a/platypush/backend/http/static/css/source/webpanel/plugins/zwave/index.scss b/platypush/backend/http/static/css/source/webpanel/plugins/zwave/index.scss index 42092210a..1bc977abb 100644 --- a/platypush/backend/http/static/css/source/webpanel/plugins/zwave/index.scss +++ b/platypush/backend/http/static/css/source/webpanel/plugins/zwave/index.scss @@ -243,7 +243,7 @@ color: $error-color; } - .node { + .node, .scene { .actions { .row { cursor: pointer; diff --git a/platypush/backend/http/static/js/plugins/zwave/index.js b/platypush/backend/http/static/js/plugins/zwave/index.js index 8c1e75507..2f27231be 100644 --- a/platypush/backend/http/static/js/plugins/zwave/index.js +++ b/platypush/backend/http/static/js/plugins/zwave/index.js @@ -28,6 +28,7 @@ Vue.component('zwave', { nodeId: undefined, groupId: undefined, sceneId: undefined, + valueId: undefined, }, loading: { status: false, @@ -47,6 +48,17 @@ Vue.component('zwave', { }, computed: { + valuesMap: function() { + const values = {}; + for (const node of Object.values(this.nodes)) { + for (const value of Object.values(node.values)) { + values[value.id_on_network] = value; + } + } + + return values; + }, + networkDropdownItems: function() { const self = this; return [ @@ -192,6 +204,32 @@ Vue.component('zwave', { }, ] }, + + addToSceneDropdownItems: function() { + const self = this; + return Object.values(this.scenes).filter((scene) => { + return !scene.values || !scene.values.length || !(this.selected.valueId in this.scene.values); + }).map((scene) => { + return { + text: scene.label, + disabled: this.commandRunning, + click: async function () { + if (!self.selected.valueId) { + return; + } + + self.commandRunning = true; + await request('zwave.scene_add_value', { + id_on_network: self.selected.valueId, + scene_id: scene.scene_id, + }); + + self.commandRunning = false; + self.refresh(); + }, + }; + }); + }, }, methods: { @@ -274,6 +312,29 @@ Vue.component('zwave', { this.refreshStatus(); }, + addScene: async function() { + const name = prompt('Scene name'); + if (!name) { + return; + } + + this.commandRunning = true; + await request('zwave.create_scene', {label: name}); + this.commandRunning = false; + this.refreshScenes(); + }, + + removeScene: async function(sceneId) { + if (!confirm('Are you sure that you want to delete this scene?')) { + return; + } + + this.commandRunning = true; + await request('zwave.remove_scene', {scene_id: sceneId}); + this.commandRunning = false; + this.refreshScenes(); + }, + onNodeUpdate: function(event) { Vue.set(this.nodes, event.node.node_id, event.node); }, @@ -290,6 +351,10 @@ Vue.component('zwave', { Vue.set(this.selected, 'groupId', event.groupId === this.selected.groupId ? undefined : event.groupId); }, + onSceneClicked: function(event) { + Vue.set(this.selected, 'sceneId', event.sceneId === this.selected.sceneId ? undefined : event.sceneId); + }, + onNetworkInfoModalOpen: function() { this.refreshStatus(); this.modal.networkInfo.visible = true; @@ -308,6 +373,11 @@ Vue.component('zwave', { openDropdown(this.$refs.networkCommandsDropdown); }, + openAddToSceneDropdown: function(event) { + this.selected.valueId = event.valueId; + openDropdown(this.$refs.addToSceneDropdown); + }, + addNode: async function() { this.commandRunning = true; await request('zwave.add_node'); @@ -330,6 +400,38 @@ Vue.component('zwave', { await request('zwave.remove_node'); this.commandRunning = false; }, + + removeNodeFromScene: async function(event) { + if (!confirm('Are you sure that you want to remove this value from the scene?')) { + return; + } + + this.commandRunning = true; + await request('zwave.scene_remove_value', { + id_on_network: event.valueId, + scene_id: event.sceneId, + }); + + this.commandRunning = false; + }, + + renameScene: async function(sceneId) { + const scene = this.scenes[sceneId]; + const name = prompt('New name', scene.label); + + if (!name || !name.length || name === scene.label) { + return; + } + + this.commandRunning = true; + await request('zwave.set_scene_label', { + new_label: name, + scene_id: sceneId, + }); + + this.commandRunning = false; + this.refreshScenes(); + }, }, created: function() { @@ -339,6 +441,8 @@ Vue.component('zwave', { this.bus.$on('nodeClicked', this.onNodeClicked); this.bus.$on('groupClicked', this.onGroupClicked); this.bus.$on('openAddToGroupModal', () => {self.modal.group.visible = true}); + this.bus.$on('openAddToSceneDropdown', this.openAddToSceneDropdown); + this.bus.$on('removeFromScene', this.removeNodeFromScene); registerEventHandler(this.refreshGroups, 'platypush.message.event.zwave.ZwaveNodeGroupEvent'); registerEventHandler(this.refreshScenes, 'platypush.message.event.zwave.ZwaveNodeSceneEvent'); diff --git a/platypush/backend/http/static/js/plugins/zwave/value.js b/platypush/backend/http/static/js/plugins/zwave/value.js index 90adf5b44..a1f85081d 100644 --- a/platypush/backend/http/static/js/plugins/zwave/value.js +++ b/platypush/backend/http/static/js/plugins/zwave/value.js @@ -1,18 +1,11 @@ Vue.component('zwave-value', { template: '#tmpl-zwave-value', - props: ['node','bus','selected','values'], + props: ['value','node','bus','selected','sceneId'], data: function() { - return { - }; + return {}; }, methods: { - onNodeClicked: function() { - this.bus.$emit('nodeClicked', { - nodeId: this.node.node_id, - }); - }, - disableForm: function(form) { form.querySelector('input,button').readOnly = true; }, @@ -21,17 +14,6 @@ Vue.component('zwave-value', { form.querySelector('input,button').readOnly = false; }, - onEditMode: function(mode) { - Vue.set(this.editMode, mode, true); - const form = this.$refs[mode + 'Form']; - const input = form.querySelector('input[type=text]'); - - setTimeout(() => { - input.focus(); - input.select(); - }, 10); - }, - editName: function(event) { const value = this.node.values[event.target.parentElement.dataset.idOnNetwork]; const name = prompt('New name', value.label); diff --git a/platypush/backend/http/templates/plugins/zwave/index.html b/platypush/backend/http/templates/plugins/zwave/index.html index 5a2b6ebb8..709c60d95 100644 --- a/platypush/backend/http/templates/plugins/zwave/index.html +++ b/platypush/backend/http/templates/plugins/zwave/index.html @@ -31,7 +31,7 @@ @@ -88,12 +88,56 @@
No scenes configured on the network
- - - - - - +
+
+ +
+
+
Activate
+
+ +
+
+ +
+
+
Actions
+
+ +
+
+
Remove Scene
+
+ +
+
+ +
+
Rename Scene
+
+ +
+
+
+
+ +
+ + +
+
+
@@ -102,15 +146,26 @@
No nodes found on the network
- - +
+
+ +
+ + +
+
+ + diff --git a/platypush/backend/http/templates/plugins/zwave/node.html b/platypush/backend/http/templates/plugins/zwave/node.html index ea59ba14b..2ca113822 100644 --- a/platypush/backend/http/templates/plugins/zwave/node.html +++ b/platypush/backend/http/templates/plugins/zwave/node.html @@ -54,6 +54,13 @@
+
+
Neighbours
+
+
+
+
+
Is Ready
diff --git a/platypush/backend/http/templates/plugins/zwave/value.html b/platypush/backend/http/templates/plugins/zwave/value.html index 8f1a57f7b..c5183b2e9 100644 --- a/platypush/backend/http/templates/plugins/zwave/value.html +++ b/platypush/backend/http/templates/plugins/zwave/value.html @@ -1,107 +1,113 @@ diff --git a/platypush/plugins/zwave/__init__.py b/platypush/plugins/zwave/__init__.py index 7a2cb61c7..cd7b7f05f 100644 --- a/platypush/plugins/zwave/__init__.py +++ b/platypush/plugins/zwave/__init__.py @@ -228,6 +228,7 @@ class ZwavePlugin(Plugin): 'manufacturer_id': node.manufacturer_id, 'manufacturer_name': node.manufacturer_name, 'max_baud_rate': node.max_baud_rate, + 'neighbours': [node_id for node_id in node.neighbors], 'name': node.name, 'outdated': node.outdated, 'product_id': node.product_id, @@ -743,7 +744,11 @@ class ZwavePlugin(Plugin): """ Get the scenes configured on the network. """ - return self._get_network().scenes_to_dict() + network = self._get_network() + if not network.get_scenes(): + return {} + + return network.scenes_to_dict() @action def create_scene(self, label: str): @@ -753,6 +758,7 @@ class ZwavePlugin(Plugin): :param label: Scene label. """ self._get_network().create_scene(label) + self.write_config() @action def remove_scene(self, scene_id: Optional[int] = None, scene_label: Optional[str] = None): @@ -764,6 +770,7 @@ class ZwavePlugin(Plugin): """ scene = self._get_scene(scene_id=scene_id, scene_label=scene_label) self._get_network().remove_scene(scene.scene_id) + self.write_config() @action def activate_scene(self, scene_id: Optional[int] = None, scene_label: Optional[str] = None): @@ -790,14 +797,19 @@ class ZwavePlugin(Plugin): self.write_config() @action - def scene_add_value(self, data, value_id: Optional[int] = None, id_on_network: Optional[str] = None, + def scene_add_value(self, data: Optional[Any] = None, + value_id: Optional[int] = None, id_on_network: Optional[str] = None, value_label: Optional[str] = None, scene_id: Optional[int] = None, scene_label: Optional[str] = None, node_id: Optional[int] = None, node_name: Optional[str] = None): """ Add a value to a scene. - :param data: Data to set for the value. + WARNING: This method actually doesn't work, by own admission of the + :ref:`OpenZWave developer `_ + + + :param data: Data to set for the value (default: current value data). :param value_id: Select value by value_id. :param id_on_network: Select value by id_on_network. :param value_label: Select value by [node_id/node_name, value_label] @@ -809,6 +821,10 @@ class ZwavePlugin(Plugin): value = self._get_value(value_id=value_id, id_on_network=id_on_network, node_id=node_id, node_name=node_name, value_label=value_label) scene = self._get_scene(scene_id=scene_id, scene_label=scene_label) + data = data if data is not None else value.data + data = value.check_data(data) + assert data is not None, 'Invalid value passed to the property' + scene.add_value(value.value_id, data) self.write_config()