add existing files

This commit is contained in:
Michi 2025-03-26 08:39:47 +01:00
parent 75653e9c5b
commit a38e1678a6
7 changed files with 280 additions and 0 deletions

97
arduino/firmware.ino Normal file
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

51
db/create_db.sql Normal file
View 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
View 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
View 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"]

View file

@ -0,0 +1,5 @@
fastapi
uvicorn
sqlalchemy
psycopg2-binary

94
webservice/webservice.py Normal file
View 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)