diff --git a/platypush/backend/http/webapp/src/components/panels/Entities/EnumSensor.vue b/platypush/backend/http/webapp/src/components/panels/Entities/EnumSensor.vue
new file mode 100644
index 000000000..6d133d023
--- /dev/null
+++ b/platypush/backend/http/webapp/src/components/panels/Entities/EnumSensor.vue
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
diff --git a/platypush/backend/http/webapp/src/components/panels/Entities/meta.json b/platypush/backend/http/webapp/src/components/panels/Entities/meta.json
index 8158aa488..b80c9df8b 100644
--- a/platypush/backend/http/webapp/src/components/panels/Entities/meta.json
+++ b/platypush/backend/http/webapp/src/components/panels/Entities/meta.json
@@ -127,6 +127,14 @@
}
},
+ "enum_sensor": {
+ "name": "Sensor",
+ "name_plural": "Sensors",
+ "icon": {
+ "class": "fas fa-thermometer"
+ }
+ },
+
"sensor": {
"name": "Sensor",
"name_plural": "Sensors",
diff --git a/platypush/backend/zwave/mqtt/__init__.py b/platypush/backend/zwave/mqtt/__init__.py
index 5a5d426c3..65ca7bbe6 100644
--- a/platypush/backend/zwave/mqtt/__init__.py
+++ b/platypush/backend/zwave/mqtt/__init__.py
@@ -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'])
diff --git a/platypush/entities/sensors.py b/platypush/entities/sensors.py
index efcf3e57f..0af0553e8 100644
--- a/platypush/entities/sensors.py
+++ b/platypush/entities/sensors.py
@@ -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']
diff --git a/platypush/plugins/zigbee/mqtt/__init__.py b/platypush/plugins/zigbee/mqtt/__init__.py
index 52c4bf8b8..6cc33fcbc 100644
--- a/platypush/plugins/zigbee/mqtt/__init__.py
+++ b/platypush/plugins/zigbee/mqtt/__init__.py
@@ -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
diff --git a/platypush/plugins/zwave/mqtt/__init__.py b/platypush/plugins/zwave/mqtt/__init__.py
index ebe9a7135..83ca2c6fb 100644
--- a/platypush/plugins/zwave/mqtt/__init__.py
+++ b/platypush/plugins/zwave/mqtt/__init__.py
@@ -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):