initial version

This commit is contained in:
2023-10-30 23:15:40 +01:00
commit 8f8c69c37a
13 changed files with 321 additions and 0 deletions

1
raspberryPi/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
db/

10
raspberryPi/Dockerfile Normal file
View File

@ -0,0 +1,10 @@
FROM python:3.9.18
WORKDIR /usr/src/app
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
COPY src .
CMD ["python", "./main.py"]

View File

@ -0,0 +1,3 @@
pyserial==3.5
cobs==1.2.1
flask==3.0.0

1
raspberryPi/src/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
__pycache__/

8
raspberryPi/src/main.py Normal file
View File

@ -0,0 +1,8 @@
import threading
import reader
import website
readThread = threading.Thread(target=reader.read)
websiteThread = threading.Thread(target=website.runWebsite)
readThread.start()
websiteThread.start()

80
raspberryPi/src/reader.py Normal file
View File

@ -0,0 +1,80 @@
import serial
import sqlite3
from cobs import cobs
import time
import struct
from dataclasses import dataclass
from datetime import datetime
@dataclass
class Sensor:
id: int
accuracy: float
resolution: float
@dataclass
class DataPoint:
sensorId: int
value: float
def ensureDatabaseExists(con: sqlite3.Connection) -> None:
cur = con.cursor()
cur.execute("""
CREATE TABLE IF NOT EXISTS sensor(
sensorId INTEGER NOT NULL PRIMARY KEY,
resolution REAL NOT NULL,
accuracy REAL NOT NULL
);
""")
cur.execute("""
CREATE TABLE IF NOT EXISTS dataPoint(
dataPointId INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
sensorFK INTEGER NOT NULL,
timestamp INTEGER NOT NULL,
value REAL NOT NULL,
FOREIGN KEY(sensorFK) REFERENCES sensor(sensorId)
);
""")
def ensureSensorExists(con: sqlite3.Connection, sensor: Sensor) -> None:
ensureDatabaseExists(con)
cur = con.cursor()
res = cur.execute("SELECT COUNT(sensorId) FROM sensor WHERE sensorId = ?;", (sensor.id,))
if(res.fetchone()[0] == 0):
cur.execute("INSERT INTO sensor(sensorId, resolution, accuracy) VALUES(?, ?, ?);", (sensor.id, sensor.resolution, sensor.accuracy))
def addDataPoint(con: sqlite3.Connection, dataPoint: DataPoint) -> bool:
ensureDatabaseExists(con)
cur = con.cursor()
res = cur.execute("SELECT COUNT(sensorId) FROM sensor WHERE sensorId = ?;", (dataPoint.sensorId,))
if(res.fetchone() == 0):
return False
cur.execute("INSERT INTO dataPoint(sensorFK, timestamp, value) VALUES(?, ?, ?);", (dataPoint.sensorId, round((datetime.utcnow() - datetime(1970, 1, 1)).total_seconds()), dataPoint.value))
return True
def read() -> None:
con = sqlite3.connect("/data/specialIO.db")
with serial.Serial("/dev/ttyACM0", 9600) as s:
time.sleep(0.1)
s.reset_input_buffer()
while True:
packet = cobs.decode(s.read_until(expected=b'\x00')[:-1])
if(packet[0] == 0x01):
parsed = struct.unpack_from('<HBf', packet, 1)
sensor = Sensor(parsed[0], parsed[1], parsed[2])
ensureSensorExists(con, sensor)
print(f"register: {sensor}")
con.commit()
elif(packet[0] == 0x02):
parsed = struct.unpack_from('<Hf', packet, 1)
dataPoint = DataPoint(parsed[0], parsed[1])
addDataPoint(con, dataPoint)
print(f"data: {dataPoint}")
con.commit()
else:
raise ValueError("Received packet with unknown type", packet)

View File

@ -0,0 +1,47 @@
<!DOCTYPE html>
<html lang="en" style="margin: 0; height: 100%;">
<head>
<meta charset="UTF-8">
<title>Sensoren grafiek</title>
</head>
<body style="margin: 0; height: 100%;">
<div style="position: relative; height: 100%; width: 100%;">
<canvas id="sensorChart"></canvas>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns/dist/chartjs-adapter-date-fns.bundle.min.js"></script>
<script>
(async () => {
const ctx = document.getElementById("sensorChart");
const now = Math.floor(Date.now() / 1000)
const jsonData = (await (await fetch(`/api/data/${now-60*10}/${now}`)).json());
const data = {
datasets: Object.entries(jsonData).map(
x => ({
label: x[0],
data: x[1]["data"].map(dataPoint => ({x: dataPoint.time*1000, y: dataPoint.value}))
})
)
}
new Chart(ctx, {
type: "line",
data: data,
options: {
scales: {
x: {
type: 'time'
}
},
responsive: true,
}
});
})()
</script>
</body>
</html>

View File

@ -0,0 +1,24 @@
from flask import Flask
import sqlite3
app = Flask(__name__, static_folder='static')
@app.route("/api/data/<int:start>/<int:end>")
def getData(start: int, end: int) -> dict:
dbCon = sqlite3.connect("/data/specialIO.db")
cur = dbCon.cursor()
retVal = {}
for sensor in cur.execute("SELECT sensorId, resolution, accuracy FROM sensor;").fetchall():
retVal[sensor[0]] = {"resolution": sensor[1], "accuracy": sensor[2], "data":[]}
results = cur.execute("SELECT timestamp, value FROM dataPoint WHERE dataPoint.sensorFK = ? AND timestamp >= ? AND timestamp <= ?;", (sensor[0], start, end)).fetchall()
retVal[sensor[0]]["data"] = list(map(lambda x: {"time": x[0], "value": x[1]}, results))
return retVal
@app.route("/")
def index():
return app.send_static_file("index.html")
def runWebsite() -> None:
app.run(host='0.0.0.0')