2 Commits

Author SHA1 Message Date
7199432169 Informations sur le multithreading 2025-08-24 15:19:24 +02:00
083cfcce1d Execution multithread 2025-08-24 14:48:51 +02:00
3 changed files with 171 additions and 64 deletions

View File

@@ -263,7 +263,63 @@ ping 192.168.10.202
## Support multi-équipements ## Support multi-équipements
**Note** : Le support complet multi-équipements nécessite une implémentation avec threading/multiprocessing. Actuellement, le script traite le premier équipement de la liste et affiche un avertissement pour les autres. Le script supporte nativement la surveillance simultanée de plusieurs équipements grâce à une architecture **multi-threading** :
### Fonctionnement
- **Thread indépendant** pour chaque équipement configuré
- **Surveillance parallèle** : tous les équipements sont surveillés simultanément
- **Isolation des erreurs** : la défaillance d'un équipement n'affecte pas les autres
- **Clients MQTT séparés** : chaque thread utilise son propre client MQTT
- **Arrêt gracieux** : tous les threads s'arrêtent proprement sur signal
### Avantages
-**Performance optimale** : pas de blocage entre équipements
- 🔄 **Traitement parallèle** : requêtes SNMP simultanées
- 🛡️ **Robustesse** : isolation des défaillances
- 📊 **Scalabilité** : facilement extensible à des dizaines d'équipements
- 🔧 **Maintenance** : logs clairement identifiés par équipement
### Configuration multi-équipements
```yaml
devices:
routeur_principal:
ip: "192.168.10.1"
snmp_community: "public"
oids:
# ... configuration OID ...
switch_bureau:
ip: "192.168.10.5"
snmp_community: "public"
oids:
# ... configuration OID ...
point_acces_wifi:
ip: "192.168.10.10"
snmp_community: "private"
oids:
# ... configuration OID ...
```
### Logs multi-threading
Chaque thread est clairement identifié dans les logs :
```
(INFO) [Device-routeur_principal] Starting monitoring thread
(INFO) [Device-switch_bureau] MQTT client connected
(DEBUG) [Device-point_acces_wifi] Published state to SNMP/point_acces_wifi/state
```
### Gestion des ressources
- **Clients MQTT uniques** : ID client basé sur le nom de l'équipement
- **Topics séparés** : chaque équipement a ses propres topics MQTT
- **Discovery HA indépendante** : configuration Home Assistant par équipement
- **Disponibilité individuelle** : statut online/offline par équipement
## Logs et debugging ## Logs et debugging

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():