mirror of
https://github.com/michivonah/bbzw-horizon.git
synced 2025-12-22 17:16:27 +01:00
add existing files
This commit is contained in:
parent
75653e9c5b
commit
a38e1678a6
7 changed files with 280 additions and 0 deletions
97
arduino/firmware.ino
Normal file
97
arduino/firmware.ino
Normal file
|
|
@ -0,0 +1,97 @@
|
||||||
|
#include <WiFiNINA.h>
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <Adafruit_Sensor.h>
|
||||||
|
#include <Adafruit_BME680.h>
|
||||||
|
|
||||||
|
#define SSID ""
|
||||||
|
#define PASSWORT ""
|
||||||
|
#define API_HOST "" // Deine API-Domain
|
||||||
|
#define API_ENDPOINT "/sensor-data/" // API-Endpunkt
|
||||||
|
#define API_PORT 8080 // Falls HTTPS, dann 443
|
||||||
|
#define CLIENT_ID "1.54" // Eindeutige ID für den Arduino
|
||||||
|
#define API_TOKEN "test2" // Setze hier dein API-Token
|
||||||
|
|
||||||
|
Adafruit_BME680 bme;
|
||||||
|
WiFiClient client;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
while (!Serial);
|
||||||
|
|
||||||
|
if (WiFi.status() == WL_NO_MODULE) {
|
||||||
|
Serial.println("WiFi-Modul nicht gefunden!");
|
||||||
|
while (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
WiFi.begin(SSID, PASSWORT);
|
||||||
|
Serial.print("Verbinde mit WLAN...");
|
||||||
|
while (WiFi.status() != WL_CONNECTED) {
|
||||||
|
delay(500);
|
||||||
|
Serial.print(".");
|
||||||
|
}
|
||||||
|
Serial.println("\nWLAN verbunden!");
|
||||||
|
|
||||||
|
if (!bme.begin()) {
|
||||||
|
Serial.println("BME680 nicht gefunden!");
|
||||||
|
while (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bme.setTemperatureOversampling(BME680_OS_8X);
|
||||||
|
bme.setHumidityOversampling(BME680_OS_2X);
|
||||||
|
bme.setPressureOversampling(BME680_OS_4X);
|
||||||
|
bme.setIIRFilterSize(BME680_FILTER_SIZE_3);
|
||||||
|
bme.setGasHeater(320, 150);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
if (!bme.performReading()) {
|
||||||
|
Serial.println("Fehler beim Auslesen des BME680!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WiFi.status() == WL_CONNECTED) {
|
||||||
|
Serial.println("Sende Daten an API...");
|
||||||
|
|
||||||
|
String jsonPayload = "{";
|
||||||
|
jsonPayload += "\"token\": \"" + String(API_TOKEN) + "\",";
|
||||||
|
jsonPayload += "\"clientid\": \"" + String(CLIENT_ID) + "\",";
|
||||||
|
jsonPayload += "\"temperature\": " + String(bme.temperature) + ",";
|
||||||
|
jsonPayload += "\"humidity\": " + String(bme.humidity) + ",";
|
||||||
|
jsonPayload += "\"pressure\": " + String(bme.pressure / 100.0) + ",";
|
||||||
|
jsonPayload += "\"voc\": " + String(0.0) + ","; // Falls VOC nicht gemessen wird
|
||||||
|
jsonPayload += "\"gas\": " + String(bme.gas_resistance / 1000.0);
|
||||||
|
jsonPayload += "}";
|
||||||
|
|
||||||
|
if (client.connect(API_HOST, API_PORT)) { // Falls HTTPS genutzt wird, dann WiFiSSLClient
|
||||||
|
client.println("POST " + String(API_ENDPOINT) + " HTTP/1.1");
|
||||||
|
client.println("Host: " + String(API_HOST));
|
||||||
|
client.println("Content-Type: application/json");
|
||||||
|
client.print("Content-Length: ");
|
||||||
|
client.println(jsonPayload.length());
|
||||||
|
client.println();
|
||||||
|
client.println(jsonPayload);
|
||||||
|
|
||||||
|
unsigned long timeout = millis() + 5000; // Wartezeit für die Antwort
|
||||||
|
while (client.available() == 0) {
|
||||||
|
if (millis() > timeout) {
|
||||||
|
Serial.println("Timeout bei API-Antwort!");
|
||||||
|
client.stop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (client.available()) {
|
||||||
|
String response = client.readString();
|
||||||
|
Serial.println("API Antwort: " + response);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Serial.println("Fehler beim Verbinden mit API!");
|
||||||
|
}
|
||||||
|
|
||||||
|
client.stop();
|
||||||
|
} else {
|
||||||
|
Serial.println("WLAN nicht verbunden!");
|
||||||
|
}
|
||||||
|
|
||||||
|
delay(5000);
|
||||||
|
}
|
||||||
BIN
db/ERMv2.png
Normal file
BIN
db/ERMv2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 171 KiB |
51
db/create_db.sql
Normal file
51
db/create_db.sql
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
SETUP DATABASE ENVIROMENT FOR bbzw-horizon
|
||||||
|
INP21bL - M241/M245
|
||||||
|
*/
|
||||||
|
|
||||||
|
-- CREATE TABLES
|
||||||
|
|
||||||
|
CREATE TABLE "clients"(
|
||||||
|
id INTEGER GENERATED BY DEFAULT AS IDENTITY,
|
||||||
|
name VARCHAR(50),
|
||||||
|
PRIMARY KEY(id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE "sensor_data"(
|
||||||
|
id INTEGER GENERATED BY DEFAULT AS IDENTITY,
|
||||||
|
timestamp TIMESTAMP,
|
||||||
|
humidity DECIMAL(5,3),
|
||||||
|
pressure DECIMAL(5,3),
|
||||||
|
temperature DECIMAL(5,3),
|
||||||
|
voc DECIMAL(5,3),
|
||||||
|
gas DECIMAL(5,3),
|
||||||
|
clientid INTEGER,
|
||||||
|
PRIMARY KEY(id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE "user"(
|
||||||
|
id INTEGER GENERATED BY DEFAULT AS IDENTITY,
|
||||||
|
name VARCHAR(50),
|
||||||
|
mail VARCHAR(150),
|
||||||
|
password VARCHAR(250),
|
||||||
|
api_access BOOLEAN,
|
||||||
|
PRIMARY KEY(id)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
CREATE TABLE "sessions"(
|
||||||
|
id INTEGER GENERATED BY DEFAULT AS IDENTITY,
|
||||||
|
token VARCHAR(96),
|
||||||
|
validuntil DATE,
|
||||||
|
userid INTEGER,
|
||||||
|
PRIMARY KEY(id)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
-- SET FOREIGN KEYS
|
||||||
|
ALTER TABLE "sensor_data" ADD FOREIGN KEY(clientid) REFERENCES "clients"(id);
|
||||||
|
ALTER TABLE "sessions" ADD FOREIGN KEY(userid) REFERENCES "user"(id);
|
||||||
|
|
||||||
|
-- SET DEFAULT VALUES
|
||||||
|
ALTER TABLE "user" ALTER COLUMN "api_access" SET DEFAULT False;
|
||||||
|
ALTER TABLE "sensor_data" ALTER COLUMN "timestamp" SET DEFAULT Now();
|
||||||
8
db/create_users.sql
Normal file
8
db/create_users.sql
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
INSERT INTO "user" ("name", "api_access") VALUES
|
||||||
|
('test', True);
|
||||||
|
|
||||||
|
INSERT INTO "sessions" ("token", "userid", "validuntil") VALUES
|
||||||
|
('test2', 1, '2025-04-30');
|
||||||
|
|
||||||
|
INSERT INTO "clients" ("name") VALUES
|
||||||
|
('1.54');
|
||||||
25
webservice/Dockerfile.txt
Normal file
25
webservice/Dockerfile.txt
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
FROM python:3.12
|
||||||
|
|
||||||
|
# Create directory
|
||||||
|
RUN mkdir app
|
||||||
|
WORKDIR /app/
|
||||||
|
|
||||||
|
# Copy files
|
||||||
|
COPY requirements.txt .
|
||||||
|
|
||||||
|
# Set enviromental variables
|
||||||
|
ENV DB_CONNECTION_STRING ep-plannerDB
|
||||||
|
|
||||||
|
# Install needed packages
|
||||||
|
RUN pip3 install --upgrade pip
|
||||||
|
RUN pip3 install pipenv
|
||||||
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
|
# Expose port
|
||||||
|
EXPOSE 8080
|
||||||
|
|
||||||
|
# Imort script
|
||||||
|
COPY webservice.py .
|
||||||
|
|
||||||
|
# Start app
|
||||||
|
CMD ["uvicorn", "webservice:app", "--host", "0.0.0.0", "--port", "8080"]
|
||||||
5
webservice/requirements.txt
Normal file
5
webservice/requirements.txt
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
fastapi
|
||||||
|
uvicorn
|
||||||
|
sqlalchemy
|
||||||
|
psycopg2-binary
|
||||||
|
|
||||||
94
webservice/webservice.py
Normal file
94
webservice/webservice.py
Normal file
|
|
@ -0,0 +1,94 @@
|
||||||
|
from fastapi import FastAPI, Depends, HTTPException
|
||||||
|
from sqlalchemy import Column, Integer, Float, String, DateTime, create_engine, ForeignKey
|
||||||
|
from sqlalchemy.orm import sessionmaker, declarative_base, Session, relationship
|
||||||
|
from datetime import datetime
|
||||||
|
import os
|
||||||
|
|
||||||
|
DATABASE_URL = os.getenv("DB_CONNECTION_STRING", "postgresql://user:password@localhost/sensordb")
|
||||||
|
|
||||||
|
Base = declarative_base()
|
||||||
|
engine = create_engine(DATABASE_URL)
|
||||||
|
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
||||||
|
|
||||||
|
app = FastAPI()
|
||||||
|
|
||||||
|
# Neue Clients-Tabelle
|
||||||
|
class Client(Base):
|
||||||
|
__tablename__ = "clients"
|
||||||
|
|
||||||
|
id = Column(Integer, primary_key=True, index=True)
|
||||||
|
name = Column(String, unique=True, index=True)
|
||||||
|
|
||||||
|
class SensorData(Base):
|
||||||
|
__tablename__ = "sensor_data"
|
||||||
|
|
||||||
|
id = Column(Integer, primary_key=True, index=True)
|
||||||
|
clientid = Column(Integer, ForeignKey("clients.id"), index=True)
|
||||||
|
timestamp = Column(DateTime, default=datetime.utcnow)
|
||||||
|
temperature = Column(Float)
|
||||||
|
humidity = Column(Float)
|
||||||
|
pressure = Column(Float)
|
||||||
|
voc = Column(Float)
|
||||||
|
gas = Column(Float)
|
||||||
|
|
||||||
|
client = relationship("Client")
|
||||||
|
|
||||||
|
class SessionToken(Base):
|
||||||
|
__tablename__ = "sessions"
|
||||||
|
|
||||||
|
id = Column(Integer, primary_key=True, index=True)
|
||||||
|
token = Column(String, unique=True, index=True)
|
||||||
|
validuntil = Column(DateTime)
|
||||||
|
userid = Column(Integer, ForeignKey("user.id"))
|
||||||
|
|
||||||
|
def get_db():
|
||||||
|
db = SessionLocal()
|
||||||
|
try:
|
||||||
|
yield db
|
||||||
|
finally:
|
||||||
|
db.close()
|
||||||
|
|
||||||
|
def verify_token(token: str, db: Session):
|
||||||
|
session = db.query(SessionToken).filter(SessionToken.token == token).first()
|
||||||
|
if not session or session.validuntil < datetime.utcnow():
|
||||||
|
raise HTTPException(status_code=401, detail="Invalid or expired token")
|
||||||
|
return session
|
||||||
|
|
||||||
|
@app.post("/sensor-data/")
|
||||||
|
def receive_sensor_data(
|
||||||
|
token: str,
|
||||||
|
clientname: str, # Ändert clientid zu clientname
|
||||||
|
temperature: float,
|
||||||
|
humidity: float,
|
||||||
|
pressure: float,
|
||||||
|
voc: float,
|
||||||
|
gas: float,
|
||||||
|
db: Session = Depends(get_db)
|
||||||
|
):
|
||||||
|
verify_token(token, db)
|
||||||
|
|
||||||
|
# Suche die Client-ID anhand des Client-Namens
|
||||||
|
client = db.query(Client).filter(Client.name == clientname).first()
|
||||||
|
if not client:
|
||||||
|
raise HTTPException(status_code=404, detail="Client not found")
|
||||||
|
|
||||||
|
sensor_data = SensorData(
|
||||||
|
clientid=client.id, # Verwende die gefundene ID
|
||||||
|
temperature=temperature,
|
||||||
|
humidity=humidity,
|
||||||
|
pressure=pressure,
|
||||||
|
voc=voc,
|
||||||
|
gas=gas
|
||||||
|
)
|
||||||
|
db.add(sensor_data)
|
||||||
|
db.commit()
|
||||||
|
db.refresh(sensor_data)
|
||||||
|
return {"message": "Data received", "id": sensor_data.id}
|
||||||
|
|
||||||
|
@app.get("/sensor-data/")
|
||||||
|
def get_sensor_data(db: Session = Depends(get_db)):
|
||||||
|
data = db.query(SensorData).all()
|
||||||
|
return data
|
||||||
|
|
||||||
|
# Erstelle die Tabellen, falls sie noch nicht existieren
|
||||||
|
Base.metadata.create_all(bind=engine)
|
||||||
Loading…
Add table
Add a link
Reference in a new issue