Added support for `EnumSensor` entities

This commit is contained in:
Fabio Manganiello 2022-11-21 00:04:07 +01:00
parent d171000a0e
commit b9e6614b04
Signed by: blacklight
GPG Key ID: D90FBA7F76362774
6 changed files with 162 additions and 40 deletions

View File

@ -0,0 +1,60 @@
<template>
<div class="entity sensor-container">
<div class="head">
<div class="col-1 icon">
<EntityIcon
:icon="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 pull-right"
v-if="value.value != null">
<span class="unit" v-text="value.unit"
v-if="value.unit != null" />
<span class="value" v-text="displayValue(value.value)" />
</div>
</div>
</div>
</template>
<script>
import EntityIcon from "./EntityIcon"
import Sensor from "./Sensor"
export default {
name: 'EnumSensor',
components: {EntityIcon},
mixins: [Sensor],
methods: {
displayValue(val) {
if (this.value?.values && typeof(this.value.values) === 'object')
return this.value.values[val] || val
return val
},
},
}
</script>
<style lang="scss" scoped>
@import "common";
.sensor-container {
.head {
.value {
font-size: 1.1em;
font-weight: bold;
opacity: 0.7;
}
.unit {
margin-left: 0.2em;
}
}
}
</style>

View File

@ -127,6 +127,14 @@
}
},
"enum_sensor": {
"name": "Sensor",
"name_plural": "Sensors",
"icon": {
"class": "fas fa-thermometer"
}
},
"sensor": {
"name": "Sensor",
"name_plural": "Sensors",

View File

@ -106,7 +106,7 @@ class ZwaveMqttBackend(MqttBackend):
value: Optional[dict] = None,
**kwargs,
):
if value and 'id' not in value:
if node and value and 'id' not in value:
value_id = f"{value['commandClass']}-{value.get('endpoint', 0)}-{value['property']}"
if 'propertyKey' in value:
value_id += '-' + str(value['propertyKey'])

View File

@ -1,6 +1,14 @@
import logging
from sqlalchemy import Column, Integer, ForeignKey, Boolean, Numeric, String
from sqlalchemy import (
Boolean,
Column,
ForeignKey,
Integer,
JSON,
Numeric,
String,
)
from .devices import Device, entity_types_registry
@ -83,3 +91,23 @@ if not entity_types_registry.get('BinarySensor'):
entity_types_registry['BinarySensor'] = BinarySensor
else:
BinarySensor = entity_types_registry['BinarySensor']
if not entity_types_registry.get('EnumSensor'):
class EnumSensor(Sensor):
__tablename__ = 'enum_sensor'
id = Column(
Integer, ForeignKey(Device.id, ondelete='CASCADE'), primary_key=True
)
value = Column(String)
values = Column(JSON)
__mapper_args__ = {
'polymorphic_identity': __tablename__,
}
entity_types_registry['EnumSensor'] = EnumSensor
else:
EnumSensor = entity_types_registry['EnumSensor']

View File

@ -17,7 +17,12 @@ from platypush.entities.electricity import (
from platypush.entities.humidity import HumiditySensor
from platypush.entities.lights import Light
from platypush.entities.linkquality import LinkQuality
from platypush.entities.sensors import Sensor, BinarySensor, NumericSensor
from platypush.entities.sensors import (
BinarySensor,
EnumSensor,
NumericSensor,
Sensor,
)
from platypush.entities.switches import Switch, EnumSwitch
from platypush.entities.temperature import TemperatureSensor
from platypush.message import Mapping
@ -1586,6 +1591,9 @@ class ZigbeeMqttPlugin(MqttPlugin): # lgtm [py/missing-call-to-init]
sensor_args['value'] = sensor_args['value'] == exposed.get(
'value_on', True
)
elif exposed.get('type') == 'enum':
entity_type = EnumSensor
sensor_args['values'] = exposed.get('values', [])
elif exposed.get('type') == 'numeric':
entity_type = NumericSensor

View File

@ -26,7 +26,7 @@ from platypush.entities.electricity import (
VoltageSensor,
)
from platypush.entities.humidity import HumiditySensor
from platypush.entities.sensors import BinarySensor, NumericSensor
from platypush.entities.sensors import BinarySensor, EnumSensor, NumericSensor
from platypush.entities.switches import Switch
from platypush.entities.temperature import TemperatureSensor
from platypush.message.event.zwave import ZwaveNodeRenamedEvent, ZwaveNodeEvent
@ -507,46 +507,64 @@ class ZwaveMqttPlugin(MqttPlugin, ZwaveBasePlugin):
def _get_sensor_args(
cls, value: Mapping
) -> Tuple[Optional[Type], Optional[Mapping]]:
if not value.get('is_read_only'):
return None, None
sensor_type, args = None, None
known_sensor_classes = {
'battery',
'door_lock',
'lock',
'meter',
'notification',
'sensor_alarm',
'sensor_binary',
'sensor_multilevel',
'thermostat_fan_mode',
'thermostat_fan_state',
'thermostat_heating',
}
if (
cls._matches_classes(value, 'sensor_binary', 'sensor_alarm', 'meter')
and value.get('type') == 'Bool'
if value.get('is_read_only') and cls._matches_classes(
value, *known_sensor_classes
):
return (
BinarySensor,
{
'value': value.get('data', False),
},
)
if value.get('type') == 'Bool':
sensor_type, args = (
BinarySensor,
{
'value': value.get('data', False),
},
)
elif value.get('type') == 'List':
sensor_type, args = (
EnumSensor,
{
'value': value.get('data'),
'values': {
i['value']: i['text'] for i in value.get('data_items', [])
},
},
)
elif value.get('type') == 'Decimal':
sensor_type = NumericSensor
if re.search(r'\s*power$', value['property_id'], re.IGNORECASE):
sensor_type = PowerSensor
if re.search(r'\s*voltage$', value['property_id'], re.IGNORECASE):
sensor_type = VoltageSensor
elif re.search(
r'\s*consumption$', value['property_id'], re.IGNORECASE
) or re.search(r'Wh$', (value.get('units') or '')):
sensor_type = EnergySensor
elif re.search(r'\s*temperature$', value['property_id'], re.IGNORECASE):
sensor_type = TemperatureSensor
elif re.search(r'\s*humidity$', value['property_id'], re.IGNORECASE):
sensor_type = HumiditySensor
if (
cls._matches_classes(value, 'sensor_multilevel', 'sensor_alarm', 'meter')
and value.get('type') == 'Decimal'
):
args = {
'value': value.get('data'),
'min': value.get('min'),
'max': value.get('max'),
'unit': value.get('units'),
}
args = {
'value': value.get('data'),
'min': value.get('min'),
'max': value.get('max'),
'unit': value.get('units'),
}
sensor_type = NumericSensor
if re.search(r'\s*power$', value['property_id'], re.IGNORECASE):
sensor_type = PowerSensor
if re.search(r'\s*voltage$', value['property_id'], re.IGNORECASE):
sensor_type = VoltageSensor
elif re.search(r'Wh$', value.get('units', '')):
sensor_type = EnergySensor
elif re.search(r'\s*temperature$', value['property_id'], re.IGNORECASE):
sensor_type = TemperatureSensor
elif re.search(r'\s*humidity$', value['property_id'], re.IGNORECASE):
sensor_type = HumiditySensor
return sensor_type, args
return None, None
return sensor_type, args
@classmethod
def _is_battery(cls, value: Mapping):