forked from platypush/platypush
Added dimmer entities
This commit is contained in:
parent
d7278857e5
commit
951950c864
5 changed files with 509 additions and 115 deletions
|
@ -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>
|
|
@ -29,5 +29,13 @@
|
|||
"icon": {
|
||||
"class": "fas fa-lightbulb"
|
||||
}
|
||||
},
|
||||
|
||||
"dimmer": {
|
||||
"name": "Dimmer",
|
||||
"name_plural": "Dimmers",
|
||||
"icon": {
|
||||
"class": "fas fa-gauge"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
25
platypush/entities/dimmers.py
Normal file
25
platypush/entities/dimmers.py
Normal 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']
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue