diff --git a/platypush/backend/http/webapp/src/components/panels/Entities/Battery.vue b/platypush/backend/http/webapp/src/components/panels/Entities/Battery.vue new file mode 100644 index 000000000..5a1968293 --- /dev/null +++ b/platypush/backend/http/webapp/src/components/panels/Entities/Battery.vue @@ -0,0 +1,123 @@ + + + + + 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 98f457585..42c32de6d 100644 --- a/platypush/backend/http/webapp/src/components/panels/Entities/meta.json +++ b/platypush/backend/http/webapp/src/components/panels/Entities/meta.json @@ -1,9 +1,9 @@ { - "entity": { - "name": "Entity", - "name_plural": "Entities", + "battery": { + "name": "Battery", + "name_plural": "Batteries", "icon": { - "class": "fas fa-circle-question" + "class": "fas fa-battery-full" } }, @@ -15,11 +15,19 @@ } }, - "switch": { - "name": "Switch", - "name_plural": "Switches", + "dimmer": { + "name": "Dimmer", + "name_plural": "Dimmers", "icon": { - "class": "fas fa-toggle-on" + "class": "fas fa-gauge" + } + }, + + "entity": { + "name": "Entity", + "name_plural": "Entities", + "icon": { + "class": "fas fa-circle-question" } }, @@ -31,11 +39,11 @@ } }, - "dimmer": { - "name": "Dimmer", - "name_plural": "Dimmers", + "switch": { + "name": "Switch", + "name_plural": "Switches", "icon": { - "class": "fas fa-gauge" + "class": "fas fa-toggle-on" } } } diff --git a/platypush/entities/batteries.py b/platypush/entities/batteries.py new file mode 100644 index 000000000..3eaacc54b --- /dev/null +++ b/platypush/entities/batteries.py @@ -0,0 +1,37 @@ +from sqlalchemy import Column, Integer, ForeignKey + +from .devices import entity_types_registry +from .sensors import NumericSensor + + +if not entity_types_registry.get('Battery'): + + class Battery(NumericSensor): + __tablename__ = 'battery' + + def __init__( + self, + *args, + value, + unit: str = '%', + min: float = 0, + max: float = 100, + **kwargs + ): + super().__init__(*args, **kwargs) + self.value = float(value) + self.unit = unit + self.min = min + self.max = max + + id = Column( + Integer, ForeignKey(NumericSensor.id, ondelete='CASCADE'), primary_key=True + ) + + __mapper_args__ = { + 'polymorphic_identity': __tablename__, + } + + entity_types_registry['Battery'] = Battery +else: + Battery = entity_types_registry['Battery'] diff --git a/platypush/entities/sensors.py b/platypush/entities/sensors.py new file mode 100644 index 000000000..16e3f33cc --- /dev/null +++ b/platypush/entities/sensors.py @@ -0,0 +1,43 @@ +from sqlalchemy import Column, Integer, ForeignKey, Numeric, String + +from .devices import Device, entity_types_registry + + +if not entity_types_registry.get('RawSensor'): + + class RawSensor(Device): + __tablename__ = 'raw_sensor' + + id = Column( + Integer, ForeignKey(Device.id, ondelete='CASCADE'), primary_key=True + ) + value = Column(String) + + __mapper_args__ = { + 'polymorphic_identity': __tablename__, + } + + entity_types_registry['RawSensor'] = RawSensor +else: + RawSensor = entity_types_registry['RawSensor'] + + +if not entity_types_registry.get('NumericSensor'): + + class NumericSensor(Device): + __tablename__ = 'numeric_sensor' + + id = Column( + Integer, ForeignKey(Device.id, ondelete='CASCADE'), primary_key=True + ) + value = Column(Numeric) + min = Column(Numeric) + max = Column(Numeric) + + __mapper_args__ = { + 'polymorphic_identity': __tablename__, + } + + entity_types_registry['NumericSensor'] = NumericSensor +else: + NumericSensor = entity_types_registry['NumericSensor'] diff --git a/platypush/plugins/zwave/_base.py b/platypush/plugins/zwave/_base.py index 3fe9d637b..9b145ef9f 100644 --- a/platypush/plugins/zwave/_base.py +++ b/platypush/plugins/zwave/_base.py @@ -2,13 +2,14 @@ from abc import ABC, abstractmethod from typing import Any, Dict, Optional, List, Union from platypush.entities import manages +from platypush.entities.batteries import Battery from platypush.entities.dimmers import Dimmer from platypush.entities.lights import Light from platypush.entities.switches import Switch from platypush.plugins import Plugin, action -@manages(Dimmer, Light, Switch) +@manages(Battery, Dimmer, Light, Switch) class ZwaveBasePlugin(Plugin, ABC): """ Base class for Z-Wave plugins. diff --git a/platypush/plugins/zwave/mqtt/__init__.py b/platypush/plugins/zwave/mqtt/__init__.py index 4d069bc99..b272e0d8c 100644 --- a/platypush/plugins/zwave/mqtt/__init__.py +++ b/platypush/plugins/zwave/mqtt/__init__.py @@ -6,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.batteries import Battery from platypush.entities.dimmers import Dimmer from platypush.entities.switches import Switch from platypush.message.event.zwave import ZwaveNodeRenamedEvent, ZwaveNodeEvent @@ -482,6 +483,14 @@ class ZwaveMqttPlugin(MqttPlugin, ZwaveBasePlugin): value, 'switch_multilevel', 'switch_toggle_multilevel' ) and not value.get('is_read_only') + @classmethod + def _is_battery(cls, value: Mapping): + return ( + cls._matches_classes(value, 'battery') + and value.get('is_read_only') + and not value['id'].endswith('-isLow') + ) + def _to_entity_args(self, value: Mapping) -> dict: if value['id'].endswith('-targetValue'): current_value_id = '-'.join(value['id'].split('-')[:-1] + ['currentValue']) @@ -525,6 +534,12 @@ class ZwaveMqttPlugin(MqttPlugin, ZwaveBasePlugin): entity_args['value'] = value['data'] entity_args['min'] = value['min'] entity_args['max'] = value['max'] + elif self._is_battery(value): + entity_type = Battery + entity_args['value'] = value['data'] + entity_args['min'] = value['min'] + entity_args['max'] = value['max'] + entity_args['unit'] = value.get('units', '%') elif self._is_switch(value): entity_type = Switch entity_args['state'] = value['data']