Initial commit: System2MQTT implementation

This commit is contained in:
2025-05-22 07:56:25 +02:00
commit dc1d276df6
10 changed files with 997 additions and 0 deletions

View File

@@ -0,0 +1,121 @@
#!/usr/bin/env python3
import os
import platform
import subprocess
import glob
from typing import Dict, Any, Optional, List, Tuple
import sys
def get_temperature_linux_coretemp() -> List[Tuple[float, str]]:
"""Get CPU temperatures using coretemp module."""
temps = []
try:
for hwmon_dir in glob.glob('/sys/class/hwmon/hwmon*'):
try:
with open(os.path.join(hwmon_dir, 'name'), 'r') as f:
if f.read().strip() == 'coretemp':
# Found coretemp, get all temperatures
for temp_file in glob.glob(os.path.join(hwmon_dir, 'temp*_input')):
try:
with open(temp_file, 'r') as tf:
temp = float(tf.read().strip()) / 1000.0
# Get label if available
label = "Package"
label_file = temp_file.replace('_input', '_label')
if os.path.exists(label_file):
with open(label_file, 'r') as lf:
label = lf.read().strip()
temps.append((temp, label))
except (FileNotFoundError, ValueError):
continue
except (FileNotFoundError, ValueError):
continue
except Exception:
pass
return temps
def get_temperature_linux_thermal() -> List[Tuple[float, str]]:
"""Get CPU temperatures using thermal zones."""
temps = []
try:
for thermal_dir in glob.glob('/sys/class/thermal/thermal_zone*'):
try:
with open(os.path.join(thermal_dir, 'type'), 'r') as f:
zone_type = f.read().strip()
if 'cpu' in zone_type.lower():
with open(os.path.join(thermal_dir, 'temp'), 'r') as tf:
temp = float(tf.read().strip()) / 1000.0
temps.append((temp, zone_type))
except (FileNotFoundError, ValueError):
continue
except Exception:
pass
return temps
def get_temperature_freebsd() -> List[Tuple[float, str]]:
"""Get CPU temperatures on FreeBSD systems."""
temps = []
try:
# Get number of CPUs
cpu_count = int(subprocess.check_output(['sysctl', '-n', 'hw.ncpu']).decode().strip())
# Get temperature for each CPU
for cpu in range(cpu_count):
try:
temp = subprocess.check_output(['sysctl', '-n', f'dev.cpu.{cpu}.temperature']).decode().strip()
temp_value = float(temp)
temps.append((temp_value, f'CPU {cpu}'))
except (subprocess.SubprocessError, ValueError):
continue
except (subprocess.SubprocessError, ValueError):
pass
return temps
def collect_metrics() -> Dict[str, Any]:
"""Collect CPU temperature metrics."""
metrics = {
"entities": []
}
temps = []
# Get CPU temperatures based on OS
if sys.platform.startswith('linux'):
# Try coretemp first (most reliable)
temps.extend(get_temperature_linux_coretemp())
# If no coretemp found, try thermal zones
if not temps:
temps.extend(get_temperature_linux_thermal())
elif sys.platform.startswith('freebsd'):
temps.extend(get_temperature_freebsd())
# Add temperature sensors
if temps:
# Only keep package temperatures
package_temps = [(t, l) for t, l in temps if 'Package' in l]
# Add package temperature
for temp, label in package_temps:
metrics['entities'].append({
'sensor_id': 'cpu_temperature',
'name': 'CPU Temperature',
'value': str(round(temp, 1)),
'state_class': 'measurement',
'unit_of_measurement': '°C',
'device_class': 'temperature',
'icon': 'mdi:thermometer',
'attributes': {
'friendly_name': 'CPU Temperature',
'source': 'coretemp'
}
})
return metrics
if __name__ == "__main__":
# Example usage
metrics = collect_metrics()
print(metrics)

View File

