Added battery entity support to `system` plugin.

This commit is contained in:
Fabio Manganiello 2023-04-23 00:41:21 +02:00
parent b3440ab96b
commit a72c32cb00
Signed by: blacklight
GPG Key ID: D90FBA7F76362774
11 changed files with 141 additions and 40 deletions

View File

@ -0,0 +1 @@
Battery.vue

View File

@ -79,14 +79,6 @@
}
},
"current_sensor": {
"name": "Sensor",
"name_plural": "Sensors",
"icon": {
"class": "fas fa-bolt"
}
},
"system_fan": {
"name": "System",
"name_plural": "System",
@ -95,6 +87,22 @@
}
},
"system_battery": {
"name": "System",
"name_plural": "System",
"icon": {
"class": "fas fa-battery-full"
}
},
"current_sensor": {
"name": "Sensor",
"name_plural": "Sensors",
"icon": {
"class": "fas fa-bolt"
}
},
"cpu": {
"name": "System",
"name_plural": "System",

View File

@ -1,10 +1,10 @@
from sqlalchemy import Column, Float, ForeignKey, Integer, JSON, String
from sqlalchemy import Boolean, Column, Float, ForeignKey, Integer, JSON, String
from platypush.common.db import Base
from . import Entity
from .devices import Device
from .sensors import NumericSensor
from .sensors import NumericSensor, PercentSensor
from .temperature import TemperatureSensor
@ -253,3 +253,26 @@ if 'system_fan' not in Base.metadata:
__mapper_args__ = {
'polymorphic_identity': __tablename__,
}
if 'system_battery' not in Base.metadata:
class SystemBattery(PercentSensor):
"""
``SystemBattery`` ORM model.
"""
__tablename__ = 'system_battery'
id = Column(
Integer,
ForeignKey(PercentSensor.id, ondelete='CASCADE'),
primary_key=True,
)
seconds_left = Column(Float)
power_plugged = Column(Boolean)
__mapper_args__ = {
'polymorphic_identity': __tablename__,
}

View File

@ -8,25 +8,6 @@ class SystemResponse(Response):
pass
class SensorResponse(SystemResponse):
pass
class SensorBatteryResponse(SensorResponse):
def __init__(
self, percent: float, secs_left: int, power_plugged: bool, *args, **kwargs
):
super().__init__(
*args,
output={
'percent': percent,
'secs_left': secs_left,
'power_plugged': power_plugged,
},
**kwargs
)
class ConnectUserResponse(SystemResponse):
def __init__(
self,

View File

@ -19,11 +19,11 @@ from platypush.entities.system import (
MemoryStats as MemoryStatsModel,
NetworkInterface as NetworkInterfaceModel,
SwapStats as SwapStatsModel,
SystemBattery,
SystemFan,
SystemTemperature,
)
from platypush.message.response.system import (
SensorBatteryResponse,
ConnectedUserResponseList,
ConnectUserResponse,
ProcessResponseList,
@ -32,6 +32,8 @@ from platypush.message.response.system import (
from platypush.plugins import action
from platypush.plugins.sensor import SensorPlugin
from platypush.schemas.system import (
Battery,
BatterySchema,
ConnectionSchema,
CpuFrequency,
CpuFrequencySchema,
@ -387,19 +389,19 @@ class SystemPlugin(SensorPlugin, EntityManager):
"""
return FanSchema().dump(self._sensors_fan(), many=True)
def _sensors_battery(self) -> Optional[Battery]:
battery = psutil.sensors_battery()
return BatterySchema().load(battery) if battery else None # type: ignore
@action
def sensors_battery(self) -> SensorBatteryResponse:
def sensors_battery(self) -> Optional[dict]:
"""
Get stats from the battery sensor.
:return: List of :class:`platypush.message.response.system.SensorFanResponse`.
"""
stats = psutil.sensors_battery()
return SensorBatteryResponse(
percent=stats.percent,
secs_left=stats.secsleft,
power_plugged=stats.power_plugged,
)
:return: .. schema:: system.BatterySchema
"""
battery = self._sensors_battery()
return BatterySchema().dump(battery) if battery else None # type: ignore
@action
def connected_users(self) -> ConnectedUserResponseList:
@ -554,12 +556,14 @@ class SystemPlugin(SensorPlugin, EntityManager):
'network': self._network_info(),
'temperature': self._sensors_temperature(),
'fans': self._sensors_fan(),
'battery': self._sensors_battery(),
}
)
@override
def transform_entities(self, entities: dict) -> List[Entity]:
cpu = entities['cpu'].copy()
battery = entities['battery']
return [
Cpu(
@ -663,6 +667,15 @@ class SystemPlugin(SensorPlugin, EntityManager):
)
for fan in entities.get('fans', [])
],
*[
SystemBattery(
id='system:battery',
name='Battery',
**battery,
)
if battery
else ()
],
]

View File

@ -1,3 +1,4 @@
from ._battery import Battery, BatterySchema
from ._connection import Connection, ConnectionSchema
from ._cpu import (
Cpu,
@ -20,6 +21,8 @@ from ._temperature import Temperature, TemperatureSchema
__all__ = [
"Battery",
"BatterySchema",
"Connection",
"ConnectionSchema",
"Cpu",

View File

@ -0,0 +1,4 @@
from ._model import Battery
from ._schemas import BatterySchema
__all__ = ['Battery', 'BatterySchema']

View File

@ -0,0 +1,20 @@
from enum import Enum
from marshmallow import pre_load
from .._base import SystemBaseSchema
class BatteryBaseSchema(SystemBaseSchema):
"""
Base schema for system battery sensors.
"""
@pre_load
def pre_load(self, data: dict, **_) -> dict:
data = super().pre_load(data)
percent = data.pop('percent', data.pop('value', None))
seconds_left = data.pop('secsleft', data.pop('seconds_left', None))
data['value'] = percent / 100 if percent is not None else None
data['seconds_left'] = None if isinstance(seconds_left, Enum) else seconds_left
return data

View File

@ -0,0 +1,39 @@
from dataclasses import dataclass, field
from typing import Optional
from platypush.schemas.dataclasses import percent_field
@dataclass
class Battery:
"""
System battery sensor wrapper.
"""
seconds_left: Optional[float] = field(
metadata={
'metadata': {
'description': 'High threshold for the temperature sensor, in Celsius',
'example': 75,
}
}
)
power_plugged: Optional[bool] = field(
metadata={
'metadata': {
'description': 'Whether the battery is plugged in or not',
'example': False,
}
}
)
value: Optional[float] = percent_field(
metadata={
'metadata': {
'description': 'Current charge left, as a percentage value '
'between 0 and 1',
'example': 0.5,
}
}
)

View File

@ -0,0 +1,7 @@
from marshmallow_dataclass import class_schema
from ._base import BatteryBaseSchema
from ._model import Battery
BatterySchema = class_schema(Battery, base_schema=BatteryBaseSchema)

View File

@ -1,6 +1,7 @@
from dataclasses import dataclass
from typing import List
from typing import List, Optional
from ._battery import Battery
from ._cpu import Cpu
from ._disk import Disk
from ._fan import Fan
@ -22,3 +23,4 @@ class SystemInfo:
network: List[NetworkInterface]
temperature: List[Temperature]
fans: List[Fan]
battery: Optional[Battery]