From d31d273073eec5220b4eb6cbeb576b3661ec6d7b Mon Sep 17 00:00:00 2001 From: jwansek Date: Sun, 19 Nov 2023 18:27:15 +0000 Subject: Added python script to subscribe to MQTT topics and push them to InfluxDB --- README.md | 6 ++++- config.env | 10 +++++++ config.env.example | 10 +++++++ docker-compose.yml | 26 +++++++++++++++++- mqtt-client/Dockerfile | 10 +++++++ mqtt-client/mqtt-client.py | 63 ++++++++++++++++++++++++++++++++++++++++++++ mqtt-client/requirements.txt | 3 +++ 7 files changed, 126 insertions(+), 2 deletions(-) create mode 100644 config.env create mode 100644 config.env.example create mode 100644 mqtt-client/Dockerfile create mode 100644 mqtt-client/mqtt-client.py create mode 100644 mqtt-client/requirements.txt diff --git a/README.md b/README.md index c0323a0..d679508 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,14 @@ Logs Tasmota-flashed power usage monitors to InfluxDB and Grafana using MQTT. +Looking for the Mikrotik POE usage monitor/exporter? That's been moved to [MikrotikPOEPowerExporter](https://github.com/jwansek/MikrotikPOEPowerExporter) + ## Setup +- `cp power.env.example power.env` +- Edit `power.env` as appropriate - `touch .passwords` -- `sudo docker-compose up -d` +- `sudo docker-compose up -d --build` - `sudo docker exec -it poweredagay_mqtt_1 sh` Then in the container: - `chmod 0700 /mosquitto/passwd_file` - `chmod root:root /mosquitto/passwd_file` diff --git a/config.env b/config.env new file mode 100644 index 0000000..061d3a6 --- /dev/null +++ b/config.env @@ -0,0 +1,10 @@ +MQTT_USER=eden +MQTT_PASSWD=securebackdoor + +DOCKER_INFLUXDB_INIT_MODE=setup +DOCKER_INFLUXDB_INIT_USERNAME=eden +DOCKER_INFLUXDB_INIT_PASSWORD=securebackdoor +DOCKER_INFLUXDB_INIT_ORG=poweredagay +DOCKER_INFLUXDB_INIT_BUCKET=edenbucket +DOCKER_INFLUXDB_INIT_ADMIN_TOKEN=027b29324702baad0fd9a3fcf2dbe644 +DOCKER_INFLUXDB_DB=power diff --git a/config.env.example b/config.env.example new file mode 100644 index 0000000..9010652 --- /dev/null +++ b/config.env.example @@ -0,0 +1,10 @@ +MQTT_USER=eden +MQTT_PASSWD=**************** + +DOCKER_INFLUXDB_INIT_MODE=setup +DOCKER_INFLUXDB_INIT_USERNAME=eden +DOCKER_INFLUXDB_INIT_PASSWORD=**************** +DOCKER_INFLUXDB_INIT_ORG=poweredagay +DOCKER_INFLUXDB_INIT_BUCKET=edenbucket +DOCKER_INFLUXDB_INIT_ADMIN_TOKEN=************************ +DOCKER_INFLUXDB_DB=power diff --git a/docker-compose.yml b/docker-compose.yml index daaeb5c..0ca01a6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,10 +8,34 @@ services: - 9001:9001 volumes: - ./mosquitto.conf:/mosquitto/config/mosquitto.conf - - ./.passwords://mosquitto/passwd_file + - ./.passwords:/mosquitto/passwd_file - mosquitto-data:/mosquitto/data - mosquitto-logs:/mosquitto/log + + influxdb: + image: influxdb:2.0 + ports: + - 8086:8086 + volumes: + - influxdb-config:/etc/influxdb2 + - influxdb-data:/var/lib/influxdb2 + env_file: + - ./config.env + depends_on: + - mqtt + + mqtt_client: + image: jwansek/mqtt-client + build: + context: ./mqtt-client + dockerfile: Dockerfile + env_file: + - ./config.env + depends_on: + - influxdb volumes: mosquitto-data: mosquitto-logs: + influxdb-config: + influxdb-data: diff --git a/mqtt-client/Dockerfile b/mqtt-client/Dockerfile new file mode 100644 index 0000000..ad59f9b --- /dev/null +++ b/mqtt-client/Dockerfile @@ -0,0 +1,10 @@ +FROM debian:11-slim +ENV TZ=Europe/London +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone +RUN apt-get update -y +RUN apt-get install -y python3-pip iputils-ping +COPY . /app +WORKDIR /app +RUN pip3 install -r requirements.txt +ENTRYPOINT ["python3"] +CMD ["mqtt-client.py"] diff --git a/mqtt-client/mqtt-client.py b/mqtt-client/mqtt-client.py new file mode 100644 index 0000000..248e5af --- /dev/null +++ b/mqtt-client/mqtt-client.py @@ -0,0 +1,63 @@ +import paho.mqtt.client as paho +from influxdb_client import InfluxDBClient, Point, WritePrecision +from influxdb_client.client.write_api import SYNCHRONOUS +import json +import os + +class MQTTClient: + def __init__(self): + self.influxc = InfluxDBClient( + url = "http://%s:8086" % INFLUXDB_HOST, + token = os.environ["DOCKER_INFLUXDB_INIT_ADMIN_TOKEN"], + org = os.environ["DOCKER_INFLUXDB_INIT_ORG"] + ) + self.influxc.ping() + + self.mqttc = paho.Client('power-listener', clean_session = True) + self.mqttc.on_connect = self._on_connect_cb + self.mqttc.on_message = self._on_message_cb + + self.mqttc.username_pw_set(os.environ["MQTT_USER"], password = os.environ["MQTT_PASSWD"]) + self.mqttc.connect(MQTT_HOST, 1883, 60) + self.mqttc.loop_forever() + + def _on_connect_cb(self, mqtt, userdata, flags, rc): + print("Connected to broker") + self.mqttc.subscribe("tele/+/SENSOR") + + def _on_message_cb(self, mqtt, userdata, msg): + print('Topic: {0} | Message: {1}'.format(msg.topic, msg.payload)) + + if "Tasmota" in msg.topic: + self.handle_tasmota(msg) + + def handle_tasmota(self, msg): + from_ = msg.topic.split("/")[1] + msg_j = json.loads(msg.payload.decode()) + #print(from_) + fields = {k: v for k, v in msg_j["ENERGY"].items() if k not in {"TotalStartTime"}} + points = [{"measurement": "tasmota_power", "tags": {"plug": from_}, "fields": fields}] + write_api = self.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 = "localhost" + MQTT_HOST = "localhost" + else: + INFLUXDB_HOST = "influxdb" + MQTT_HOST = "mqtt" + + mqtt_client = MQTTClient() + + + + diff --git a/mqtt-client/requirements.txt b/mqtt-client/requirements.txt new file mode 100644 index 0000000..2532957 --- /dev/null +++ b/mqtt-client/requirements.txt @@ -0,0 +1,3 @@ +paho-mqtt +python-dotenv +influxdb-client -- cgit v1.2.3