Added dimmer entities

This commit is contained in:
Fabio Manganiello 2022-10-23 00:30:32 +02:00
parent d7278857e5
commit 951950c864
Signed by: blacklight
GPG Key ID: D90FBA7F76362774
5 changed files with 509 additions and 115 deletions

View File

@ -0,0 +1,124 @@
<template>
<div class="entity dimmer-container">
<div class="head" :class="{expanded: expanded}">
<div class="col-1 icon">
<EntityIcon
:icon="this.value.meta?.icon || {}"
:loading="loading"
:error="error" />
</div>
<div class="col-s-8 col-m-9 label">
<div class="name" v-text="value.name" />
</div>
<div class="col-s-3 col-m-2 buttons pull-right">
<button @click.stop="expanded = !expanded">
<i class="fas"
:class="{'fa-angle-up': expanded, 'fa-angle-down': !expanded}" />
</button>
<span class="value-percent"
v-text="valuePercent.toFixed(0) + '%'"
v-if="valuePercent != null" />
</div>
</div>
<div class="body" v-if="expanded" @click.stop="prevent">
<div class="row">
<div class="input">
<Slider :range="[value.min, value.max]"
:value="value.value" @input="setValue" />
</div>
</div>
</div>
</div>
</template>
<script>
import Slider from "@/components/elements/Slider"
import EntityMixin from "./EntityMixin"
import EntityIcon from "./EntityIcon"
export default {
name: 'Dimmer',
components: {Slider, EntityIcon},
mixins: [EntityMixin],
data() {
return {
expanded: false,
}
},
computed: {
valuePercent() {
if (this.value?.is_write_only || this.value?.value == null)
return null
const min = this.value.min || 0
const max = this.value.max || 100
return (100 * this.value.value) / (max - min)
}
},
methods: {
prevent(event) {
event.stopPropagation()
return false
},
async setValue(event) {
this.$emit('loading', true)
try {
await this.request('entities.execute', {
id: this.value.id,
action: 'set_value',
data: +event.target.value,
})
} finally {
this.$emit('loading', false)
}
},
},
}
</script>
<style lang="scss" scoped>
@import "common";
.dimmer-container {
.head {
.buttons {
button {
margin-right: 0.5em;
}
}
.value-percent {
font-size: 1.1em;
font-weight: bold;
opacity: 0.7;
}
}
.body {
.row {
display: flex;
.icon {
width: 2em;
text-align: center;
}
.input {
width: calc(100% - 2em);
:deep(.slider) {
margin-top: 0.5em;
}
}
}
}
}
</style>

View File

@ -29,5 +29,13 @@
"icon": {
"class": "fas fa-lightbulb"
}
},
"dimmer": {
"name": "Dimmer",
"name_plural": "Dimmers",
"icon": {
"class": "fas fa-gauge"
}
}
}

View File

@ -0,0 +1,25 @@
from sqlalchemy import Column, Integer, ForeignKey, Float
from .devices import Device, entity_types_registry
if not entity_types_registry.get('Dimmer'):
class Dimmer(Device):
__tablename__ = 'dimmer'
id = Column(
Integer, ForeignKey(Device.id, ondelete='CASCADE'), primary_key=True
)
min = Column(Float)
max = Column(Float)
step = Column(Float, default=1.0)
value = Column(Float)
__mapper_args__ = {
'polymorphic_identity': __tablename__,
}
entity_types_registry['Dimmer'] = Dimmer
else:
Dimmer = entity_types_registry['Dimmer']

View File

