Execution multithread

This commit is contained in:
2025-08-24 14:48:51 +02:00
parent 96b0cd9b99
commit 083cfcce1d
2 changed files with 114 additions and 63 deletions

View File

@@ -82,18 +82,6 @@ devices:
HA_device_class: "connectivity" HA_device_class: "connectivity"
HA_platform: "binary_sensor" HA_platform: "binary_sensor"
# Example of how to add another device:
# another_device:
# ip: "192.168.10.3"
# snmp_community: "public"
# oids:
# - name: "cpu_usage"
# oid: ".1.3.6.1.4.1.14988.1.1.3.14.0" # MikroTik CPU usage
# type: "int"
# HA_device_class: "power_factor"
# HA_platform: "sensor"
# HA_unit: "%"
# OID Configuration Reference: # OID Configuration Reference:
# - name: Unique identifier for this metric (used in MQTT topics and Home Assistant) # - name: Unique identifier for this metric (used in MQTT topics and Home Assistant)
# - oid: SNMP Object Identifier # - oid: SNMP Object Identifier

View File

@@ -11,12 +11,83 @@ import yaml
import argparse import argparse
import sys import sys
import os import os
import threading
import signal
import time
logging.basicConfig( logging.basicConfig(
format='(%(levelname)s) %(message)s', format='(%(levelname)s) [%(threadName)s] %(message)s',
level=logging.DEBUG level=logging.DEBUG
) )
# Global shutdown flag
shutdown_event = threading.Event()
class DeviceMonitorThread(threading.Thread):
"""Thread class for monitoring a single device"""
def __init__(self, device_name, device_config, mqtt_config, sleep_interval=2):
super().__init__(name=f"Device-{device_name}")
self.device_name = device_name
self.device_config = device_config
self.mqtt_config = mqtt_config.copy()
self.sleep_interval = sleep_interval
self.daemon = True # Dies when main thread dies
# Create unique client ID for this device
self.mqtt_config['client_id'] = f"snmp-mqtt-{device_name}-{random.randint(0, 1000)}"
# Create device request object
self.req = {
"device_name": device_name,
"ip": device_config["ip"],
"snmp_community": device_config["snmp_community"],
"oids": device_config["oids"]
}
def run(self):
"""Main thread execution"""
logging.info(f"Starting monitoring thread for device: {self.device_name} ({self.device_config['ip']})")
try:
# Setup MQTT connection and Home Assistant config
ha_config = ha_create_config(self.req)
client = connect_mqtt(self.mqtt_config)
client.loop_start()
config_topic = f"homeassistant/device/{ha_config['dev']['ids']}/config"
state_topic = ha_config['state_topic']
logging.info(f"[{self.device_name}] MQTT client connected, starting monitoring loop")
while not shutdown_event.is_set():
try:
# Publish Home Assistant configuration
publish(config_topic, client, ha_config, True, 0)
logging.debug(f"[{self.device_name}] Published config to {config_topic}")
# Get SNMP data and publish state
state = asyncio.run(get_snmp(self.req))
publish(state_topic, client, state, False, 0)
logging.debug(f"[{self.device_name}] Published state to {state_topic}: {json.dumps(state)}")
except Exception as e:
logging.error(f"[{self.device_name}] Error in monitoring loop: {e}")
# Wait for next iteration or shutdown signal
shutdown_event.wait(timeout=self.sleep_interval)
# Cleanup
client.loop_stop()
client.disconnect()
logging.info(f"[{self.device_name}] Monitoring thread stopped gracefully")
except Exception as e:
logging.error(f"[{self.device_name}] Fatal error in monitoring thread: {e}")
logging.info(f"[{self.device_name}] Thread {self.name} finished")
def parse_arguments(): def parse_arguments():
"""Parse command line arguments""" """Parse command line arguments"""
@@ -180,63 +251,55 @@ def ha_create_config(req):
return ha_config return ha_config
def send_to_mqtt(device_name, device_config, mqtt_config, sleep_interval=2): def signal_handler(signum, frame):
"""Send SNMP data to MQTT for a single device""" """Handle shutdown signals gracefully"""
# Create device request object logging.info(f"Received signal {signum}, initiating graceful shutdown...")
req = { shutdown_event.set()
"device_name": device_name,
"ip": device_config["ip"],
"snmp_community": device_config["snmp_community"],
"oids": device_config["oids"]
}
config = ha_create_config(req)
client = connect_mqtt(mqtt_config)
client.loop_start()
config_topic = f"homeassistant/device/{config['dev']['ids']}/config"
state_topic = config['state_topic']
while True:
try:
publish(config_topic, client, config, True, 0)
logging.info(f"{config_topic} -> {config}")
except Exception as e:
logging.error(f"Error publishing config for {device_name}: {e}")
pass
try:
state = asyncio.run(get_snmp(req))
publish(state_topic, client, state, False, 0)
logging.info(f"{state_topic} -> {state}")
except Exception as e:
logging.error(f"Error getting SNMP data for {device_name}: {e}")
pass
sleep(sleep_interval)
def process_devices(config): def process_devices(config):
"""Process multiple devices from configuration""" """Process multiple devices using threading"""
mqtt_config = config['mqtt'].copy() mqtt_config = config['mqtt'].copy()
mqtt_config['client_id'] = f"snmp-mqtt-{random.randint(0, 1000)}"
# Get sleep interval from config or use default
sleep_interval = config.get('sleep_interval', 2) sleep_interval = config.get('sleep_interval', 2)
if len(config['devices']) == 1: # Setup signal handlers for graceful shutdown
# Single device mode - run directly signal.signal(signal.SIGINT, signal_handler)
device_name = list(config['devices'].keys())[0] signal.signal(signal.SIGTERM, signal_handler)
device_config = config['devices'][device_name]
logging.info(f"Starting monitoring for single device: {device_name}") device_threads = []
send_to_mqtt(device_name, device_config, mqtt_config, sleep_interval)
else: try:
# Multiple devices mode - would need threading/multiprocessing logging.info(f"Starting monitoring for {len(config['devices'])} device(s)")
# For now, let's process the first device and warn about others
logging.warning(f"Multiple devices detected ({len(config['devices'])}), but only processing the first one")
logging.warning("Multi-device support will require threading implementation")
device_name = list(config['devices'].keys())[0] # Create and start a thread for each device
device_config = config['devices'][device_name] for device_name, device_config in config['devices'].items():
logging.info(f"Starting monitoring for device: {device_name}") thread = DeviceMonitorThread(
send_to_mqtt(device_name, device_config, mqtt_config, sleep_interval) device_name=device_name,
device_config=device_config,
mqtt_config=mqtt_config,
sleep_interval=sleep_interval
)
device_threads.append(thread)
thread.start()
logging.info(f"Started thread for device: {device_name}")
# Wait for all threads to complete or shutdown signal
while any(thread.is_alive() for thread in device_threads) and not shutdown_event.is_set():
time.sleep(0.5)
except Exception as e:
logging.error(f"Error in process_devices: {e}")
shutdown_event.set()
# Wait for all threads to finish
logging.info("Waiting for all monitoring threads to finish...")
for thread in device_threads:
if thread.is_alive():
thread.join(timeout=5.0) # Wait max 5 seconds per thread
if thread.is_alive():
logging.warning(f"Thread {thread.name} did not stop gracefully")
logging.info("All monitoring threads have finished")
def main(): def main():