Initial commit: System2MQTT implementation
This commit is contained in:
121
collectors/cpu_temperature.py
Normal file
121
collectors/cpu_temperature.py
Normal 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)
|
162
collectors/system_metrics.py
Normal file
162
collectors/system_metrics.py
Normal 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)
|
Reference in New Issue
Block a user