forked from platypush/platypush
Added support for fan sensors on the system
plugin.
This commit is contained in:
parent
45d5f439be
commit
b3440ab96b
11 changed files with 127 additions and 50 deletions
|
@ -0,0 +1 @@
|
||||||
|
NumericSensor.vue
|
|
@ -87,6 +87,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"system_fan": {
|
||||||
|
"name": "System",
|
||||||
|
"name_plural": "System",
|
||||||
|
"icon": {
|
||||||
|
"class": "fas fa-fan"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
"cpu": {
|
"cpu": {
|
||||||
"name": "System",
|
"name": "System",
|
||||||
"name_plural": "System",
|
"name_plural": "System",
|
||||||
|
|
|
@ -4,6 +4,7 @@ from platypush.common.db import Base
|
||||||
|
|
||||||
from . import Entity
|
from . import Entity
|
||||||
from .devices import Device
|
from .devices import Device
|
||||||
|
from .sensors import NumericSensor
|
||||||
from .temperature import TemperatureSensor
|
from .temperature import TemperatureSensor
|
||||||
|
|
||||||
|
|
||||||
|
@ -232,3 +233,23 @@ if 'system_temperature' not in Base.metadata:
|
||||||
__mapper_args__ = {
|
__mapper_args__ = {
|
||||||
'polymorphic_identity': __tablename__,
|
'polymorphic_identity': __tablename__,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if 'system_fan' not in Base.metadata:
|
||||||
|
|
||||||
|
class SystemFan(NumericSensor):
|
||||||
|
"""
|
||||||
|
``SystemFan`` ORM model.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__tablename__ = 'system_fan'
|
||||||
|
|
||||||
|
id = Column(
|
||||||
|
Integer,
|
||||||
|
ForeignKey(NumericSensor.id, ondelete='CASCADE'),
|
||||||
|
primary_key=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
__mapper_args__ = {
|
||||||
|
'polymorphic_identity': __tablename__,
|
||||||
|
}
|
||||||
|
|
|
@ -12,21 +12,6 @@ class SensorResponse(SystemResponse):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class SensorFanResponse(SensorResponse):
|
|
||||||
def __init__(
|
|
||||||
self, name: str, current: int, label: Optional[str] = None, *args, **kwargs
|
|
||||||
):
|
|
||||||
super().__init__(
|
|
||||||
*args,
|
|
||||||
output={
|
|
||||||
'name': name,
|
|
||||||
'current': current,
|
|
||||||
'label': label,
|
|
||||||
},
|
|
||||||
**kwargs
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class SensorBatteryResponse(SensorResponse):
|
class SensorBatteryResponse(SensorResponse):
|
||||||
def __init__(
|
def __init__(
|
||||||
self, percent: float, secs_left: int, power_plugged: bool, *args, **kwargs
|
self, percent: float, secs_left: int, power_plugged: bool, *args, **kwargs
|
||||||
|
@ -127,11 +112,6 @@ class SystemResponseList(SystemResponse):
|
||||||
super().__init__(output=[r.output for r in responses], *args, **kwargs)
|
super().__init__(output=[r.output for r in responses], *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class SensorResponseList(SensorResponse, SystemResponseList):
|
|
||||||
def __init__(self, responses: List[SensorResponse], *args, **kwargs):
|
|
||||||
super().__init__(responses=responses, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class ConnectedUserResponseList(SystemResponseList):
|
class ConnectedUserResponseList(SystemResponseList):
|
||||||
def __init__(self, responses: List[ConnectUserResponse], *args, **kwargs):
|
def __init__(self, responses: List[ConnectUserResponse], *args, **kwargs):
|
||||||
super().__init__(responses=responses, *args, **kwargs)
|
super().__init__(responses=responses, *args, **kwargs)
|
||||||
|
|
|
@ -19,11 +19,10 @@ from platypush.entities.system import (
|
||||||
MemoryStats as MemoryStatsModel,
|
MemoryStats as MemoryStatsModel,
|
||||||
NetworkInterface as NetworkInterfaceModel,
|
NetworkInterface as NetworkInterfaceModel,
|
||||||
SwapStats as SwapStatsModel,
|
SwapStats as SwapStatsModel,
|
||||||
|
SystemFan,
|
||||||
SystemTemperature,
|
SystemTemperature,
|
||||||
)
|
)
|
||||||
from platypush.message.response.system import (
|
from platypush.message.response.system import (
|
||||||
SensorResponseList,
|
|
||||||
SensorFanResponse,
|
|
||||||
SensorBatteryResponse,
|
SensorBatteryResponse,
|
||||||
ConnectedUserResponseList,
|
ConnectedUserResponseList,
|
||||||
ConnectUserResponse,
|
ConnectUserResponse,
|
||||||
|
@ -44,6 +43,8 @@ from platypush.schemas.system import (
|
||||||
CpuTimesSchema,
|
CpuTimesSchema,
|
||||||
Disk,
|
Disk,
|
||||||
DiskSchema,
|
DiskSchema,
|
||||||
|
Fan,
|
||||||
|
FanSchema,
|
||||||
MemoryStats,
|
MemoryStats,
|
||||||
MemoryStatsSchema,
|
MemoryStatsSchema,
|
||||||
NetworkInterface,
|
NetworkInterface,
|
||||||
|
@ -363,36 +364,28 @@ class SystemPlugin(SensorPlugin, EntityManager):
|
||||||
"""
|
"""
|
||||||
return TemperatureSchema().dump(self._sensors_temperature(), many=True)
|
return TemperatureSchema().dump(self._sensors_temperature(), many=True)
|
||||||
|
|
||||||
|
def _sensors_fan(self) -> List[Fan]:
|
||||||
|
return FanSchema().load( # type: ignore
|
||||||
|
[
|
||||||
|
{
|
||||||
|
**sensor._asdict(),
|
||||||
|
'id': f'{kind}_{i + 1}',
|
||||||
|
'label': (f'{kind} #{i + 1}' if not sensor.label else sensor.label),
|
||||||
|
}
|
||||||
|
for kind, sensors in psutil.sensors_fans().items()
|
||||||
|
for i, sensor in enumerate(sensors)
|
||||||
|
],
|
||||||
|
many=True,
|
||||||
|
)
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def sensors_fan(self, sensor: Optional[str] = None) -> SensorResponseList:
|
def sensors_fan(self) -> List[dict]:
|
||||||
"""
|
"""
|
||||||
Get stats from the fan sensors.
|
Get stats from the fan sensors.
|
||||||
|
|
||||||
:param sensor: Select the sensor name.
|
:return: .. schema:: system.FanSchema(many=True)
|
||||||
:return: List of :class:`platypush.message.response.system.SensorFanResponse`.
|
|
||||||
"""
|
"""
|
||||||
stats = psutil.sensors_fans()
|
return FanSchema().dump(self._sensors_fan(), many=True)
|
||||||
|
|
||||||
def _expand_stats(name, _stats):
|
|
||||||
return SensorResponseList(
|
|
||||||
[
|
|
||||||
SensorFanResponse(
|
|
||||||
name=name,
|
|
||||||
current=s.current,
|
|
||||||
label=s.label,
|
|
||||||
)
|
|
||||||
for s in _stats
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
if sensor:
|
|
||||||
stats = [addr for name, addr in stats.items() if name == sensor]
|
|
||||||
assert stats, 'No such sensor name: {}'.format(sensor)
|
|
||||||
return _expand_stats(sensor, stats[0])
|
|
||||||
|
|
||||||
return SensorResponseList(
|
|
||||||
[_expand_stats(name, stat) for name, stat in stats.items()]
|
|
||||||
)
|
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def sensors_battery(self) -> SensorBatteryResponse:
|
def sensors_battery(self) -> SensorBatteryResponse:
|
||||||
|
@ -545,7 +538,7 @@ class SystemPlugin(SensorPlugin, EntityManager):
|
||||||
"""
|
"""
|
||||||
:return: .. schema:: system.SystemInfoSchema
|
:return: .. schema:: system.SystemInfoSchema
|
||||||
"""
|
"""
|
||||||
ret = SystemInfoSchema().dump(
|
return SystemInfoSchema().dump(
|
||||||
{
|
{
|
||||||
'cpu': {
|
'cpu': {
|
||||||
'frequency': self._cpu_frequency_avg(),
|
'frequency': self._cpu_frequency_avg(),
|
||||||
|
@ -560,11 +553,10 @@ class SystemPlugin(SensorPlugin, EntityManager):
|
||||||
'disks': self._disk_info(),
|
'disks': self._disk_info(),
|
||||||
'network': self._network_info(),
|
'network': self._network_info(),
|
||||||
'temperature': self._sensors_temperature(),
|
'temperature': self._sensors_temperature(),
|
||||||
|
'fans': self._sensors_fan(),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
return ret
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
def transform_entities(self, entities: dict) -> List[Entity]:
|
def transform_entities(self, entities: dict) -> List[Entity]:
|
||||||
cpu = entities['cpu'].copy()
|
cpu = entities['cpu'].copy()
|
||||||
|
@ -662,6 +654,15 @@ class SystemPlugin(SensorPlugin, EntityManager):
|
||||||
)
|
)
|
||||||
for temp in entities.get('temperature', [])
|
for temp in entities.get('temperature', [])
|
||||||
],
|
],
|
||||||
|
*[
|
||||||
|
SystemFan(
|
||||||
|
id=f'system:fan:{fan.pop("id")}',
|
||||||
|
name=fan.pop('label'),
|
||||||
|
unit='rpm',
|
||||||
|
**fan,
|
||||||
|
)
|
||||||
|
for fan in entities.get('fans', [])
|
||||||
|
],
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ from ._cpu import (
|
||||||
CpuTimesSchema,
|
CpuTimesSchema,
|
||||||
)
|
)
|
||||||
from ._disk import Disk, DiskSchema
|
from ._disk import Disk, DiskSchema
|
||||||
|
from ._fan import Fan, FanSchema
|
||||||
from ._memory import MemoryStats, MemoryStatsSchema, SwapStats, SwapStatsSchema
|
from ._memory import MemoryStats, MemoryStatsSchema, SwapStats, SwapStatsSchema
|
||||||
from ._model import SystemInfo
|
from ._model import SystemInfo
|
||||||
from ._network import NetworkInterface, NetworkInterfaceSchema
|
from ._network import NetworkInterface, NetworkInterfaceSchema
|
||||||
|
@ -32,6 +33,8 @@ __all__ = [
|
||||||
"CpuTimesSchema",
|
"CpuTimesSchema",
|
||||||
"Disk",
|
"Disk",
|
||||||
"DiskSchema",
|
"DiskSchema",
|
||||||
|
"Fan",
|
||||||
|
"FanSchema",
|
||||||
"MemoryStats",
|
"MemoryStats",
|
||||||
"MemoryStatsSchema",
|
"MemoryStatsSchema",
|
||||||
"SwapStats",
|
"SwapStats",
|
||||||
|
|
4
platypush/schemas/system/_fan/__init__.py
Normal file
4
platypush/schemas/system/_fan/__init__.py
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
from ._model import Fan
|
||||||
|
from ._schemas import FanSchema
|
||||||
|
|
||||||
|
__all__ = ["Fan", "FanSchema"]
|
15
platypush/schemas/system/_fan/_base.py
Normal file
15
platypush/schemas/system/_fan/_base.py
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
from marshmallow import pre_load
|
||||||
|
|
||||||
|
from .._base import SystemBaseSchema
|
||||||
|
|
||||||
|
|
||||||
|
class FanBaseSchema(SystemBaseSchema):
|
||||||
|
"""
|
||||||
|
Base schema for system fan sensors.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@pre_load
|
||||||
|
def pre_load(self, data: dict, **_) -> dict:
|
||||||
|
data = super().pre_load(data)
|
||||||
|
data['value'] = data.pop('current', data.pop('value', None))
|
||||||
|
return data
|
35
platypush/schemas/system/_fan/_model.py
Normal file
35
platypush/schemas/system/_fan/_model.py
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Fan:
|
||||||
|
"""
|
||||||
|
System fan sensor data class.
|
||||||
|
"""
|
||||||
|
|
||||||
|
id: str = field(
|
||||||
|
metadata={
|
||||||
|
'metadata': {
|
||||||
|
'description': 'Unique ID for the sensor',
|
||||||
|
'example': 'acpi_1',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
label: str = field(
|
||||||
|
metadata={
|
||||||
|
'metadata': {
|
||||||
|
'description': 'Name of the sensor',
|
||||||
|
'example': 'CPU',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
value: float = field(
|
||||||
|
metadata={
|
||||||
|
'metadata': {
|
||||||
|
'description': 'Current fan speed, in RPM',
|
||||||
|
'example': 3000,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
7
platypush/schemas/system/_fan/_schemas.py
Normal file
7
platypush/schemas/system/_fan/_schemas.py
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
from marshmallow_dataclass import class_schema
|
||||||
|
|
||||||
|
from ._base import FanBaseSchema
|
||||||
|
from ._model import Fan
|
||||||
|
|
||||||
|
|
||||||
|
FanSchema = class_schema(Fan, base_schema=FanBaseSchema)
|
|
@ -3,6 +3,7 @@ from typing import List
|
||||||
|
|
||||||
from ._cpu import Cpu
|
from ._cpu import Cpu
|
||||||
from ._disk import Disk
|
from ._disk import Disk
|
||||||
|
from ._fan import Fan
|
||||||
from ._memory import MemoryStats, SwapStats
|
from ._memory import MemoryStats, SwapStats
|
||||||
from ._network import NetworkInterface
|
from ._network import NetworkInterface
|
||||||
from ._temperature import Temperature
|
from ._temperature import Temperature
|
||||||
|
@ -20,3 +21,4 @@ class SystemInfo:
|
||||||
disks: List[Disk]
|
disks: List[Disk]
|
||||||
network: List[NetworkInterface]
|
network: List[NetworkInterface]
|
||||||
temperature: List[Temperature]
|
temperature: List[Temperature]
|
||||||
|
fans: List[Fan]
|
||||||
|
|
Loading…
Reference in a new issue