diff options
Diffstat (limited to 'mqtt-client')
-rw-r--r-- | mqtt-client/Dockerfile | 2 | ||||
m--------- | mqtt-client/TasmotaCLI | 0 | ||||
-rw-r--r-- | mqtt-client/mqtt-client.py | 107 | ||||
-rw-r--r-- | mqtt-client/requirements.txt | 1 |
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 |