Skip to content

Commit

Permalink
Adding Fanspeed Entity for Linux (#80)
Browse files Browse the repository at this point in the history
* init fanspeed and first mock

* working for linux, still wip

* add readme and todos

* rename venv to be ignored

* cleanup

* remove debug prints

* add Rotation ValueFormat as rpm

* rename and create link to Deployments

* change to hardlink, add units, move test to correct location, update images

* implement config dialog

* format and link

* code more readable

* docstrings and formatting, fix update

* fix menu preset

* more work on test

* Delete .gitignore

* Delete changes in IoTuring/Configurator/ConfiguratorIO.py

* Delete softlink

was a softlink for developement

* remove dev temps

* whoops forgot the code

* cleanup

* first mock for state as num of fans above threshold

* configurable threshold, entity state = amount of fans above that threshold

* docstrings

* remove unit from entity state, but keep rpm for attributes

* unify unix systems as psutil seems consistent, check for attributes on sensors

* remove default from printed config string, redo sensorlabel fallback

* redo configuration to be more readable and easier

* update configuration, redo update method cleaner

* restore consts.py

* remove tests

* add FALLBACK labels when blank, addd some logging, raise NotImplementedError on blank controllername

* more granular check for psutil support/ found fans

* remove config, extra classes and threshold, entityState->max(rpm),)

* cleanup, add unit back since were only talking rpm now

* Small semantics

* Fanspeed is not multi instance

* Update readme

---------

Co-authored-by: infeeeee <gyetpet@mailbox.org>
  • Loading branch information
lockenkop and infeeeee authored Dec 13, 2023
1 parent e085f30 commit 8705430
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 7 deletions.
95 changes: 95 additions & 0 deletions IoTuring/Entity/Deployments/Fanspeed/Fanspeed.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import psutil
from IoTuring.Entity.Entity import Entity
from IoTuring.Entity.EntityData import EntitySensor
from IoTuring.Entity.ValueFormat import ValueFormatterOptions
from IoTuring.MyApp.SystemConsts import OperatingSystemDetection as OsD


VALUEFORMATTEROPTIONS_FANSPEED_RPM = ValueFormatterOptions(
value_type=ValueFormatterOptions.TYPE_ROTATION)


FALLBACK_CONTROLLER_LABEL = "controller"
FALLBACK_FAN_LABEL = "fan"


class Fanspeed(Entity):
"""Entity to read fanspeed"""
NAME = "Fanspeed"

def Initialize(self) -> None:
"""Initialize the Class, setup Formatter, determin specificInitialize and specificUpdate depending on OS"""

self.specificInitialize = None
self.specificUpdate = None

if OsD.IsLinux():
# psutil docs: no attribute -> system not supported
if not hasattr(psutil, "sensors_fans"):
raise Exception("System not supported by psutil")
# psutil docs: empty dict -> no fancontrollers reporting
if not bool(psutil.sensors_fans()):
raise Exception("No fan found in system")
self.specificInitialize = self.InitLinux
self.specificUpdate = self.UpdateLinux

else:
raise NotImplementedError

self.specificInitialize()

def InitLinux(self) -> None:
"""OS dependant Init for Linux"""
sensors = psutil.sensors_fans()
self.Log(self.LOG_DEBUG, f"fancontrollers found:{sensors}")

for i, controller in enumerate(sensors):
# use FALLBACK for blank controllernames
controllerName = controller or FALLBACK_CONTROLLER_LABEL + str(i)

# Add extra attributes only if there are multiple fans:
hasMultipleFans = bool(len(sensors[controller]) > 1)

# register an entity for each controller
self.RegisterEntitySensor(
EntitySensor(
self,
controllerName,
supportsExtraAttributes=hasMultipleFans,
valueFormatterOptions=VALUEFORMATTEROPTIONS_FANSPEED_RPM,
)
)

def Update(self) -> None:
"""placeholder for OS specificUpdate"""
if self.specificUpdate:
self.specificUpdate()
else:
raise NotImplementedError

