From 2d44f3d5a6c6a4b75ffa5081b011a93407d1026d Mon Sep 17 00:00:00 2001 From: localhorst Date: Wed, 1 Mar 2023 21:45:23 +0100 Subject: [PATCH] first dummy backend --- README.md | 2 + msv_clubhouse_backend.py | 169 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 171 insertions(+) create mode 100644 msv_clubhouse_backend.py diff --git a/README.md b/README.md index 9ddc370..35af250 100644 --- a/README.md +++ b/README.md @@ -30,5 +30,7 @@ TTN LoRa frequency / region 3. Build with ESP-IDF extension in VSCodium +## MQTT Endpoint ## +`pip3 install paho-mqtt` diff --git a/msv_clubhouse_backend.py b/msv_clubhouse_backend.py new file mode 100644 index 0000000..8d1b86b --- /dev/null +++ b/msv_clubhouse_backend.py @@ -0,0 +1,169 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" Author: Hendrik Schutter, mail@hendrikschutter.com + Date of creation: 2022/03/01 + Date of last modification: 2023/03/01 +""" + +from http.server import BaseHTTPRequestHandler, HTTPServer +import time +import threading +from datetime import datetime +from urllib.parse import urlsplit, parse_qs +from random import randrange +import os, sys, logging, time +import paho.mqtt.client as mqtt +import json +import csv +from datetime import datetime + +hostName = "127.0.0.1" +serverPort = 9101 +exporter_prefix = "msv_clubhouse_" + +User = "APP UUID @ttn" +Password = "API Key" +theRegion = "EU1" # The region you are using + +scrape_healthy = True +startTime = datetime.now() +node_metrics = list() +mutex = threading.Lock() +request_count = 0 + +# MQTT event functions +def on_connect(mqttc, obj, flags, rc): + print("\nConnect: rc = " + str(rc)) + +def on_message(mqttc, obj, msg): + print("\nMessage: " + msg.topic + " " + str(msg.qos)) # + " " + str(msg.payload)) + parsedJSON = json.loads(msg.payload) + print(json.dumps(parsedJSON, indent=4)) # Uncomment this to fill your terminal screen with JSON + uplink_message = parsedJSON["uplink_message"]; + frm_payload = uplink_message["frm_payload"]; + print("MSG: " + frm_payload) + print("MSG: " + str(type(frm_payload))) + +def on_subscribe(mqttc, obj, mid, granted_qos): + print("\nSubscribe: " + str(mid) + " " + str(granted_qos)) + +def on_log(mqttc, obj, level, string): + print("\nLog: "+ string) + logging_level = mqtt.LOGGING_LEVEL[level] + logging.log(logging_level, string) + +class RequestHandler(BaseHTTPRequestHandler): + + def get_metrics(self): + global request_count + global node_metrics + global exporter_prefix + global mutex + mutex.acquire() + self.send_response(200) + self.send_header("Content-type", "text/html") + self.end_headers() + self.wfile.write(bytes(exporter_prefix + "expoter_duration_seconds_sum " + str(int((datetime.now() - startTime).total_seconds())) + "\n", "utf-8")) + self.wfile.write(bytes(exporter_prefix + "exporter_request_count " + str(request_count) + "\n", "utf-8")) + self.wfile.write(bytes(exporter_prefix + "exporter_scrape_healthy " + str(int(scrape_healthy)) + "\n", "utf-8")) + + for metric in node_metrics: + #print(metric) + self.wfile.write(bytes(exporter_prefix + metric + "\n", "utf-8")) + + mutex.release() + + def do_GET(self): + global request_count + request_count = request_count + 1 + print("Request: " + self.path) + if (self.path.startswith("/metrics")): + self.get_metrics() + else: + self.send_response(200) + self.send_header("Content-type", "text/html") + self.end_headers() + self.wfile.write(bytes("", "utf-8")) + self.wfile.write(bytes("MSV Clubhouse exporter", "utf-8")) + self.wfile.write(bytes("", "utf-8")) + self.wfile.write(bytes('

msv-clubhouse exporter based on data from LoRaWAN TTN node.

', "utf-8")) + self.wfile.write(bytes('

Metrics

', "utf-8")) + self.wfile.write(bytes("", "utf-8")) + self.wfile.write(bytes("", "utf-8")) + + +def update_metrics(): + while True: + print("set data from ttn") + global node_metrics + global mutex + global scrape_healthy + mutex.acquire() + scrape_healthy = True + node_metrics.clear() + + try: + + node_metrics.append("target_temperature " + str(int(42))) + node_metrics.append("valve " + str(int(42))) + node_metrics.append("low_battery " + str(int(42))) + node_metrics.append("window_open " + str(int(42))) + except Exception as ex: + print("unable to poll data from TTN! error: " + str(ex)) + scrape_healthy = False + pass + mutex.release() + time.sleep(300) + +def poll_mqtt(mqttc): + while True: + mqttc.loop(10) # seconds timeout / blocking time + print(".", end="", flush=True) # feedback to the user that something is actually happening + + +def main(): + print("start") + + print("Init mqtt client") + mqttc = mqtt.Client() + + print("Assign callbacks") + mqttc.on_connect = on_connect + mqttc.on_subscribe = on_subscribe + mqttc.on_message = on_message + + print("Connect") + # Setup authentication from settings above + mqttc.username_pw_set(User, Password) + + # IMPORTANT - this enables the encryption of messages + mqttc.tls_set() # default certification authority of the system + + mqttc.connect(theRegion.lower() + ".cloud.thethings.network", 8883, 60) + + print("Subscribe") + mqttc.subscribe("#", 0) # all device uplinks + + print("And run forever") + poll_mqtt_thread = threading.Thread(target=poll_mqtt, args=((mqttc,))) + poll_mqtt_thread.start() + + webServer = HTTPServer((hostName, serverPort), RequestHandler) + + print("Server started http://%s:%s" % (hostName, serverPort)) + + update_metrics_thread = threading.Thread(target=update_metrics, args=()) + update_metrics_thread.start() + + try: + webServer.serve_forever() + except KeyboardInterrupt: + pass + + webServer.server_close() + print("Server stopped.") + update_metrics_thread.join() + poll_mqtt_thread.join() + +if __name__ == "__main__": + main() \ No newline at end of file