From ec1dad8e8cf33077f6bcd4a762f51480f32cee88 Mon Sep 17 00:00:00 2001 From: Antoine Van Elstraete Date: Thu, 10 Apr 2025 21:45:35 +0200 Subject: [PATCH] Auto discovery avec Home Assistant --- snmp2mqtt.py | 143 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 132 insertions(+), 11 deletions(-) mode change 100644 => 100755 snmp2mqtt.py diff --git a/snmp2mqtt.py b/snmp2mqtt.py old mode 100644 new mode 100755 index 16e3153..e24ce5f --- a/snmp2mqtt.py +++ b/snmp2mqtt.py @@ -3,7 +3,10 @@ import asyncio from pysnmp.hlapi.asyncio.slim import Slim from pysnmp.smi.rfc1902 import ObjectIdentity, ObjectType import logging - +import random +from paho.mqtt import client as mqtt_client +import json +from time import sleep logging.basicConfig( format='(%(levelname)s) %(message)s', @@ -11,16 +14,40 @@ logging.basicConfig( ) -async def run(req): +def connect_mqtt(mqtt_config): + def on_connect(client, userdata, flags, rc): + if rc == 0: + print("Connected to MQTT Broker!") + else: + print("Failed to connect, return code {rc}") + client = mqtt_client.Client() + client.username_pw_set(mqtt_config["user"], mqtt_config["password"]) + client.on_connect = on_connect + client.connect(mqtt_config['broker'], mqtt_config['port']) + return client + + +def publish(topic, client, data, retain, qos): + msg = json.dumps(data) + result = client.publish(topic=topic, payload=msg, qos=qos, retain=bool(retain)) + status = result[0] + if status == 0: + logging.debug(f"Send `{msg}` to topic `{topic}`") + else: + logging.error(f"Failed to send message to topic {topic}") + + +async def get_snmp(req): + data = {} for oid in req["oids"]: with Slim(1) as slim: errorIndication, errorStatus, errorIndex, varBinds = await slim.get( req["snmp_community"], req["ip"], 161, - ObjectType(ObjectIdentity(req["oids"][oid])), + ObjectType(ObjectIdentity(oid["oid"])), ) - + if errorIndication: logging.error(errorIndication) elif errorStatus: @@ -32,16 +59,110 @@ async def run(req): ) else: for varBind in varBinds: - logging.debug(f"SNMP/{req['mqtt_topic']}/{oid} => {varBind[1]}") + logging.debug(f"{req['device_name']} {oid['name']} => {oid['type'](varBind[1])}") + if oid['type'] == bool: + if bool(varBind[1]): + data.update({oid["name"]: "on"}) + else: + data.update({oid["name"]: "off"}) + else: + data.update({oid["name"]: oid["type"](varBind[1])}) + logging.debug(f"JSON : {json.dumps(data)}") + return data + + +def ha_create_config(req): + ha_config = {} + device = { + "ids": f"{req['device_name']}_{req['ip']}".replace(".", "_"), + "name": req['device_name'], + } + origin = { + "name": "snmp2mqtt" + } + ha_config.update({"dev": device, "o": origin}) + ha_config.update({"state_topic": f"SNMP/{req['device_name']}/state"}) + ha_config.update({"qos": 1}) + cmps = {} + for oid in req['oids']: + cmps.update( + { + f"{req['device_name']}_{req['ip']}_{oid['name']}".replace(".", "_"): + { + "p": oid['HA_platform'], + "device_class": oid['HA_device_class'], + "value_template": f"{{{{ value_json.{oid['name']}}}}}", + "unique_id": f"{req['device_name']}_{req['ip']}_{oid['name']}".replace(".", "_"), + "name": oid['name'] + } + }) + if "HA_unit" in oid.keys(): + cmps.update( + {f"{req['device_name']}_{req['ip']}_{oid['name']}".replace(".", "_"): + {"unit_of_measurement": oid['HA_unit']}}) + ha_config.update({"cmps": cmps}) + logging.debug(f"config : {json.dumps(ha_config)}") + return ha_config + + +def send_to_mqtt(): + 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, 2) + logging.info(f"{config_topic} -> {config}") + except Exception as e: + logging.error(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(e) + pass + sleep(2) + req = { - "mqtt_topic": "mikrotik_hex", + "device_name": "mikrotik_hex", "ip": "192.168.10.2", "snmp_community": "public", - "oids": { - "stln_In": "1.3.6.1.2.1.2.2.1.10.12", - "stln_Out": "1.3.6.1.2.1.2.2.1.16.12" - } + "oids": [ + {"name": "stln_vpn_in", + "oid": ".1.3.6.1.2.1.2.2.1.10.12", + "type": int, + "HA_device_class": "data_size", + "HA_platform": "sensor", + "HA_unit": "bit" + }, + {"name": "stlon_vpn_out", + "oid": ".1.3.6.1.2.1.2.2.1.16.12", + "type": int, + "HA_device_class": "data_size", + "HA_platform": "sensor", + "HA_unit": "bit" + }, + {"name": "stln_vpn_status", + "oid": ".1.3.6.1.2.1.2.2.1.8.12", + "type": bool, + "HA_device_class": "connectivity", + "HA_platform": "binary_sensor", + } + ] } -asyncio.run(run(req)) +mqtt_config = { + "broker": "192.168.10.202", + "port": 1883, + "client_id": f"snmp-mqtt-{random.randint(0, 1000)}", + "user": "snmp2mqtt", + "password": "snmp_2_MQTT" + } + + +send_to_mqtt()