def UpdateLinux(self) -> None:
"""Updatemethod for Linux"""
for controller, fans in psutil.sensors_fans().items():
# get all fanspeed in a list and find max
highest_fan = max([fan.current for fan in fans])
# find higest fanspeed and assign the entity state
self.SetEntitySensorValue(
key=controller,
value=highest_fan)
# Set extra attributes {fan name : fanspeed in rpm}
self.Log(self.LOG_DEBUG,
f"updating controller:{controller} with {fans}")

# Add fans as extra attributes, if there are more than one:
if len(fans) > 1:
for i, fan in enumerate(fans):
# appy FALLBACK if label is blank
fanlabel = fan.label or FALLBACK_FAN_LABEL + str(i)

# set extra attributes for each fan
self.SetEntitySensorExtraAttribute(
controller,
fanlabel,
fan.current,
valueFormatterOptions=VALUEFORMATTEROPTIONS_FANSPEED_RPM,
)
16 changes: 16 additions & 0 deletions IoTuring/Entity/ValueFormat/ValueFormatter.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
FREQUENCY_SIZES = ['Hz', 'kHz', 'MHz', 'GHz']
TIME_SIZES_DIVIDERS = [1, 60, 60, 24]
CELSIUS_UNIT = '°C'
ROTATION = ['rpm']

SPACE_BEFORE_UNIT = ' '

