aboutsummaryrefslogtreecommitdiffstats
path: root/mqtt-client
diff options
context:
space:
mode:
Diffstat (limited to 'mqtt-client')
-rw-r--r--mqtt-client/Dockerfile2
m---------mqtt-client/TasmotaCLI0
-rw-r--r--mqtt-client/mqtt-client.py107
-rw-r--r--mqtt-client/requirements.txt1
4 files changed, 102 insertions, 8 deletions
diff --git a/mqtt-client/Dockerfile b/mqtt-client/Dockerfile
index ad59f9b..12c8a53 100644
--- a/mqtt-client/Dockerfile
+++ b/mqtt-client/Dockerfile
@@ -6,5 +6,7 @@ RUN apt-get install -y python3-pip iputils-ping
COPY . /app
WORKDIR /app
RUN pip3 install -r requirements.txt
+RUN pip3 install docker
+RUN pip3 install -r TasmotaCLI/requirements.txt
ENTRYPOINT ["python3"]
CMD ["mqtt-client.py"]
diff --git a/mqtt-client/TasmotaCLI b/mqtt-client/TasmotaCLI
new file mode 160000
+Subproject dd7790dab8d3fbea8f2b58eb4d5aaffc36b3cb0
diff --git a/mqtt-client/mqtt-client.py b/mqtt-client/mqtt-client.py
index a441e6d..37ed8cb 100644
--- a/mqtt-client/mqtt-client.py
+++ b/mqtt-client/mqtt-client.py
@@ -1,25 +1,62 @@
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 asyncio
+import time
import json
+import sys
import os
+sys.path.insert(1, os.path.join(os.path.dirname(__file__), "TasmotaCLI"))
+import tasmotaMQTTClient
+import tasmotaHTTPClient
+
class MQTTClient:
- def __init__(self):
+ def __init__(self, mqtt_client_name = "reg.reaweb.uk/mqtt-client", loop_forever = True):
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.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('power-listener', clean_session = True)
- self.mqttc.on_connect = self._on_connect_cb
- self.mqttc.on_message = self._on_message_cb
+ self.mqttc = paho.Client(mqtt_client_name, clean_session = True)
+ if loop_forever:
+ 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()
+ if loop_forever:
+ self.mqttc.loop_forever()
def _on_connect_cb(self, mqtt, userdata, flags, rc):
#print("Connected to broker")
@@ -41,18 +78,69 @@ 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...")
+ tasmotaMQTTClient.MQTTClient(MQTT_HOST, "TasmotaGeoffery", os.environ["MQTT_USER"], os.environ["MQTT_PASSWD"], "OFF")
+ print("Waiting...")
+ time.sleep(8)
+ tasmotaMQTTClient.MQTTClient(MQTT_HOST, "TasmotaGeoffery", os.environ["MQTT_USER"], os.environ["MQTT_PASSWD"], "ON")
+ print("Toggled again.")
+
zigbee_id = list(msg_j["ZbReceived"].keys())[0]
fields = msg_j["ZbReceived"][zigbee_id]
friendlyname = fields.pop("Name")
del fields["Device"]
print("Zigbee device '%s' reported: %s" % (friendlyname, str(fields)))
- self.append_influxdb(fields, "zigbee", {"friendlyname": friendlyname, "id": zigbee_id})
+
+ if zigbee_id == "0x7327" and friendlyname == "TVButton" and "Power" in fields.keys():
+ if fields["Power"] == 2:
+ print("TV Zigbee button pressed, toggling TasmotaTV Tasmota Plug")
+ self.toggle_plug("TasmotaTV")
+ threading.Thread(target = toggle_geoffery, args = ()).start()
+ #loop = asyncio.get_event_loop()
+ #loop.run_until_complete(tasmotaHTTPClient.main(host = "geoffery.plug", username = "admin", password = os.environ["MQTT_PASSWD"], toggle = True))
+ #time.sleep(8)
+ #loop.run_until_complete(tasmotaHTTPClient.main(host = "geoffery.plug", username = "admin", password = os.environ["MQTT_PASSWD"], toggle = True))
+
+
+ if zigbee_id == "0x74B3" and friendlyname == "HarveyButton" and "Power" in fields.keys():
+ if fields["Power"] == 2:
+ print("Harvey's button pressed, toggling TasmotaHarveyPC Plug")
+ self.toggle_plug("TasmotaHarveyPC")
+
+ if "Humidity" in fields.keys():
+ fields["Humidity"] = float(fields["Humidity"])
+ self.humidity_prom.labels(location = friendlyname).set(fields["Humidity"])
+ elif "Temperature" in fields.keys():
+ fields["Temperature"] = float(fields["Temperature"])
+ 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")
+
+ if "Read" not in fields.keys():
+ self.append_influxdb(fields, "zigbee", {"friendlyname": friendlyname, "id": zigbee_id})
+
+ def set_plug(self, friendlyname, payload):
+ t = "cmnd/TasmotaPlug/%s/Power" % friendlyname
+ self.mqttc.publish(t, payload = payload)
+ print("Send payload '%s' to %s" % (payload, t))
+
+ def toggle_plug(self, friendlyname):
+ self.set_plug(friendlyname, "TOGGLE")
def append_influxdb(self, fields, measurement_name, tags):
points = [{"measurement": measurement_name, "tags": tags, "fields": fields}]
@@ -69,10 +157,13 @@ if __name__ == "__main__":
if os.path.exists(env_path):
import dotenv
dotenv.load_dotenv(dotenv_path = env_path)
- INFLUXDB_HOST = "localhost"
- MQTT_HOST = "localhost"
+ 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