forked from platypush/platypush
Support for battery entities
This commit is contained in:
parent
cdacf50fc7
commit
d61b053f72
6 changed files with 240 additions and 13 deletions
|
@ -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>
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
37
platypush/entities/batteries.py
Normal file
37
platypush/entities/batteries.py
Normal 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']
|
43
platypush/entities/sensors.py
Normal file
43
platypush/entities/sensors.py
Normal 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']
|
|
@ -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.
|
||||
|
|
|
@ -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']
|
||||
|
|
Loading…
Reference in a new issue