Support for battery entities

This commit is contained in:
Fabio Manganiello 2022-10-29 13:38:42 +02:00
parent cdacf50fc7
commit d61b053f72
Signed by untrusted user: blacklight
GPG key ID: D90FBA7F76362774
6 changed files with 240 additions and 13 deletions

View file

@ -0,0 +1,123 @@
<template>
<div class="entity battery-container">
<div class="head">
<div class="col-1 icon">
<EntityIcon
:icon="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">
<span class="value-percent"
v-text="valuePercent + '%'"
v-if="valuePercent != null" />
</div>
</div>
</div>
</template>
<script>
import EntityMixin from "./EntityMixin"
import EntityIcon from "./EntityIcon"
const thresholds = [
{
iconClass: 'full',
color: '#157145',
value: 0.9,
},
{
iconClass: 'three-quarters',
color: '#94C595',
value: 0.825,
},
{
iconClass: 'half',
color: '#F0B67F',
value: 0.625,
},
{
iconClass: 'quarter',
color: '#FE5F55',
value: 0.375,
},
{
iconClass: 'low',
color: '#CC444B',
value: 0.15,
},
{
iconClass: 'empty',
color: '#EC0B43',
value: 0.05,
},
]
export default {
name: 'Battery',
components: {EntityIcon},
mixins: [EntityMixin],
data() {
return {
expanded: false,
}
},
computed: {
valuePercent() {
if (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)).toFixed(0)
},
icon() {
const icon = {...(this.value.meta?.icon || {})}
let value = this.valuePercent
let threshold = thresholds[0]
if (value != null) {
value = parseFloat(value) / 100
for (const t of thresholds) {
if (value > t.value)
break
threshold = t
}
}
icon['class'] = `fas fa-battery-${threshold.iconClass}`
icon['color'] = threshold.color
return icon
},
},
methods: {
prevent(event) {
event.stopPropagation()
return false
},
},
}
</script>
<style lang="scss" scoped>
@import "common";
.battery-container {
.head {
.value-percent {
font-size: 1.1em;
font-weight: bold;
opacity: 0.7;
}
}
}
</style>

View file

@ -1,9 +1,9 @@
{ {
"entity": { "battery": {
"name": "Entity", "name": "Battery",
"name_plural": "Entities", "name_plural": "Batteries",
"icon": { "icon": {
"class": "fas fa-circle-question" "class": "fas fa-battery-full"
} }
}, },
@ -15,11 +15,19 @@
} }
}, },
"switch": { "dimmer": {
"name": "Switch", "name": "Dimmer",
"name_plural": "Switches", "name_plural": "Dimmers",
"icon": { "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": { "switch": {
"name": "Dimmer", "name": "Switch",
"name_plural": "Dimmers", "name_plural": "Switches",
"icon": { "icon": {
"class": "fas fa-gauge" "class": "fas fa-toggle-on"
} }
} }
} }

View file

@ -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']

View file

@ -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']

View file

@ -2,13 +2,14 @@ from abc import ABC, abstractmethod
from typing import Any, Dict, Optional, List, Union from typing import Any, Dict, Optional, List, Union
from platypush.entities import manages from platypush.entities import manages
from platypush.entities.batteries import Battery
from platypush.entities.dimmers import Dimmer from platypush.entities.dimmers import Dimmer
from platypush.entities.lights import Light from platypush.entities.lights import Light
from platypush.entities.switches import Switch from platypush.entities.switches import Switch
from platypush.plugins import Plugin, action from platypush.plugins import Plugin, action
@manages(Dimmer, Light, Switch) @manages(Battery, Dimmer, Light, Switch)
class ZwaveBasePlugin(Plugin, ABC): class ZwaveBasePlugin(Plugin, ABC):
""" """
Base class for Z-Wave plugins. Base class for Z-Wave plugins.

View file

@ -6,6 +6,7 @@ from datetime import datetime
from threading import Timer from threading import Timer
from typing import Optional, List, Any, Dict, Union, Iterable, Mapping, Callable 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.dimmers import Dimmer
from platypush.entities.switches import Switch from platypush.entities.switches import Switch
from platypush.message.event.zwave import ZwaveNodeRenamedEvent, ZwaveNodeEvent from platypush.message.event.zwave import ZwaveNodeRenamedEvent, ZwaveNodeEvent
@ -482,6 +483,14 @@ class ZwaveMqttPlugin(MqttPlugin, ZwaveBasePlugin):
value, 'switch_multilevel', 'switch_toggle_multilevel' value, 'switch_multilevel', 'switch_toggle_multilevel'
) and not value.get('is_read_only') ) 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: def _to_entity_args(self, value: Mapping) -> dict:
if value['id'].endswith('-targetValue'): if value['id'].endswith('-targetValue'):
current_value_id = '-'.join(value['id'].split('-')[:-1] + ['currentValue']) current_value_id = '-'.join(value['id'].split('-')[:-1] + ['currentValue'])
@ -525,6 +534,12 @@ class ZwaveMqttPlugin(MqttPlugin, ZwaveBasePlugin):
entity_args['value'] = value['data'] entity_args['value'] = value['data']
entity_args['min'] = value['min'] entity_args['min'] = value['min']
entity_args['max'] = value['max'] 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): elif self._is_switch(value):
entity_type = Switch entity_type = Switch
entity_args['state'] = value['data'] entity_args['state'] = value['data']