From 7888999ec38225dcceddef0c0442c8b2bd5462f7 Mon Sep 17 00:00:00 2001 From: Antoine Van Elstraete Date: Thu, 6 Nov 2025 17:05:20 +0100 Subject: [PATCH] =?UTF-8?q?feat:=20Ajoute=20la=20transformation=20de=20val?= =?UTF-8?q?eur=20par=20op=C3=A9ration=20math=C3=A9matique?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cette modification introduit la possibilité d'appliquer une opération mathématique simple (addition, soustraction, multiplication, division) sur les valeurs SNMP récupérées. L'utilisateur peut désormais définir une clé 'operation' dans la configuration d'un OID (par exemple, 'value / 1000') pour normaliser les données avant leur envoi à MQTT. La documentation dans `config.yaml` a été mise à jour avec un exemple. --- config.yaml | 11 +++++++++++ snmp2mqtt.py | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/config.yaml b/config.yaml index 3640027..cb6d928 100644 --- a/config.yaml +++ b/config.yaml @@ -39,6 +39,17 @@ devices: type: "bool" HA_device_class: "connectivity" HA_platform: "binary_sensor" + + # Example of a temperature sensor that returns the value in millidegrees. + # The 'operation' key allows performing a simple calculation. + # The placeholder 'value' will be replaced by the SNMP value. + # - name: "temperature" + # oid: ".1.3.6.1.4.1.XXXX.1.1.1.5.1.3.1" # Example OID + # type: "int" + # operation: "value / 1000" + # HA_device_class: "temperature" + # HA_platform: "sensor" + # HA_unit: "°C" # OID Configuration Reference: # - name: Unique identifier for this metric (used in MQTT topics and Home Assistant) diff --git a/snmp2mqtt.py b/snmp2mqtt.py index 2e81496..dec1247 100755 --- a/snmp2mqtt.py +++ b/snmp2mqtt.py @@ -207,6 +207,46 @@ def publish(topic, client, data, retain, qos): logging.error(f"Failed to send message to topic {topic}") +def apply_operation(value, operation_str): + """ + Applies a simple mathematical operation to a value. + e.g., operation_str = "value / 1000" + """ + if 'value' not in operation_str: + logging.error(f"Invalid operation string: 'value' placeholder missing in '{operation_str}'") + return value + + expression = operation_str.replace('value', str(value)) + + try: + parts = expression.split() + if len(parts) != 3: + logging.error(f"Invalid operation format: '{operation_str}'. Expected 'value '") + return value + + val = float(parts[0]) + operator = parts[1] + operand = float(parts[2]) + + if operator == '+': + return val + operand + elif operator == '-': + return val - operand + elif operator == '*': + return val * operand + elif operator == '/': + if operand == 0: + logging.warning(f"Attempted division by zero in operation: {operation_str}") + return value + return val / operand + else: + logging.error(f"Unsupported operator: '{operator}' in '{operation_str}'") + return value + except (ValueError, IndexError) as e: + logging.error(f"Could not parse operation string: '{operation_str}'. Error: {e}") + return value + + async def get_snmp(req): """Asynchronously retrieve SNMP data from device using new pysnmp API""" data = {} @@ -239,13 +279,21 @@ async def get_snmp(req): else: for varBind in varBinds: logging.debug(f"{req['device_name']} {oid['name']} => {oid['type'](varBind[1])}") + + # Cast to the right type + value = oid['type'](varBind[1]) + + # Apply operation if defined + if 'operation' in oid: + value = apply_operation(value, oid['operation']) + if oid['type'] == bool: - if bool(varBind[1]): + if bool(value): data.update({oid["name"]: "ON"}) else: data.update({oid["name"]: "OFF"}) else: - data.update({oid["name"]: oid["type"](varBind[1])}) + data.update({oid["name"]: value}) except Exception as e: logging.error(f"{req['device_name']} Exception getting OID {oid['oid']}: {e}") continue