The webserver is now using flask instead of python http server. This is

due to its incapability to easily render images or graphs.
The program now also uses a new class called 'Sensor' instead of a
very long for loop to correctly format the data from the json file.
Added LICENSE file
Added favicon
Added Flask HTML
This commit is contained in:
mia 2025-05-27 11:25:37 +02:00
parent 9a48f52845
commit 4c654ec969
13 changed files with 932 additions and 115 deletions

View file

@ -1,114 +1,223 @@
from http.server import BaseHTTPRequestHandler, HTTPServer
from datetime import datetime
import re
from flask import Flask, send_from_directory, render_template
import json
import matplotlib.pyplot as plt
import mimetypes
mimetypes.add_type("image/png", ".png")
# Opening JSON file
f = open("data.json")
# returns JSON object as a dictionary
data = json.load(f)
sensors = dict()
# Iterating through the json list
for i in data["sensors"]:
sensors[i["id"]] = [i["type"], i["unit"], i["readings"]]
# Closing file
f.close()
def create_plot(id: str, unit: str, xaxis: list, yaxis: list):
plt.plot(xaxis, yaxis)
plt.title(id)
plt.xlabel("Time")
plt.ylabel(unit)
plt.savefig(f"plots/{id}.png") # Save to file
plt.close()
# Global Variables:
jsonpath = "data.json"
htmldata = ""
def sortfunc(körber):
return körber
# class Entries:
# def __init__(self, id: str, ts: list, value: list):
# self.id = id
# templist: list = []
# for i in range(len(ts)):
# templist.append([ts[i], value[i]])
# self.entries: list = templist
#
# def printEntries(self):
# print(self.entries)
#
#
# tese = Entries("sensor0", [1, 2, 3, 4], [10, 20, 30, 40])
# tese.printEntries()
for i in sensors:
type = sensors[i][0]
unit = sensors[i][1]
readings = ""
datapoints: list = []
sensorrange = len(sensors[i][2]) if len(sensors[i][2]) < 5 else 5
for j in range(sensorrange):
datapoints.append([])
ts = sensors[i][2][j]["ts"]
value = sensors[i][2][j]["value"]
datapoints[j].append(ts)
datapoints[j].append(value)
datapoints[j].append(unit)
datapoints.sort(key=sortfunc, reverse=True)
class Sensor:
def __init__(self, id: str, unit: str, type: str, ts: list, value: list):
self.id = id
self.unit = unit
self.type = type
self.ts: list = ts
self.values: list = value
self.timeonly: list = []
self.timedate: list = []
for i in ts:
# print(i)
self.timeonly.append(datetime.fromtimestamp(int(i)).strftime("%H:%M.%S"))
self.timedate.append(
datetime.fromtimestamp(i).strftime("%d.%m.%Y %H:%M.%S")
)
graphdata: list = [[], []]
for j in datapoints:
ts = j[0]
time = datetime.fromtimestamp(ts).strftime("%d.%m.%Y %H:%M.%S")
timeNoDate = datetime.fromtimestamp(ts).strftime("%H:%M.%S")
value = j[1]
unit = j[2]
# print(f"{time} {j}")
readings += f"{time}> {value}{unit}<br>"
graphdata[0].append(timeNoDate)
graphdata[1].append(value)
def getId(self):
return self.id
create_plot(i, unit, graphdata[0], graphdata[1])
def getUnit(self):
return self.unit
htmldata += f"""
<p>Id: {i}</p>
<p>Type: {type}</p>
<p>Readings:</p>
<div style="margin-left: 40px;">
{readings}
<img src="/plots/{i}.png" alt="Graph">
</div>
<hr>
"""
def getType(self):
return self.type
html = f"""
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Sensor Data</title>
<style>
* {{
font-family: 'Caskaydia Cove NF';
font-size: 18px;
color: white;
background: #1C1C1C;
}}
</style>
</head>
<body>
{htmldata}
</body>
</html>
"""
def getReadings(self, limit=5, reversed=True, timetype="ts"):
datadic: dict = {}
match timetype:
case "ts":
for i in range(limit if limit < len(self.ts) else len(self.ts)):
datadic[self.ts[i]] = self.values[i]
case "time":
for i in range(limit if limit < len(self.ts) else len(self.ts)):
datadic[self.timeonly[i]] = self.values[i]
case "timedate":
for i in range(limit if limit < len(self.ts) else len(self.ts)):
datadic[self.timedate[i]] = self.values[i]
case _:
return "ERROR: timetype must be one of 'ts', 'time', 'timedate'"
return dict(sorted(datadic.items(), reverse=reversed))
# This only exist because jinja2 can not accept arguments :(
def getReadingsTimeDate(self):
return self.getReadings(timetype="timedate")
def getReadingsTime(self):
return self.getReadings(timetype="time")
def getValueByTimestamp(self, ts: int):
c = 0
for i in self.ts:
c += 1
if i == ts:
return self.values[c]
def getTimestampByValue(self, value: float):
values: list = []
for i in range(len(self.values)):
if self.values[i] == value:
values.append(self.ts[i])
return values
def renderPlot(self):
plt.plot(self.timeonly, self.values)
plt.title(self.id)
plt.xlabel("Time")
plt.ylabel(self.unit)
path = f"plots/{self.id}.png"
plt.savefig(f"static/{path}") # Save to file
plt.close()
return path
# def formatLine(self, ts: int):
# for i in self.ts:
# if i == ts:
# return f"{self.timedate}> {self.values[]}"
class MyHandler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
# self.send_header("Content-type", "text/html")
self.end_headers()
self.wfile.write(html.encode("utf-8"))
# Json
f = open(jsonpath)
jsondata = json.load(f) # returns JSON object as a dictionary
# sensordict = dict()
sensors: dict = {}
for i in jsondata["sensors"]: # Iterating through the json list
timestamps: list = []
values: list = []
# print(len(i["readings"]))
for j in range(len(i["readings"])):
timestamps.append(i["readings"][j]["ts"])
values.append(i["readings"][j]["value"])
# print(i)
# print(i["readings"][1])
# print("\n")
# sensordict[i["id"]] = [i["type"], i["unit"], i["readings"]]
# print(sensordict[i["id"]])
sensors[i["id"]] = Sensor(i["id"], i["unit"], i["type"], timestamps, values)
f.close()
print("\n")
# print(sensordict)
print(sensors)
# print(sensors["sensor_001"].getReadings(limit=2, reversed=True, timetype="time"))
# for i in sensordict:
# type = sensordict[i][0]
# unit = sensordict[i][1]
# readings = ""
# datapoints: list = []
# sensorrange = len(sensordict[i][2]) if len(sensordict[i][2]) < 5 else 5
# for j in range(sensorrange):
# datapoints.append([])
# ts = sensordict[i][2][j]["ts"]
# value = sensordict[i][2][j]["value"]
# datapoints[j].append(ts)
# datapoints[j].append(value)
# datapoints[j].append(unit)
# datapoints.sort(reverse=True)
#
# graphdata: list = [[], []]
# for j in datapoints:
# ts = j[0]
# time = datetime.fromtimestamp(ts).strftime("%d.%m.%Y %H:%M.%S")
# timeNoDate = datetime.fromtimestamp(ts).strftime("%H:%M.%S")
# value = j[1]
# unit = j[2]
# # print(f"{time} {j}")
# readings += f"{time}> {value}{unit}<br>"
# graphdata[0].append(timeNoDate)
# graphdata[1].append(value)
#
# # create_plot(i, unit, graphdata[0], graphdata[1])
#
# htmldata += f"""
# <p>Id: {i}</p>
# <p>Type: {type}</p>
# <p>Readings:</p>
# <div style="margin-left: 40px;">
# {readings}
# <img src="/plots/{i}.png" alt="Graph">
# </div>
# <hr>"""
#
# html = f"""
# <!DOCTYPE html>
# <html lang="en">
# <head>
# <meta charset="UTF-8">
# <title>Sensor Data</title>
# <style>
# * {{
# font-family: 'Caskaydia Cove NF';
# font-size: 18px;
# color: white;
# background: #1C1C1C;
# }}
# </style>
# </head>
# <body>
# {htmldata}
# </body>
# </html>
# """
# class MyHandler(BaseHTTPRequestHandler):
# def do_GET(self):
# self.send_response(200)
# # self.send_header("Content-type", "text/html")
# self.end_headers()
# self.wfile.write(html.encode("utf-8"))
#
#
# if __name__ == "__main__":
# server_address = ("", 8000)
# httpd = HTTPServer(server_address, MyHandler)
# print("Serving on http://localhost:8000")
# httpd.serve_forever()
app = Flask(__name__)
@app.route("/")
def index():
return render_template("index.html", data=sensors)
# @app.before_request
# def before_request():
# for sensor in sensors.values():
# print(sensor)
# sensor.renderPlot()
if __name__ == "__main__":
server_address = ("", 8000)
httpd = HTTPServer(server_address, MyHandler)
print("Serving on http://localhost:8000")
httpd.serve_forever()
app.run(debug=True)