From 0ed8b90c287e6b9bd3e0b45dd4907326e14897fb Mon Sep 17 00:00:00 2001 From: Andrei Belov Date: Fri, 27 Jun 2025 19:59:01 +0400 Subject: [PATCH 1/3] zont_prom_exporter: add failure status and error code metrics --- .../zont_prom_exporter/zont_prom_exporter.py | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/examples/zont_prom_exporter/zont_prom_exporter.py b/examples/zont_prom_exporter/zont_prom_exporter.py index 2885feb..5573bf5 100755 --- a/examples/zont_prom_exporter/zont_prom_exporter.py +++ b/examples/zont_prom_exporter/zont_prom_exporter.py @@ -84,6 +84,18 @@ "zont_boiler_rml", "Burner modulation level", ["device_id", "sensor_id"] ) +# авария котла +# boiler failure status +BOILER_OTA_FAILED = Gauge( + "zont_boiler_failed", "Boiler failure status", ["device_id", "sensor_id"] +) + +# последний код ошибки +# boiler last error code +BOILER_OTA_ERROR = Gauge( + "zont_boiler_error", "Latest error code", ["device_id", "sensor_id"] +) + zapi = None zdevice = None @@ -157,6 +169,16 @@ def update_metrics() -> bool: BOILER_OTA_DS.labels(zdevice.id, adapter_id).set(z3k_ot.get("ds")) BOILER_OTA_DT.labels(zdevice.id, adapter_id).set(z3k_ot.get("dt")) BOILER_OTA_RML.labels(zdevice.id, adapter_id).set(z3k_ot.get("rml")) + + status = z3k_ot.get("s", []) + # TODO: should we keep these metrics permanently instead of setting on error only? + if len(status) > 0: + if "f" in status: + boiler_error = z3k_ot.get("ff", {}).get("c", 0) + logger.info("boiler error detected: E%02d", boiler_error) + BOILER_OTA_FAILED.labels(zdevice.id, adapter_id).set(1) + BOILER_OTA_ERROR.labels(zdevice.id, adapter_id).set(boiler_error) + logger.info("%s/%s (%s) updated", zdevice.id, adapter_id, adapter_name) except Exception as e: logger.error( From b6d66f1f26257508e684aab90cedbb21457fdf22 Mon Sep 17 00:00:00 2001 From: Andrei Belov Date: Fri, 27 Jun 2025 20:15:52 +0400 Subject: [PATCH 2/3] Add OpenTherm object scheme reference from API docs --- .../zont_prom_exporter/zont_prom_exporter.py | 43 ++++++++++++++++--- 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/examples/zont_prom_exporter/zont_prom_exporter.py b/examples/zont_prom_exporter/zont_prom_exporter.py index 5573bf5..3432ba6 100755 --- a/examples/zont_prom_exporter/zont_prom_exporter.py +++ b/examples/zont_prom_exporter/zont_prom_exporter.py @@ -163,6 +163,38 @@ def update_metrics() -> bool: adapter_name = boiler_adapter.get("name") try: z3k_ot = z3k.get(adapter_id).get("ot") + + """ + https://zont-online.ru/api/docs/#c248a6163b-4 + + ot (object) — состояние OpenTherm + s (array) — массив флагов состояния + "f" — авария + "ch" — отопление включено + "dhw" — ГВС включено + "fl" — горелка работает + "cl" — охлаждение работает + "ch2" — второй контур отопления включен + "di" — диагностическая индикация + cs (float) — расчётная температура теплоносителя отопления + ff (object) — состояние аварии + c (int) — OEM-код аварии + f (array) — флаги аварии + "sr" — требуется обслуживание + "lr" — требуется ручной сброс + "wp" — низкое давление теплоносителя + "gf" — сбой газа/горелки + "ap" — сбой давления воздуха + "wot" — превышение температуры + bt (float) — фактическая температура теплоносителя + dt (float) — фактическая температура ГВС + ot (float) — уличная температура + rwt (float) — температура обратного потока + rml (float) — относительный уровень модуляции в процентах + wp (float) — давление теплоносителя (бар) + fr (float) — скорость потока ГВС (литр/мин) + """ + BOILER_OTA_OT.labels(zdevice.id, adapter_id).set(z3k_ot.get("ot")) BOILER_OTA_CS.labels(zdevice.id, adapter_id).set(z3k_ot.get("cs")) BOILER_OTA_BT.labels(zdevice.id, adapter_id).set(z3k_ot.get("bt")) @@ -172,12 +204,11 @@ def update_metrics() -> bool: status = z3k_ot.get("s", []) # TODO: should we keep these metrics permanently instead of setting on error only? - if len(status) > 0: - if "f" in status: - boiler_error = z3k_ot.get("ff", {}).get("c", 0) - logger.info("boiler error detected: E%02d", boiler_error) - BOILER_OTA_FAILED.labels(zdevice.id, adapter_id).set(1) - BOILER_OTA_ERROR.labels(zdevice.id, adapter_id).set(boiler_error) + if "f" in status: + boiler_error = z3k_ot.get("ff", {}).get("c", -1) + logger.info("boiler error detected: E%02d", boiler_error) + BOILER_OTA_FAILED.labels(zdevice.id, adapter_id).set(1) + BOILER_OTA_ERROR.labels(zdevice.id, adapter_id).set(boiler_error) logger.info("%s/%s (%s) updated", zdevice.id, adapter_id, adapter_name) except Exception as e: From 70c4b110a3e012fdac72c5f5b42fdf786ccceef8 Mon Sep 17 00:00:00 2001 From: Andrei Belov Date: Fri, 27 Jun 2025 20:34:43 +0400 Subject: [PATCH 3/3] Year bump --- LICENSE | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/LICENSE b/LICENSE index 937893e..5ea5daf 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2024 Andrei Belov +Copyright (c) 2024-2025 Andrei Belov Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 68699b9..161bf4a 100644 --- a/README.md +++ b/README.md @@ -10,4 +10,4 @@ but should work with other compatible devices as well. # Copyright -Copyright © 2024 Andrei Belov. Released under the [MIT License](LICENSE). +Copyright © 2024-2025 Andrei Belov. Released under the [MIT License](LICENSE).