diff --git a/mqtt/mqtt.yaml b/mqtt/mqtt.yaml new file mode 100644 index 0000000..1d13baa --- /dev/null +++ b/mqtt/mqtt.yaml @@ -0,0 +1,116 @@ +apiVersion: v1 +kind: Pod +metadata: + annotations: + bind-mount-options:/data/mqtt/config: z + bind-mount-options:/data/mqtt/data: z + bind-mount-options:/data/mqtt/log: z + bind-mount-options:/data/mqtt/config/prometheus.yml: z + bind-mount-options:/data/mqtt/config/mqtt2prometheus-config.yaml: z + bind-mount-options:/data/mqtt/data-shellies: z + io.kubernetes.cri-o.TTY/mqtt: "false" + io.podman.annotations.autoremove/mqtt: "FALSE" + io.podman.annotations.init/mqtt: "FALSE" + io.podman.annotations.label/mqtt: type:container_runtime_t + io.podman.annotations.privileged/mqtt: "FALSE" + io.podman.annotations.publish-all/mqtt: "FALSE" + labels: + app: mqtt-pod + name: mqtt-pod +spec: + containers: + - name: mosquitto + image: docker.io/library/eclipse-mosquitto:latest + env: + - name: TZ + value: Europe/Zurich + ports: + - containerPort: 1883 + hostPort: 9080 + resources: {} + securityContext: + capabilities: + drop: + - CAP_MKNOD + - CAP_NET_RAW + - CAP_AUDIT_WRITE + volumeMounts: + - mountPath: /mosquitto/config + name: mosquittoconfig + - mountPath: /mosquitto/data + name: mosquittodata + - mountPath: /mosquitto/log + name: mosquittolog + - name: mqtt2log + image: localhost/mqtt2log:2022122901 + env: + - name: TZ + value: Europe/Zurich + resources: {} + securityContext: + capabilities: + drop: + - CAP_MKNOD + - CAP_NET_RAW + - CAP_AUDIT_WRITE + volumeMounts: + - mountPath: /data + name: datashellies + - name: mqtt2prometheus + image: ghcr.io/hikhvar/mqtt2prometheus:latest + env: + - name: TZ + value: Europe/Zurich + ports: + - containerPort: 9641 + resources: {} + securityContext: + capabilities: + drop: + - CAP_MKNOD + - CAP_NET_RAW + - CAP_AUDIT_WRITE + volumeMounts: + - mountPath: /config.yaml + name: mqtt2prometheusconfig + - name: prometheus + image: registry.hub.docker.com/prom/prometheus:latest + env: + - name: TZ + value: Europe/Zurich + resources: {} + securityContext: + capabilities: + drop: + - CAP_MKNOD + - CAP_NET_RAW + - CAP_AUDIT_WRITE + volumeMounts: + - mountPath: /etc/prometheus/prometheus.yml + name: prometheusconfig + restartPolicy: Always + volumes: + - hostPath: + path: /data/mqtt/data + type: Directory + name: mosquittodata + - hostPath: + path: /data/mqtt/config + type: Directory + name: mosquittoconfig + - hostPath: + path: /data/mqtt/log + type: Directory + name: mosquittolog + - hostPath: + path: /data/mqtt/data-shellies + type: Directory + name: datashellies + - hostPath: + path: /data/mqtt/config/mqtt2prometheus-config.yaml + type: File + name: mqtt2prometheusconfig + - hostPath: + path: /data/mqtt/config/prometheus.yml + type: File + name: prometheusconfig diff --git a/mqtt/mqtt2log-build/Dockerfile b/mqtt/mqtt2log-build/Dockerfile new file mode 100644 index 0000000..ae24ef1 --- /dev/null +++ b/mqtt/mqtt2log-build/Dockerfile @@ -0,0 +1,5 @@ +FROM python:3.10 +ADD . /code +WORKDIR /code +RUN pip install --root-user-action ignore -r requirements.txt +CMD ["python", "mqtt2log.py"] diff --git a/mqtt/mqtt2log-build/mqtt2log.py b/mqtt/mqtt2log-build/mqtt2log.py new file mode 100755 index 0000000..557d501 --- /dev/null +++ b/mqtt/mqtt2log-build/mqtt2log.py @@ -0,0 +1,65 @@ +import re +import json +from typing import NamedTuple +from datetime import datetime + +import paho.mqtt.client as mqtt + +MQTT_ADDRESS = 'mqtt.nbit.ch' +MQTT_USER = 'mqtt' +MQTT_PASSWORD = 'mqtt7355@' +MQTT_TOPIC = 'shellies/events/rpc' +MQTT_CLIENT_ID = 'MQTT_Logfile_Bridge' + +def on_connect(client, userdata, flags, rc): + """ The callback for when the client receives a CONNACK response from the server.""" + print('Connected with result code ' + str(rc)) + client.subscribe(MQTT_TOPIC) + +def _parse_mqtt_message(topic, payload): + print("_parse_mqtt_message") + payload = json.loads(payload) + src = payload.get('src','N/A') + if 'params' in payload.keys(): + ts = payload['params'].get('ts',-1) + if 'switch:0' in payload['params'].keys(): + if 'aenergy' in payload['params']['switch:0'].keys(): + if 'total' in payload['params']['switch:0']['aenergy'].keys(): + return "E,%.0f,%s,%.3f" % (ts,src,payload['params']['switch:0']['aenergy']['total']) + if 'apower' in payload['params']['switch:0'].keys(): + return "P,%.0f,%s,%.1f" % (ts,src,payload['params']['switch:0']['apower']) + else: + return None + +def write2file(msg): + now = datetime.now() # current date and time + filename = "/data/" + now.strftime("%Y%m%d") + ".log" + f = open(filename, "a") + f.write(msg + "\n") + f.close() + +def on_message(client, userdata, msg): + """The callback for when a PUBLISH message is received from the server.""" + #print(msg.topic + ' ' + str(msg.payload)) + result = _parse_mqtt_message(msg.topic, msg.payload.decode('utf-8')) + if result is None: + print("Couldn't parse sensor data!") + print(msg.payload.decode('utf-8')) + return + else: + write2file(result) + return + +def main(): + mqtt_client = mqtt.Client(MQTT_CLIENT_ID) + mqtt_client.username_pw_set(MQTT_USER, MQTT_PASSWORD) + mqtt_client.on_connect = on_connect + mqtt_client.on_message = on_message + + mqtt_client.connect(MQTT_ADDRESS, 1883) + mqtt_client.loop_forever() + + +if __name__ == '__main__': + print('MQTT to Logfile bridge') + main() diff --git a/mqtt/mqtt2log-build/requirements.txt b/mqtt/mqtt2log-build/requirements.txt new file mode 100644 index 0000000..8579e8b --- /dev/null +++ b/mqtt/mqtt2log-build/requirements.txt @@ -0,0 +1 @@ +paho-mqtt diff --git a/traefik/configuration/mqtt.yml b/traefik/configuration/mqtt.yml new file mode 100644 index 0000000..3274a0e --- /dev/null +++ b/traefik/configuration/mqtt.yml @@ -0,0 +1,13 @@ +tcp: + routers: + mqtt: + entrypoints: + - "mqtt" + rule: "HostSNI(`*`)" + service: mqtt + + services: + mqtt: + loadBalancer: + servers: + - address: "127.0.0.1:9080" diff --git a/traefik/traefik.yaml b/traefik/traefik.yaml index e1f7f83..dc920a7 100644 --- a/traefik/traefik.yaml +++ b/traefik/traefik.yaml @@ -23,6 +23,7 @@ spec: - --entrypoints.web.http.redirections.entryPoint.to=websecure - --entrypoints.web.http.redirections.entryPoint.scheme=https - --entrypoints.websecure.address=:443 + - --entrypoints.mqtt.address=:1883 - --certificatesresolvers.myresolver.acme.email=postmaster@nbit.ch - --certificatesresolvers.myresolver.acme.storage=/acme.json - --certificatesresolvers.myresolver.acme.tlschallenge=true