Converted to PyPy package

This commit is contained in:
Christian Busch 2025-05-23 18:03:13 +02:00
parent 6e6f22f5d4
commit 4878866ada
13 changed files with 218 additions and 243 deletions

15
.gitignore vendored
View File

@ -21,7 +21,6 @@ wheels/
*.egg *.egg
# Virtual Environment # Virtual Environment
.venv/
venv/ venv/
env/ env/
ENV/ ENV/
@ -32,9 +31,15 @@ ENV/
*.swp *.swp
*.swo *.swo
# OS # Testing
.DS_Store .coverage
Thumbs.db htmlcov/
.pytest_cache/
# Project specific # Distribution
dist/
build/
*.egg-info/
# Local configuration
config.yaml config.yaml

6
MANIFEST.in Normal file
View File

@ -0,0 +1,6 @@
include LICENSE
include README.md
include requirements.txt
include config.yaml.example
recursive-include src/system2mqtt *.py
recursive-include src/system2mqtt/collectors *.py

View File

@ -1,88 +0,0 @@
#!/usr/bin/env python3
import os
import sys
import yaml
import paho.mqtt.client as mqtt
import time
def load_config():
"""Load configuration from YAML file."""
try:
with open('config.yaml', 'r') as f:
return yaml.safe_load(f)
except Exception as e:
print(f"Error loading config: {e}")
sys.exit(1)
def on_connect(client, userdata, flags, rc):
"""Callback for when the client connects to the MQTT broker."""
if rc == 0:
print("Connected to MQTT broker")
else:
print(f"Failed to connect, return code {rc}")
sys.exit(1)
def on_message(client, userdata, message):
"""Callback for when a message is received."""
userdata.append(message.topic)
def get_topics(client, timeout=1):
"""Get all system2mqtt topics from the MQTT broker."""
topics = []
client.user_data_set(topics)
client.on_message = on_message
# Subscribe to all topics
client.subscribe('#')
client.loop_start()
# Wait for messages
time.sleep(timeout)
client.loop_stop()
client.unsubscribe('#')
# Filter for system2mqtt topics
return [topic for topic in topics if 'system2mqtt' in topic]
def cleanup_topics(config):
"""Clean up MQTT topics."""
# Create MQTT client
client = mqtt.Client()
client.username_pw_set(config['mqtt']['username'], config['mqtt']['password'])
client.on_connect = on_connect
# Connect to MQTT broker
try:
print(f"Connecting to MQTT broker at {config['mqtt']['host']}:{config['mqtt']['port']}...")
client.connect(config['mqtt']['host'], config['mqtt']['port'], 60)
except Exception as e:
print(f"Failed to connect to MQTT broker: {e}")
sys.exit(1)
# Get all system2mqtt topics
print("Finding system2mqtt topics...")
topics = get_topics(client)
if not topics:
print("No system2mqtt topics found")
return
# Delete each topic
for topic in topics:
print(f"Deleting topic: {topic}")
client.publish(topic, "", retain=True)
time.sleep(0.1) # Small delay between deletions
# Wait for messages to be published
time.sleep(1)
# Stop the MQTT client loop and disconnect
client.disconnect()
print("Cleanup completed")
if __name__ == "__main__":
config = load_config()
cleanup_topics(config)

20
pyproject.toml Normal file
View File

@ -0,0 +1,20 @@
[build-system]
requires = ["setuptools>=42", "wheel"]
build-backend = "setuptools.build_meta"
[tool.black]
line-length = 100
target-version = ['py38']
include = '\.pyi?$'
[tool.isort]
profile = "black"
multi_line_output = 3
line_length = 100
[tool.mypy]
python_version = "3.8"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true
disallow_incomplete_defs = true

View File

@ -1,3 +1,8 @@
paho-mqtt==1.6.1 paho-mqtt>=2.0.0
psutil==5.9.5 psutil>=5.9.0
PyYAML==6.0.1 pyyaml>=6.0
black>=23.0.0
isort>=5.12.0
mypy>=1.0.0
pytest>=7.0.0
pytest-cov>=4.0.0

73
run.sh
View File