@ -1,11 +1,15 @@
from abc import ABC, abstractmethod
from typing import Any, Dict, Optional, List, Union
from platypush.plugins import action
from platypush.plugins.switch import SwitchPlugin
from platypush.entities import manages
from platypush.entities.dimmers import Dimmer
from platypush.entities.lights import Light
from platypush.entities.switches import Switch
from platypush.plugins import Plugin, action
class ZwaveBasePlugin(SwitchPlugin, ABC):
@manages(Dimmer, Light, Switch)
class ZwaveBasePlugin(Plugin, ABC):
"""
Base class for Z-Wave plugins.
"""
@ -46,7 +50,9 @@ class ZwaveBasePlugin(SwitchPlugin, ABC):
@abstractmethod
@action
def remove_failed_node(self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs):
def remove_failed_node(
self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs
):
"""
Remove a failed node from the network.
@ -57,7 +63,9 @@ class ZwaveBasePlugin(SwitchPlugin, ABC):
@abstractmethod
@action
def replace_failed_node(self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs):
def replace_failed_node(
self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs
):
"""
Replace a failed node on the network.
@ -68,7 +76,9 @@ class ZwaveBasePlugin(SwitchPlugin, ABC):
@abstractmethod
@action
def replication_send(self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs):
def replication_send(
self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs
):
"""
Send node information from the primary to the secondary controller.
@ -79,7 +89,9 @@ class ZwaveBasePlugin(SwitchPlugin, ABC):
@abstractmethod
@action
def request_network_update(self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs):
def request_network_update(
self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs
):
"""
Request a network update to a node.
@ -90,7 +102,9 @@ class ZwaveBasePlugin(SwitchPlugin, ABC):
@abstractmethod
@action
def request_node_neighbour_update(self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs):
def request_node_neighbour_update(
self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs
):
"""
Request a neighbours list update to a node.
@ -101,7 +115,9 @@ class ZwaveBasePlugin(SwitchPlugin, ABC):
@abstractmethod
@action
def get_nodes(self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs) -> Dict[str, Any]:
def get_nodes(
self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs
) -> Dict[str, Any]:
"""
Get the nodes associated to the network.
@ -112,8 +128,9 @@ class ZwaveBasePlugin(SwitchPlugin, ABC):
@abstractmethod
@action
def get_node_stats(self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs) \
-> Dict[str, Any]:
def get_node_stats(
self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs
) -> Dict[str, Any]:
"""
Get the statistics of a node on the network.
@ -124,7 +141,12 @@ class ZwaveBasePlugin(SwitchPlugin, ABC):
@abstractmethod
@action
def set_node_name(self, new_name: str, node_id: Optional[int] = None, node_name: Optional[str] = None):
def set_node_name(
self,
new_name: str,
node_id: Optional[int] = None,
node_name: Optional[str] = None,
):
"""
Rename a node on the network.
@ -136,8 +158,13 @@ class ZwaveBasePlugin(SwitchPlugin, ABC):
@abstractmethod
@action
def set_node_product_name(self, product_name: str, node_id: Optional[int] = None, node_name: Optional[str] = None,
**kwargs):
def set_node_product_name(
self,
product_name: str,
node_id: Optional[int] = None,
node_name: Optional[str] = None,
**kwargs
):
"""
Set the product name of a node.
@ -149,8 +176,13 @@ class ZwaveBasePlugin(SwitchPlugin, ABC):
@abstractmethod
@action
def set_node_manufacturer_name(self, manufacturer_name: str, node_id: Optional[int] = None,
node_name: Optional[str] = None, **kwargs):
def set_node_manufacturer_name(
self,
manufacturer_name: str,
node_id: Optional[int] = None,
node_name: Optional[str] = None,
**kwargs
):
"""
Set the manufacturer name of a node.
@ -162,8 +194,13 @@ class ZwaveBasePlugin(SwitchPlugin, ABC):
@abstractmethod
@action
def set_node_location(self, location: str, node_id: Optional[int] = None, node_name: Optional[str] = None,
**kwargs):
def set_node_location(
self,
location: str,
node_id: Optional[int] = None,
node_name: Optional[str] = None,
**kwargs
):
"""
Set the location of a node.
@ -256,9 +293,15 @@ class ZwaveBasePlugin(SwitchPlugin, ABC):
@abstractmethod
@action
def get_value(self, value_id: Optional[int] = None, id_on_network: Optional[str] = None,
value_label: Optional[str] = None, node_id: Optional[int] = None, node_name: Optional[str] = None,
**kwargs) -> Dict[str, Any]:
def get_value(
self,
value_id: Optional[int] = None,
id_on_network: Optional[str] = None,
value_label: Optional[str] = None,
node_id: Optional[int] = None,
node_name: Optional[str] = None,
**kwargs
) -> Dict[str, Any]:
"""
Get a value on the network.
@ -272,9 +315,16 @@ class ZwaveBasePlugin(SwitchPlugin, ABC):
@abstractmethod
@action
def set_value(self, data, value_id: Optional[int] = None, id_on_network: Optional[str] = None,
value_label: Optional[str] = None, node_id: Optional[int] = None, node_name: Optional[str] = None,
**kwargs):
def set_value(
self,
data,
value_id: Optional[int] = None,
id_on_network: Optional[str] = None,
value_label: Optional[str] = None,
node_id: Optional[int] = None,
node_name: Optional[str] = None,
**kwargs
):
"""
Set a value.
@ -289,9 +339,16 @@ class ZwaveBasePlugin(SwitchPlugin, ABC):
@abstractmethod
@action
def set_value_label(self, new_label: str, value_id: Optional[int] = None, id_on_network: Optional[str] = None,
value_label: Optional[str] = None, node_id: Optional[int] = None,
node_name: Optional[str] = None, **kwargs):
def set_value_label(
self,
new_label: str,
value_id: Optional[int] = None,
id_on_network: Optional[str] = None,
value_label: Optional[str] = None,
node_id: Optional[int] = None,
node_name: Optional[str] = None,
**kwargs
):
"""
Change the label/name of a value.
@ -306,9 +363,15 @@ class ZwaveBasePlugin(SwitchPlugin, ABC):
@abstractmethod
@action
def node_add_value(self, value_id: Optional[int] = None, id_on_network: Optional[str] = None,
value_label: Optional[str] = None, node_id: Optional[int] = None,
node_name: Optional[str] = None, **kwargs):
def node_add_value(
self,
value_id: Optional[int] = None,
id_on_network: Optional[str] = None,
value_label: Optional[str] = None,
node_id: Optional[int] = None,
node_name: Optional[str] = None,
**kwargs
):
"""
Add a value to a node.
@ -322,9 +385,15 @@ class ZwaveBasePlugin(SwitchPlugin, ABC):
@abstractmethod
@action
def node_remove_value(self, value_id: Optional[int] = None, id_on_network: Optional[str] = None,
value_label: Optional[str] = None, node_id: Optional[int] = None,
node_name: Optional[str] = None, **kwargs):
def node_remove_value(
self,
value_id: Optional[int] = None,
id_on_network: Optional[str] = None,
value_label: Optional[str] = None,
node_id: Optional[int] = None,
node_name: Optional[str] = None,
**kwargs
):
"""
Remove a value from a node.
@ -338,8 +407,13 @@ class ZwaveBasePlugin(SwitchPlugin, ABC):
@abstractmethod
@action
def node_heal(self, node_id: Optional[int] = None, node_name: Optional[str] = None, refresh_routes: bool = False,
**kwargs):
def node_heal(
self,
node_id: Optional[int] = None,
node_name: Optional[str] = None,
refresh_routes: bool = False,
**kwargs
):
"""
Heal network node by requesting the node to rediscover their neighbours.
@ -351,7 +425,9 @@ class ZwaveBasePlugin(SwitchPlugin, ABC):
@abstractmethod
@action
def node_update_neighbours(self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs):
def node_update_neighbours(
self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs
):
"""
Ask a node to update its neighbours table.
@ -362,7 +438,9 @@ class ZwaveBasePlugin(SwitchPlugin, ABC):
@abstractmethod
@action
def node_network_update(self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs):
def node_network_update(
self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs
):
"""
Update the controller with network information.
@ -373,7 +451,9 @@ class ZwaveBasePlugin(SwitchPlugin, ABC):
@abstractmethod
@action
def node_refresh_info(self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs):
def node_refresh_info(
self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs
):
"""
Fetch up-to-date information about the node.
@ -384,7 +464,9 @@ class ZwaveBasePlugin(SwitchPlugin, ABC):
@abstractmethod
@action
def get_dimmers(self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs) -> Dict[int, Any]:
def get_dimmers(
self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs
) -> Dict[int, Any]:
"""
Get the dimmers on the network or associated to a node.
@ -395,8 +477,9 @@ class ZwaveBasePlugin(SwitchPlugin, ABC):
@abstractmethod
@action
def get_node_config(self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs) \
-> Dict[int, Any]:
def get_node_config(
self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs
) -> Dict[int, Any]:
"""
Get the configuration values of a node or of all the nodes on the network.
@ -407,8 +490,9 @@ class ZwaveBasePlugin(SwitchPlugin, ABC):
@abstractmethod
@action
def get_battery_levels(self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs) \
-> Dict[int, Any]:
def get_battery_levels(
self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs
) -> Dict[int, Any]:
"""
Get the battery levels of a node or of all the nodes on the network.
@ -419,8 +503,9 @@ class ZwaveBasePlugin(SwitchPlugin, ABC):
@abstractmethod
@action
def get_power_levels(self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs) \
-> Dict[int, Any]:
def get_power_levels(
self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs
) -> Dict[int, Any]:
"""
Get the power levels of this node.
@ -431,7 +516,9 @@ class ZwaveBasePlugin(SwitchPlugin, ABC):
@abstractmethod
@action
def get_bulbs(self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs) -> Dict[int, Any]:
def get_bulbs(
self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs
) -> Dict[int, Any]:
"""
Get the bulbs/LEDs on the network or associated to a node.
@ -442,7 +529,9 @@ class ZwaveBasePlugin(SwitchPlugin, ABC):
@abstractmethod
@action
def get_switches(self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs) -> Dict[int, Any]:
def get_switches(
self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs
) -> Dict[int, Any]:
"""
Get the switches on the network or associated to a node.
@ -453,7 +542,9 @@ class ZwaveBasePlugin(SwitchPlugin, ABC):
@abstractmethod
@action
def get_sensors(self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs) -> Dict[int, Any]:
def get_sensors(
self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs
) -> Dict[int, Any]:
"""
Get the sensors on the network or associated to a node.
@ -464,7 +555,9 @@ class ZwaveBasePlugin(SwitchPlugin, ABC):
@abstractmethod
@action
def get_doorlocks(self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs) -> Dict[int, Any]:
def get_doorlocks(
self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs
) -> Dict[int, Any]:
"""
Get the doorlocks on the network or associated to a node.
@ -475,7 +568,9 @@ class ZwaveBasePlugin(SwitchPlugin, ABC):
@abstractmethod
@action
def get_usercodes(self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs) -> Dict[int, Any]:
def get_usercodes(
self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs
) -> Dict[int, Any]:
"""
Get the usercodes on the network or associated to a node.
@ -486,8 +581,9 @@ class ZwaveBasePlugin(SwitchPlugin, ABC):
@abstractmethod
@action
def get_thermostats(self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs) \
-> Dict[int, Any]:
def get_thermostats(
self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs
) -> Dict[int, Any]:
"""
Get the thermostats on the network or associated to a node.
@ -498,8 +594,9 @@ class ZwaveBasePlugin(SwitchPlugin, ABC):
@abstractmethod
@action
def get_protections(self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs) \
-> Dict[int, Any]:
def get_protections(
self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs
) -> Dict[int, Any]:
"""
Get the protection-compatible devices on the network or associated to a node.
@ -536,7 +633,12 @@ class ZwaveBasePlugin(SwitchPlugin, ABC):
@abstractmethod
@action
def remove_scene(self, scene_id: Optional[int] = None, scene_label: Optional[str] = None, **kwargs):
def remove_scene(
self,
scene_id: Optional[int] = None,
scene_label: Optional[str] = None,
**kwargs
):
"""
Remove a scene.
@ -547,7 +649,12 @@ class ZwaveBasePlugin(SwitchPlugin, ABC):
@abstractmethod
@action
def activate_scene(self, scene_id: Optional[int] = None, scene_label: Optional[str] = None, **kwargs):
def activate_scene(
self,
scene_id: Optional[int] = None,
scene_label: Optional[str] = None,
**kwargs
):
"""
Activate a scene.
@ -558,8 +665,13 @@ class ZwaveBasePlugin(SwitchPlugin, ABC):
@abstractmethod
@action
def set_scene_label(self, new_label: str, scene_id: Optional[int] = None, scene_label: Optional[str] = None,
**kwargs):
def set_scene_label(
self,
new_label: str,
scene_id: Optional[int] = None,
scene_label: Optional[str] = None,
**kwargs
):
"""
Rename a scene/set the scene label.
@ -571,11 +683,18 @@ class ZwaveBasePlugin(SwitchPlugin, ABC):
@abstractmethod
@action
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, **kwargs):
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,
**kwargs
):
"""
Add a value to a scene.
@ -592,10 +711,17 @@ class ZwaveBasePlugin(SwitchPlugin, ABC):
@abstractmethod
@action
def scene_remove_value(self, 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, **kwargs):
def scene_remove_value(
self,
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,
**kwargs
):
"""
Remove a value from a scene.
@ -611,19 +737,12 @@ class ZwaveBasePlugin(SwitchPlugin, ABC):
@abstractmethod
@action
def get_scene_values(self, scene_id: Optional[int] = None, scene_label: Optional[str] = None, **kwargs) -> dict:
"""
Get the values associated to a scene.
:param scene_id: Select by scene_id.
:param scene_label: Select by scene label.
:return: value_id -> value (as a dict) mapping.
"""
raise NotImplementedError
@abstractmethod
@action
def get_scene_values(self, scene_id: Optional[int] = None, scene_label: Optional[str] = None, **kwargs) -> dict:
def get_scene_values(
self,
scene_id: Optional[int] = None,
scene_label: Optional[str] = None,
**kwargs
) -> dict:
"""
Get the values associated to a scene.
@ -634,8 +753,13 @@ class ZwaveBasePlugin(SwitchPlugin, ABC):
@abstractmethod
@action
def create_button(self, button_id: Union[int, str], node_id: Optional[int] = None, node_name: Optional[str] = None,
**kwargs):
def create_button(
self,
button_id: Union[int, str],
node_id: Optional[int] = None,
node_name: Optional[str] = None,
**kwargs
):
"""
Create a handheld button on a device. Only intended for bridge firmware controllers.
@ -647,8 +771,13 @@ class ZwaveBasePlugin(SwitchPlugin, ABC):
@abstractmethod
@action
def delete_button(self, button_id: Union[int, str], node_id: Optional[int] = None, node_name: Optional[str] = None,
**kwargs):
def delete_button(
self,
button_id: Union[int, str],
node_id: Optional[int] = None,
node_name: Optional[str] = None,
**kwargs
):
"""
Delete a button association from a device. Only intended for bridge firmware controllers.
@ -660,8 +789,14 @@ class ZwaveBasePlugin(SwitchPlugin, ABC):
@abstractmethod
@action
def add_node_to_group(self, group_index: Optional[int] = None, group_label: Optional[str] = None,
node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs):
def add_node_to_group(
self,
group_index: Optional[int] = None,
group_label: Optional[str] = None,
node_id: Optional[int] = None,
node_name: Optional[str] = None,
**kwargs
):
"""
Add a node to a group.
@ -674,8 +809,14 @@ class ZwaveBasePlugin(SwitchPlugin, ABC):
@abstractmethod
@action
def remove_node_from_group(self, group_index: Optional[int] = None, group_label: Optional[str] = None,
node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs):
def remove_node_from_group(
self,
group_index: Optional[int] = None,
group_label: Optional[str] = None,
node_id: Optional[int] = None,
node_name: Optional[str] = None,
**kwargs
):
"""
Remove a node from a group.

View File

@ -1,3 +1,4 @@
from collections import OrderedDict
import json
import queue
@ -5,6 +6,7 @@ from datetime import datetime
from threading import Timer
from typing import Optional, List, Any, Dict, Union, Iterable, Mapping, Callable
from platypush.entities.dimmers import Dimmer
from platypush.entities.switches import Switch
from platypush.message.event.zwave import ZwaveNodeRenamedEvent, ZwaveNodeEvent
@ -464,38 +466,120 @@ class ZwaveMqttPlugin(MqttPlugin, ZwaveBasePlugin):
return value
@staticmethod
def _is_switch(value: Mapping):
return (
value.get('command_class_name', '').endswith('Switch') if value else False
)
def _matches_classes(value: Mapping, *names: str):
classes = {command_class_by_name[name] for name in names}
return value.get('command_class', '') in classes if value else False
@classmethod
def _is_switch(cls, value: Mapping):
return cls._matches_classes(
value, 'switch_binary', 'switch_toggle_binary', 'switch_all'
) and not value.get('is_read_only')
@classmethod
def _is_dimmer(cls, value: Mapping):
return cls._matches_classes(
value, 'switch_multilevel', 'switch_toggle_multilevel'
) and not value.get('is_read_only')
def _to_entity_args(self, value: Mapping) -> dict:
if value['id'].endswith('-targetValue'):
current_value_id = '-'.join(value['id'].split('-')[:-1] + ['currentValue'])
value = {
**value,
'id': current_value_id,
'label': 'Current Value',
'is_read_only': False,
'is_write_only': False,
}
return {
'id': value['id'],
'name': '{node_name} [{value_name}]'.format(
node_name=self._nodes_cache['by_id'][value['node_id']].get(
'name', f'[Node {value["node_id"]}]'
),
value_name=value.get('label'),
),
'description': value.get('help'),
'is_read_only': value.get('is_read_only'),
'is_write_only': value.get('is_write_only'),
'data': {
'label': value.get('label'),
'node_id': value.get('node_id'),
},
}
def transform_entities(self, values: Iterable[Mapping]):
entities = []
for value in values:
if self._is_switch(value):
entities.append(
Switch(
id=value['id'],
name='{node_name} [{value_name}]'.format(
node_name=self._nodes_cache['by_id'][value['node_id']].get(
'name', f'[Node {value["node_id"]}]'
),
value_name=value["label"],
),
state=value['data'],
description=value.get('help'),
is_read_only=value.get('is_read_only'),
is_write_only=value.get('is_write_only'),
data={
'label': value.get('label'),
'node_id': value.get('node_id'),
},
)
)
if not value:
continue
entity_type = None
entity_args = self._to_entity_args(value)
if self._is_dimmer(value):
entity_type = Dimmer
entity_args['value'] = value['data']
entity_args['min'] = value['min']
entity_args['max'] = value['max']
elif self._is_switch(value):
entity_type = Switch
entity_args['state'] = value['data']
if entity_type:
entities.append(entity_type(**entity_args))
return super().transform_entities(entities) # type: ignore
@staticmethod
def _merge_current_and_target_values(values: Iterable[dict]) -> List[dict]:
values_by_id = OrderedDict({v.get('id'): v for v in values})
new_values = OrderedDict()
for value in values:
value_id = value.get('id')
if not value_id:
continue
associated_value_id = None
associated_value = None
value_id_prefix = '-'.join(value_id.split('-')[:-1])
if value_id.endswith('-currentValue'):
associated_value_id = value_id_prefix + '-targetValue'
elif value_id.endswith('-targetValue'):
associated_value_id = value_id_prefix + '-currentValue'
if associated_value_id:
associated_value = values_by_id.pop(associated_value_id, None)
if associated_value:
value = value.copy()
value_id = value_id_prefix + '-currentValue'
value['data'] = (
value.get('data')
if value.get('id', '').endswith('-currentValue')
else associated_value.get('data')
)
value['id'] = value['value_id'] = value['id_on_network'] = value_id
value['is_read_only'] = value['is_write_only'] = False
value['label'] = 'Current Value'
value['property_id'] = 'currentValue'
value['last_update'] = (
max(
value.get('last_update') or 0,
associated_value.get('last_update') or 0,
)
or None
)
new_values[value_id] = value
return list(new_values.values())
def _topic_by_value_id(self, value_id: str) -> str:
return self.topic_prefix + '/' + '/'.join(value_id.split('-'))
@ -541,7 +625,8 @@ class ZwaveMqttPlugin(MqttPlugin, ZwaveBasePlugin):
values[value['id_on_network']] = value
self.publish_entities(values.values()) # type: ignore
entity_values = self._merge_current_and_target_values(values.values())
self.publish_entities(entity_values) # type: ignore
return values
def _get_group(
@ -1117,7 +1202,8 @@ class ZwaveMqttPlugin(MqttPlugin, ZwaveBasePlugin):
@action
def set_value(
self,
data,
*args,
data=None,
value_id: Optional[int] = None,
id_on_network: Optional[str] = None,
value_label: Optional[str] = None,
@ -1137,6 +1223,16 @@ class ZwaveMqttPlugin(MqttPlugin, ZwaveBasePlugin):
:param kwargs: Extra arguments to be passed to :meth:`platypush.plugins.mqtt.MqttPlugin.publish``
(default: query the default configured device).
"""
# Compatibility layer with the .set_value format used by
# the entities frontend
if args:
value_id = args[0]
id_ = str(value_id or id_on_network or '')
if id_.endswith('-currentValue'):
id_ = '-'.join(id_.split('-')[:-1] + ['targetValue'])
value_id = id_on_network = id_ # type: ignore
value = self._get_value(
value_id=value_id,
value_label=value_label,
@ -1354,7 +1450,7 @@ class ZwaveMqttPlugin(MqttPlugin, ZwaveBasePlugin):
(default: query the default configured device).
"""
return self._filter_values(
['switch_binary', 'switch_toggle_binary'],
['switch_binary', 'switch_toggle_binary', 'switch_all'],
filter_callback=lambda value: not value['is_read_only'],
node_id=node_id,
node_name=node_name,