diff options
| author | jwansek <eddie.atten.ea29@gmail.com> | 2025-05-28 17:50:09 +0100 | 
|---|---|---|
| committer | jwansek <eddie.atten.ea29@gmail.com> | 2025-05-28 17:50:09 +0100 | 
| commit | 595f5c8d41441ac815fac5fa24675f784083b823 (patch) | |
| tree | f5d285e2ac67b0aadcf1218787db4321b3593eda | |
| parent | 727ab83e0992e2d463c4d0c461577b3d8994ca91 (diff) | |
| parent | e89d3b9730db994f3e6d880a55c47e94497f5155 (diff) | |
| download | power.eda.gay-595f5c8d41441ac815fac5fa24675f784083b823.tar.gz power.eda.gay-595f5c8d41441ac815fac5fa24675f784083b823.zip | |
Merge
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | mqtt-client/mqtt-client.py | 45 | ||||
| -rw-r--r-- | mqtt-client/requirements.txt | 1 | ||||
| -rw-r--r-- | switch-snmp/mikrotik.py | 28 | ||||
| -rw-r--r-- | switch-snmp/requirements.txt | 3 | ||||
| -rw-r--r-- | switch-snmp/switches.py | 57 | 
6 files changed, 105 insertions, 30 deletions
| @@ -8,6 +8,7 @@ influxdb-config/  influxdb-data/  node-red-data/  prometheus/web.yml +prometheus/web.yml  # Byte-compiled / optimized / DLL files  __pycache__/ diff --git a/mqtt-client/mqtt-client.py b/mqtt-client/mqtt-client.py index 18dcd82..f81d1d6 100644 --- a/mqtt-client/mqtt-client.py +++ b/mqtt-client/mqtt-client.py @@ -1,6 +1,7 @@  import paho.mqtt.client as paho  from influxdb_client import InfluxDBClient, Point, WritePrecision  from influxdb_client.client.write_api import SYNCHRONOUS +import prometheus_client  import threading  import time  import json @@ -18,6 +19,32 @@ class MQTTClient:              org = os.environ["DOCKER_INFLUXDB_INIT_ORG"]           )          self.influxc.ping() +        self.tasmota_power_prom = prometheus_client.Gauge( +            "tasmota_power",  +            "Power metrics as reported by Tasmota-flashed plugs",  +            labelnames = ["plug", "field"] +        ) +        self.humidity_prom = prometheus_client.Gauge( +            "humidity", +            "Humidity as reported by a zigbee device over MQTT", +            labelnames = ["location"] +        ) +        self.temperature_prom = prometheus_client.Gauge( +            "temperature", +            "Temperature as reported by a zigbee device over MQTT", +            labelnames = ["location"] +        ) +        self.doorsensor_prom = prometheus_client.Enum( +            "door_sensor", +            "Door sensor state change as reported by zigbee door sensor over MQTT", +            states = ["opened", "closed"], +            labelnames = ["location"] +        ) +        self.door_opened_counter = prometheus_client.Counter( +            "door_opened", +            "Door sensor opened as reported by zigbee door sensor over MQTT", +            labelnames = ["location"] +        )          self.mqttc = paho.Client(mqtt_client_name, clean_session = True)          if loop_forever: @@ -49,11 +76,15 @@ class MQTTClient:          elif type_ == "TasmotaZigbee":              self.handle_zigbee(msg_j) +      def handle_plug(self, msg_j, location):          print("'%s' is using %.1fw @ %s. %.1fkWh so far today, %.1fkWh yesterday" % (location, msg_j["ENERGY"]["Power"], msg_j["Time"],  msg_j["ENERGY"]["Today"], msg_j["ENERGY"]["Yesterday"]))          fields = {k: v for k, v in msg_j["ENERGY"].items() if k not in {"TotalStartTime"}}          self.append_influxdb(fields, "tasmota_power", {"plug": location}) +        for k, v in fields.items(): +            self.tasmota_power_prom.labels(plug = location, field = k).set(v) +      def handle_zigbee(self, msg_j):          def toggle_geoffery():              print("Starting thread...") @@ -81,6 +112,17 @@ class MQTTClient:                  print("Harvey's button pressed, toggling TasmotaHarveyPC Plug")                  self.toggle_plug("TasmotaHarveyPC") +        if "Humidity" in fields.keys(): +            self.humidity_prom.labels(location = friendlyname).set(fields["Humidity"]) +        elif "Temperature" in fields.keys(): +            self.temperature_prom.labels(location = friendlyname).set(fields["Temperature"]) +        elif "ZoneStatus" in fields.keys() and "Contact" in fields.keys(): +            if fields["ZoneStatus"] == 1 and fields["Contact"] == 1: +                self.doorsensor_prom.labels(location = friendlyname).state("opened") +                self.door_opened_counter.labels(location = friendlyname).inc() +            elif fields["ZoneStatus"] == 0 and fields["Contact"] == 0: +                self.doorsensor_prom.labels(location = friendlyname).state("closed") +      def set_plug(self, friendlyname, payload):          t = "cmnd/TasmotaPlug/%s/Power" % friendlyname          self.mqttc.publish(t, payload = payload) @@ -106,8 +148,11 @@ if __name__ == "__main__":          dotenv.load_dotenv(dotenv_path = env_path)          INFLUXDB_HOST = "dns.athome"          MQTT_HOST = "dns.athome" +        PROM_HOST = "dns.athome"      else:          INFLUXDB_HOST = "influxdb"          MQTT_HOST = "mqtt" +        PROM_HOST = "prometheus" +    prometheus_client.start_http_server(8000)      mqtt_client = MQTTClient() diff --git a/mqtt-client/requirements.txt b/mqtt-client/requirements.txt index ac151c7..3e6f8db 100644 --- a/mqtt-client/requirements.txt +++ b/mqtt-client/requirements.txt @@ -1,3 +1,4 @@  paho-mqtt==1.6.1  python-dotenv  influxdb-client +prometheus-client diff --git a/switch-snmp/mikrotik.py b/switch-snmp/mikrotik.py index 29bc797..8493675 100644 --- a/switch-snmp/mikrotik.py +++ b/switch-snmp/mikrotik.py @@ -8,9 +8,6 @@ import time  import os  import re -from influxdb_client import InfluxDBClient, Point, WritePrecision -from influxdb_client.client.write_api import SYNCHRONOUS -  logging.basicConfig(       format = "%(levelname)s\t[%(asctime)s]\t%(message)s",       level = logging.INFO, @@ -121,30 +118,6 @@ def print_points(points):                      measurement["fields"]["tpPoeVoltage"],                  )) -def append(points): -    env_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "config.env") -    if os.path.exists(env_path): -        import dotenv -        dotenv.load_dotenv(dotenv_path = env_path) -        INFLUXDB_HOST = "dns.athome" -    else: -        INFLUXDB_HOST = "influxdb" - -    influxc = InfluxDBClient( -        url = "http://%s:8086" % INFLUXDB_HOST, -        token = os.environ["DOCKER_INFLUXDB_INIT_ADMIN_TOKEN"], -        org = os.environ["DOCKER_INFLUXDB_INIT_ORG"]  -    ) -    influxc.ping() - -    write_api = influxc.write_api(write_options = SYNCHRONOUS) -    write_api.write( -        os.environ["DOCKER_INFLUXDB_INIT_BUCKET"], -        os.environ["DOCKER_INFLUXDB_INIT_ORG"], -        points, -        write_precision = WritePrecision.S -    ) -  if __name__ == "__main__":      if not os.path.exists(os.path.join(os.path.dirname(__file__), "mikrotik-switches.conf")):          raise FileNotFoundError("Couldn't find mikrotik config file") @@ -154,5 +127,4 @@ if __name__ == "__main__":      import json      points = get_points()      print(json.dumps(points, indent = 4)) -    append(points) diff --git a/switch-snmp/requirements.txt b/switch-snmp/requirements.txt index aaf744d..aeb5843 100644 --- a/switch-snmp/requirements.txt +++ b/switch-snmp/requirements.txt @@ -1,4 +1,5 @@  python-dotenv  influxdb-client  pandas -fabric
\ No newline at end of file +fabric +prometheus-client
\ No newline at end of file diff --git a/switch-snmp/switches.py b/switch-snmp/switches.py index aee56d2..bede120 100644 --- a/switch-snmp/switches.py +++ b/switch-snmp/switches.py @@ -1,7 +1,62 @@ +import prometheus_client  import snmpOmada  import mikrotik +import os + +from influxdb_client import InfluxDBClient, Point, WritePrecision +from influxdb_client.client.write_api import SYNCHRONOUS + +def append(points): +    influxc = InfluxDBClient( +        url = "http://%s:8086" % INFLUXDB_HOST, +        token = os.environ["DOCKER_INFLUXDB_INIT_ADMIN_TOKEN"], +        org = os.environ["DOCKER_INFLUXDB_INIT_ORG"]  +    ) +    influxc.ping() + +    for measurement in points: +        for field in measurement["fields"].keys(): +            try: +                float(measurement["fields"][field]) +            except ValueError: +                continue +            else: +                switch_power.labels( +                    field = field, +                    type = measurement["tags"]["type"], +                    port = str(measurement["tags"]["port"]), +                    port_name = measurement["tags"]["port_name"], +                    host = measurement["tags"]["switch_host"] +                ).set(float(measurement["fields"][field])) + +    write_api = influxc.write_api(write_options = SYNCHRONOUS) +    write_api.write( +        os.environ["DOCKER_INFLUXDB_INIT_BUCKET"], +        os.environ["DOCKER_INFLUXDB_INIT_ORG"], +        points, +        write_precision = WritePrecision.S +    )  if __name__ == "__main__": +    env_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "config.env") +    if os.path.exists(env_path): +        import dotenv +        dotenv.load_dotenv(dotenv_path = env_path) +        INFLUXDB_HOST = "dns.athome" +        PUSHGATEWAY_HOST = "dns.athome" +    else: +        INFLUXDB_HOST = "influxdb" +        PUSHGATEWAY_HOST = "pushgateway" + +    registry = prometheus_client.CollectorRegistry() +    switch_power = prometheus_client.Gauge( +        "switch_power", +        "POE switch power usage metrics from Omada and Mikrotik switches, using Omada SNMP names", +        labelnames = ["field", "type", "port", "port_name", "host"] +    ) +      points = snmpOmada.get_points() + mikrotik.get_points()      mikrotik.print_points(points) -    mikrotik.append(points)
\ No newline at end of file +    append(points) + +    prometheus_client.push_to_gateway("%s:9091" % PUSHGATEWAY_HOST, job = "switchSNMP", registry = registry)
\ No newline at end of file | 