@ -1,73 +0,0 @@
#!/bin/bash
# Virtual environment directory
VENV_DIR=".venv"
# Function to show usage
show_usage() {
echo "Usage: $0 [start|stop|cleanup]"
echo
echo "Commands:"
echo " start - Start the system2mqtt service"
echo " stop - Stop the system2mqtt service"
echo " cleanup - Clean up all system2mqtt MQTT topics"
echo
exit 1
}
# Function to setup virtual environment
setup_venv() {
# Create virtual environment if it doesn't exist
if [ ! -d "$VENV_DIR" ]; then
echo "Creating virtual environment..."
python3 -m venv "$VENV_DIR"
fi
# Activate virtual environment
source "$VENV_DIR/bin/activate"
# Install/update dependencies
echo "Installing/updating dependencies..."
pip install -r requirements.txt
}
# Function to start the service
start_service() {
echo "Starting system2mqtt..."
setup_venv
python3 main.py
}
# Function to stop the service
stop_service() {
echo "Stopping system2mqtt..."
pkill -f "python3 main.py"
}
# Function to cleanup MQTT topics
cleanup_topics() {
echo "Running MQTT cleanup..."
setup_venv
python3 cleanup_mqtt.py
}
# Check if a command was provided
if [ $# -eq 0 ]; then
show_usage
fi
# Process command
case "$1" in
start)
start_service
;;
stop)
stop_service
;;
cleanup)
cleanup_topics
;;
*)
show_usage
;;
esac

43
setup.py Executable file
View File

@ -0,0 +1,43 @@
from setuptools import setup, find_packages
with open("README.md", "r", encoding="utf-8") as fh:
long_description = fh.read()
setup(
name="system2mqtt",
version="0.1.0",
author="Christian Busch",
author_email="hello@chbus.ch",
description="A system for monitoring hosts by collecting metrics and sending them to Home Assistant via MQTT",
long_description=long_description,
long_description_content_type="text/markdown",
url="https://git.debilux.org/chris/system2mqtt",
package_dir={"": "src"},
packages=find_packages(where="src"),
classifiers=[
"Development Status :: 4 - Beta",
"Intended Audience :: System Administrators",
"License :: OSI Approved :: MIT License",
"Operating System :: POSIX :: Linux",
"Operating System :: POSIX :: BSD :: FreeBSD",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Topic :: System :: Monitoring",
"Topic :: System :: Systems Administration",
],
python_requires=">=3.8",
install_requires=[
"paho-mqtt>=2.0.0",
"psutil>=5.9.0",
"pyyaml>=6.0",
],
entry_points={
"console_scripts": [
"system2mqtt=system2mqtt.main:main",
],
},
include_package_data=True,
)

View File

@ -0,0 +1,20 @@
"""
Collectors package for system2mqtt.
Contains various collectors for different system metrics.
"""
from .base_collector import BaseCollector
from .cpu_collector import CPUCollector
from .memory_collector import MemoryCollector
from .disk_collector import DiskCollector
from .network_collector import NetworkCollector
from .zfs_collector import ZFSCollector
__all__ = [
'BaseCollector',
'CPUCollector',
'MemoryCollector',
'DiskCollector',
'NetworkCollector',
'ZFSCollector',
]

View File

@ -10,9 +10,48 @@ import importlib
import paho.mqtt.client as mqtt import paho.mqtt.client as mqtt
from typing import Dict, Any, List from typing import Dict, Any, List
import yaml import yaml
from pathlib import Path
def get_config_path():
"""Get the path to the config file.
Returns:
Path: Path to the config file
"""
# First check if config file is specified via environment variable
if config_path := os.environ.get('SYSTEM2MQTT_CONFIG'):
return Path(config_path)
# Then check user's config directory
if sys.platform == 'win32':
config_dir = Path(os.environ['APPDATA']) / 'system2mqtt'
else:
config_dir = Path.home() / '.config' / 'system2mqtt'
config_file = config_dir / 'config.yaml'
# Create config directory if it doesn't exist
config_dir.mkdir(parents=True, exist_ok=True)
# If config file doesn't exist, copy example config
if not config_file.exists():
example_config = Path(__file__).parent.parent.parent / 'config.yaml.example'
if example_config.exists():
import shutil
shutil.copy(example_config, config_file)
print(f"Created config file at {config_file}")
print("Please edit the config file and restart the application.")
sys.exit(1)
else:
print("Error: Neither config.yaml nor config.yaml.example found!")
sys.exit(1)
return config_file
# Load configuration # Load configuration
with open('config.yaml', 'r') as f: def main():
config_path = get_config_path()
with open(config_path, 'r') as f:
config = yaml.safe_load(f) config = yaml.safe_load(f)
# MQTT Configuration # MQTT Configuration
@ -85,8 +124,6 @@ def on_disconnect(client: mqtt.Client, userdata: Any, rc: int) -> None:
if rc != 0: if rc != 0:
print("Unexpected disconnection. Attempting to reconnect...") print("Unexpected disconnection. Attempting to reconnect...")
def main():
"""Main function."""
# Create MQTT client # Create MQTT client
client = mqtt.Client(client_id=MQTT_CLIENT_ID) client = mqtt.Client(client_id=MQTT_CLIENT_ID)
client.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD) client.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD)