forked from platypush/platypush
zwave.mqtt additions
- Infer entity types on the basis of their semantic type (bool, decimal, list) and read-only attribute (read-only bool is `BinarySensor`, read-write bool is `Switch`, read-only decimal is `NumericSensor`, read-write decimal is `Dimmer`, etc.) instead of trying to infer it from the command class. Only a small set of command classes (like configurations, vendor-specific or internal values) will be excluded. This should greatly increase the number of supported values. - Added support for `EnumSwitch` entities. - Added inference for illuminance and humidity sensors.
This commit is contained in:
parent
78c59f437a
commit
0e0c90f0f2
1 changed files with 51 additions and 27 deletions
|
@ -26,8 +26,9 @@ from platypush.entities.electricity import (
|
|||
VoltageSensor,
|
||||
)
|
||||
from platypush.entities.humidity import HumiditySensor
|
||||
from platypush.entities.illuminance import IlluminanceSensor
|
||||
from platypush.entities.sensors import BinarySensor, EnumSensor, NumericSensor
|
||||
from platypush.entities.switches import Switch
|
||||
from platypush.entities.switches import EnumSwitch, Switch
|
||||
from platypush.entities.temperature import TemperatureSensor
|
||||
from platypush.message.event.zwave import ZwaveNodeRenamedEvent, ZwaveNodeEvent
|
||||
|
||||
|
@ -73,6 +74,33 @@ class ZwaveMqttPlugin(MqttPlugin, ZwaveBasePlugin):
|
|||
|
||||
"""
|
||||
|
||||
# These classes are ignored by the entity parsing logic
|
||||
_ignored_entity_classes = {
|
||||
'application_status',
|
||||
'association_command_configuration',
|
||||
'configuration',
|
||||
'controller_replication',
|
||||
'crc16_encap',
|
||||
'firmware_update_md',
|
||||
'grouping_name',
|
||||
'ip_configuration',
|
||||
'manufacturer_proprietary',
|
||||
'manufacturer_specific',
|
||||
'multi_cmd',
|
||||
'multi_instance',
|
||||
'multi_instance_association',
|
||||
'no_operation',
|
||||
'node_naming',
|
||||
'non_interoperable',
|
||||
'proprietary',
|
||||
'scene_actuator_conf',
|
||||
'scene_controller_conf',
|
||||
'sensor_configuration',
|
||||
'version',
|
||||
'wake_up',
|
||||
'zwave_plus_info',
|
||||
}
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
|
@ -488,43 +516,27 @@ class ZwaveMqttPlugin(MqttPlugin, ZwaveBasePlugin):
|
|||
@staticmethod
|
||||
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')
|
||||
return value.get('type') == 'Bool' 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')
|
||||
return value.get('type') == 'Decimal' and not value.get('is_read_only')
|
||||
|
||||
@classmethod
|
||||
def _is_enum_switch(cls, value: Mapping):
|
||||
return value.get('type') == 'List' and not value.get('is_read_only')
|
||||
|
||||
@classmethod
|
||||
def _get_sensor_args(
|
||||
cls, value: Mapping
|
||||
) -> Tuple[Optional[Type], Optional[Mapping]]:
|
||||
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 value.get('is_read_only') and cls._matches_classes(
|
||||
value, *known_sensor_classes
|
||||
):
|
||||
if value.get('is_read_only'):
|
||||
if value.get('type') == 'Bool':
|
||||
sensor_type, args = (
|
||||
BinarySensor,
|
||||
|
@ -554,8 +566,14 @@ class ZwaveMqttPlugin(MqttPlugin, ZwaveBasePlugin):
|
|||
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):
|
||||
elif re.search(
|
||||
r'\s*(humidity|moisture)$', value['property_id'], re.IGNORECASE
|
||||
):
|
||||
sensor_type = HumiditySensor
|
||||
elif re.search(
|
||||
r'\s*(illuminance|luminosity)$', value['property_id'], re.IGNORECASE
|
||||
):
|
||||
sensor_type = IlluminanceSensor
|
||||
|
||||
args = {
|
||||
'value': value.get('data'),
|
||||
|
@ -571,7 +589,7 @@ class ZwaveMqttPlugin(MqttPlugin, ZwaveBasePlugin):
|
|||
return (
|
||||
cls._matches_classes(value, 'battery')
|
||||
and value.get('is_read_only')
|
||||
and not value['id'].endswith('-isLow')
|
||||
and value.get('type') == 'Decimal'
|
||||
)
|
||||
|
||||
def _to_entity_args(self, value: Mapping) -> dict:
|
||||
|
@ -611,7 +629,7 @@ class ZwaveMqttPlugin(MqttPlugin, ZwaveBasePlugin):
|
|||
entities = []
|
||||
|
||||
for value in values:
|
||||
if not value:
|
||||
if not value or self._matches_classes(value, *self._ignored_entity_classes):
|
||||
continue
|
||||
|
||||
entity_type = None
|
||||
|
@ -623,6 +641,12 @@ class ZwaveMqttPlugin(MqttPlugin, ZwaveBasePlugin):
|
|||
entity_args['value'] = value['data']
|
||||
entity_args['min'] = value['min']
|
||||
entity_args['max'] = value['max']
|
||||
elif self._is_enum_switch(value):
|
||||
entity_type = EnumSwitch
|
||||
entity_args['value'] = value['data']
|
||||
entity_args['values'] = {
|
||||
i['value']: i['text'] for i in value.get('data_items', [])
|
||||
}
|
||||
elif self._is_battery(value):
|
||||
entity_type = Battery
|
||||
entity_args['value'] = value['data']
|
||||
|
|
Loading…
Reference in a new issue