Expand Down Expand Up @@ -50,6 +51,8 @@ def _ParseValue(value, options: ValueFormatterOptions | None, includeUnit: bool)
return ValueFormatter.FrequencyFormatter(value, options, includeUnit)
elif valueType == ValueFormatterOptions.TYPE_TEMPERATURE:
return ValueFormatter.TemperatureCelsiusFormatter(value, options, includeUnit)
elif valueType == ValueFormatterOptions.TYPE_ROTATION:
return ValueFormatter.RoundsPerMinuteFormatter(value, options, includeUnit)
elif valueType == ValueFormatterOptions.TYPE_PERCENTAGE:
if includeUnit:
return str(value) + SPACE_BEFORE_UNIT + '%'
Expand Down Expand Up @@ -152,6 +155,19 @@ def TemperatureCelsiusFormatter(value, options: ValueFormatterOptions, includeUn
result = result + SPACE_BEFORE_UNIT + CELSIUS_UNIT
return result

@staticmethod
def RoundsPerMinuteFormatter(value, options: ValueFormatterOptions, includeUnit: bool):
# asked_size not implemented

# decimals
value = ValueFormatter.roundValue(value, options)

result = str(value)

if includeUnit:
result = result + SPACE_BEFORE_UNIT + ROTATION[0]
return result

@staticmethod
def roundValue(value, options: ValueFormatterOptions):
if options.get_decimals() != ValueFormatterOptions.DO_NOT_TOUCH_DECIMALS:
Expand Down
1 change: 1 addition & 0 deletions IoTuring/Entity/ValueFormat/ValueFormatterOptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ class ValueFormatterOptions():
TYPE_FREQUENCY = 4
TYPE_MILLISECONDS = 5
TYPE_TEMPERATURE = 6
TYPE_ROTATION = 7

DO_NOT_TOUCH_DECIMALS = -1

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ AppInfo:
Temperature:
icon: mdi:thermometer-lines
unit_of_measurement: °C
Fanspeed:
icon: mdi:fan
unit_of_measurement: rpm
DisplayMode:
name: Display Mode
icon: mdi:monitor-multiple
Expand Down
15 changes: 8 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,29 +138,30 @@ All sensors and switches will be available to be added to your dashboard in your

### Available entities

| Name | Description | Supported platforms |
| ------------------ | --------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- |
| Name | Description | Supported platforms |
| ------------------ | --------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ActiveWindow | shares the name of the window you're working on | ![win](https://github.com/richibrics/IoTuring/blob/main/docs/images/win.png?raw=true) ![mac](https://raw.githubusercontent.com/richibrics/IoTuring/main/docs/images/mac.png) ![linux](https://raw.githubusercontent.com/richibrics/IoTuring/main/docs/images/linux.png) |
| AppInfo | shares app informations like the running version | ![win](https://github.com/richibrics/IoTuring/blob/main/docs/images/win.png?raw=true) ![mac](https://raw.githubusercontent.com/richibrics/IoTuring/main/docs/images/mac.png) ![linux](https://raw.githubusercontent.com/richibrics/IoTuring/main/docs/images/linux.png) |
| Battery | shares the battery level and charging status | ![win](https://github.com/richibrics/IoTuring/blob/main/docs/images/win.png?raw=true) ![mac](https://raw.githubusercontent.com/richibrics/IoTuring/main/docs/images/mac.png) ![linux](https://raw.githubusercontent.com/richibrics/IoTuring/main/docs/images/linux.png) |
| BootTime | shares the machine boot time | ![win](https://github.com/richibrics/IoTuring/blob/main/docs/images/win.png?raw=true) ![mac](https://raw.githubusercontent.com/richibrics/IoTuring/main/docs/images/mac.png) ![linux](https://raw.githubusercontent.com/richibrics/IoTuring/main/docs/images/linux.png) |
| Cpu | shares useful information about cpu usage (times, frequencies, percentages) | ![win](https://github.com/richibrics/IoTuring/blob/main/docs/images/win.png?raw=true) ![mac](https://raw.githubusercontent.com/richibrics/IoTuring/main/docs/images/mac.png) ![linux](https://raw.githubusercontent.com/richibrics/IoTuring/main/docs/images/linux.png) |
| DesktopEnvironment | shares the running desktop environment (useful only for Linux) | ![win](https://github.com/richibrics/IoTuring/blob/main/docs/images/win.png?raw=true) ![mac](https://raw.githubusercontent.com/richibrics/IoTuring/main/docs/images/mac.png) ![linux](https://raw.githubusercontent.com/richibrics/IoTuring/main/docs/images/linux.png) |
| Disk | shares disk usage data | ![win](https://github.com/richibrics/IoTuring/blob/main/docs/images/win.png?raw=true) ![mac](https://raw.githubusercontent.com/richibrics/IoTuring/main/docs/images/mac.png) ![linux](https://raw.githubusercontent.com/richibrics/IoTuring/main/docs/images/linux.png) |
| DisplayMode | command for changing multimonitor display mode | ![win](https://github.com/richibrics/IoTuring/blob/main/docs/images/win.png?raw=true) |
| DisplayMode | command for changing multimonitor display mode | ![win](https://github.com/richibrics/IoTuring/blob/main/docs/images/win.png?raw=true) |
| Fanspeed | shares maximum fanspeed of each controller | ![linux](https://raw.githubusercontent.com/richibrics/IoTuring/main/docs/images/linux.png) |
| Hostname | shares the machine hostname | ![win](https://github.com/richibrics/IoTuring/blob/main/docs/images/win.png?raw=true) ![mac](https://raw.githubusercontent.com/richibrics/IoTuring/main/docs/images/mac.png) ![linux](https://raw.githubusercontent.com/richibrics/IoTuring/main/docs/images/linux.png) |
| Lock | command for locking the machine | ![win](https://github.com/richibrics/IoTuring/blob/main/docs/images/win.png?raw=true) ![mac](https://raw.githubusercontent.com/richibrics/IoTuring/main/docs/images/mac.png) ![linux](https://raw.githubusercontent.com/richibrics/IoTuring/main/docs/images/linux.png) |
| Monitor | command for switching monitors on/off | ![win](https://github.com/richibrics/IoTuring/blob/main/docs/images/win.png?raw=true) ![linux](https://raw.githubusercontent.com/richibrics/IoTuring/main/docs/images/linux.png) |
| Monitor | command for switching monitors on/off | ![win](https://github.com/richibrics/IoTuring/blob/main/docs/images/win.png?raw=true) ![linux](https://raw.githubusercontent.com/richibrics/IoTuring/main/docs/images/linux.png) |
| Notify | displays a notification | ![win](https://github.com/richibrics/IoTuring/blob/main/docs/images/win.png?raw=true) ![mac](https://raw.githubusercontent.com/richibrics/IoTuring/main/docs/images/mac.png) ![linux](https://raw.githubusercontent.com/richibrics/IoTuring/main/docs/images/linux.png) |
| OperatingSystem | shares the operating system of your machine | ![win](https://github.com/richibrics/IoTuring/blob/main/docs/images/win.png?raw=true) ![mac](https://raw.githubusercontent.com/richibrics/IoTuring/main/docs/images/mac.png) ![linux](https://raw.githubusercontent.com/richibrics/IoTuring/main/docs/images/linux.png) |
| Power* | commands for poweroff, reboot and sleep | ![win](https://github.com/richibrics/IoTuring/blob/main/docs/images/win.png?raw=true) ![mac](https://raw.githubusercontent.com/richibrics/IoTuring/main/docs/images/mac.png) ![linux](https://raw.githubusercontent.com/richibrics/IoTuring/main/docs/images/linux.png) |
| Ram | shares useful information about ram usage | ![win](https://github.com/richibrics/IoTuring/blob/main/docs/images/win.png?raw=true) ![mac](https://raw.githubusercontent.com/richibrics/IoTuring/main/docs/images/mac.png) ![linux](https://raw.githubusercontent.com/richibrics/IoTuring/main/docs/images/linux.png) |
| Time | shares the machine local time | ![win](https://github.com/richibrics/IoTuring/blob/main/docs/images/win.png?raw=true) ![mac](https://raw.githubusercontent.com/richibrics/IoTuring/main/docs/images/mac.png) ![linux](https://raw.githubusercontent.com/richibrics/IoTuring/main/docs/images/linux.png) |
| Temperature | shares temperature sensor data | ![mac](https://raw.githubusercontent.com/richibrics/IoTuring/main/docs/images/mac.png) ![linux](https://raw.githubusercontent.com/richibrics/IoTuring/main/docs/images/linux.png) |
| Temperature | shares temperature sensor data | ![mac](https://raw.githubusercontent.com/richibrics/IoTuring/main/docs/images/mac.png) ![linux](https://raw.githubusercontent.com/richibrics/IoTuring/main/docs/images/linux.png) |
| Terminal | runs custom commands in the shell | ![win](https://github.com/richibrics/IoTuring/blob/main/docs/images/win.png?raw=true) ![mac](https://raw.githubusercontent.com/richibrics/IoTuring/main/docs/images/mac.png) ![linux](https://raw.githubusercontent.com/richibrics/IoTuring/main/docs/images/linux.png) |
| Time | shares the machine local time | ![win](https://github.com/richibrics/IoTuring/blob/main/docs/images/win.png?raw=true) ![mac](https://raw.githubusercontent.com/richibrics/IoTuring/main/docs/images/mac.png) ![linux](https://raw.githubusercontent.com/richibrics/IoTuring/main/docs/images/linux.png) |
| Uptime | shares the time since the machine is on | ![win](https://github.com/richibrics/IoTuring/blob/main/docs/images/win.png?raw=true) ![mac](https://raw.githubusercontent.com/richibrics/IoTuring/main/docs/images/mac.png) ![linux](https://raw.githubusercontent.com/richibrics/IoTuring/main/docs/images/linux.png) |
| Username | shares the name of the user who is working on the machine | ![win](https://github.com/richibrics/IoTuring/blob/main/docs/images/win.png?raw=true) ![mac](https://raw.githubusercontent.com/richibrics/IoTuring/main/docs/images/mac.png) ![linux](https://raw.githubusercontent.com/richibrics/IoTuring/main/docs/images/linux.png) |
| Volume | control audio volume | ![mac](https://raw.githubusercontent.com/richibrics/IoTuring/main/docs/images/mac.png) ![linux](https://raw.githubusercontent.com/richibrics/IoTuring/main/docs/images/linux.png) |
| Volume | control audio volume | ![mac](https://raw.githubusercontent.com/richibrics/IoTuring/main/docs/images/mac.png) ![linux](https://raw.githubusercontent.com/richibrics/IoTuring/main/docs/images/linux.png) |


\* To use the features from Power entity on macOS and on some Linux distros you need to give permissions to your user to shutdown and reboot without sudo password.
Expand Down

0 comments on commit 8705430

Please sign in to comment.