@@ -0,0 +1,162 @@
#!/usr/bin/env python3
import psutil
import time
from datetime import datetime
from typing import Dict, Any
def collect_metrics() -> Dict[str, Any]:
"""Collect system metrics and return them in the required format."""
# Get system metrics
boot_time = datetime.fromtimestamp(psutil.boot_time())
load_avg = psutil.getloadavg()
memory = psutil.virtual_memory()
swap = psutil.swap_memory()
cpu_percent = psutil.cpu_percent(interval=1)
# Convert bytes to GB
def to_gb(bytes_value: int) -> float:
return round(bytes_value / (1024**3), 2)
return {
"version": "1.0",
"entities": [
{
"name": "Last Boot",
"sensor_id": "last_boot",
"state_class": "total",
"device_class": "timestamp",
"unit_of_measurement": "",
"value": boot_time.astimezone().isoformat(),
"icon": "mdi:clock-time-four",
"attributes": {
"friendly_name": "Last Boot Time"
}
},
{
"name": "Load Average (15m)",
"sensor_id": "load_15m",
"state_class": "measurement",
"unit_of_measurement": "",
"device_class": "power_factor",
"value": str(round(load_avg[2], 1)),
"icon": "mdi:gauge",
"attributes": {
"friendly_name": "System Load (15m)"
}
},
{
"name": "Load Average (5m)",
"sensor_id": "load_5m",
"state_class": "measurement",
"unit_of_measurement": "",
"device_class": "power_factor",
"value": str(round(load_avg[1], 1)),
"icon": "mdi:gauge",
"attributes": {
"friendly_name": "System Load (5m)"
}
},
{
"name": "Load Average (1m)",
"sensor_id": "load_1m",
"state_class": "measurement",
"unit_of_measurement": "",
"device_class": "power_factor",
"value": str(round(load_avg[0], 1)),
"icon": "mdi:gauge",
"attributes": {
"friendly_name": "System Load (1m)"
}
},
{
"name": "Memory Free",
"sensor_id": "memory_free",
"state_class": "measurement",
"unit_of_measurement": "GB",
"device_class": "data_size",
"value": str(to_gb(memory.available)),
"icon": "mdi:memory",
"attributes": {
"friendly_name": "Available Memory"
}
},
{
"name": "Memory Used",
"sensor_id": "memory_used",
"state_class": "measurement",
"unit_of_measurement": "GB",
"device_class": "data_size",
"value": str(to_gb(memory.used)),
"icon": "mdi:memory",
"attributes": {
"friendly_name": "Used Memory"
}
},
{
"name": "Memory Usage",
"sensor_id": "memory_usage",
"state_class": "measurement",
"unit_of_measurement": "%",
"device_class": "power_factor",
"value": str(memory.percent),
"icon": "mdi:memory",
"attributes": {
"friendly_name": "Memory Usage"
}
},
{
"name": "CPU Usage",
"sensor_id": "cpu_usage",
"state_class": "measurement",
"unit_of_measurement": "%",
"device_class": "power_factor",
"value": str(cpu_percent),
"icon": "mdi:cpu-64-bit",
"attributes": {
"friendly_name": "CPU Usage"
}
},
{
"name": "Swap Free",
"sensor_id": "swap_free",
"state_class": "measurement",
"unit_of_measurement": "GB",
"device_class": "data_size",
"value": str(to_gb(swap.free)),
"icon": "mdi:harddisk",
"attributes": {
"friendly_name": "Free Swap"
}
},
{
"name": "Swap Used",
"sensor_id": "swap_used",
"state_class": "measurement",
"unit_of_measurement": "GB",
"device_class": "data_size",
"value": str(to_gb(swap.used)),
"icon": "mdi:harddisk",
"attributes": {
"friendly_name": "Used Swap"
}
},
{
"name": "Swap Usage",
"sensor_id": "swap_usage",
"state_class": "measurement",
"unit_of_measurement": "%",
"device_class": "power_factor",
"value": str(swap.percent),
"icon": "mdi:harddisk",
"attributes": {
"friendly_name": "Swap Usage"
}
}
]
}
if __name__ == "__main__":
# Example usage
metrics = collect_metrics()
print(metrics)