From a38e1678a68c7ba2cce6ee894c1525197c150508 Mon Sep 17 00:00:00 2001 From: michivonah Date: Wed, 26 Mar 2025 08:39:47 +0100 Subject: [PATCH] add existing files --- arduino/firmware.ino | 97 ++++++++++++++++++++++++++++++++++++ db/ERMv2.png | Bin 0 -> 175015 bytes db/create_db.sql | 51 +++++++++++++++++++ db/create_users.sql | 8 +++ webservice/Dockerfile.txt | 25 ++++++++++ webservice/requirements.txt | 5 ++ webservice/webservice.py | 94 ++++++++++++++++++++++++++++++++++ 7 files changed, 280 insertions(+) create mode 100644 arduino/firmware.ino create mode 100644 db/ERMv2.png create mode 100644 db/create_db.sql create mode 100644 db/create_users.sql create mode 100644 webservice/Dockerfile.txt create mode 100644 webservice/requirements.txt create mode 100644 webservice/webservice.py diff --git a/arduino/firmware.ino b/arduino/firmware.ino new file mode 100644 index 0000000..edcb6cd --- /dev/null +++ b/arduino/firmware.ino @@ -0,0 +1,97 @@ +#include +#include +#include +#include + +#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); +} diff --git a/db/ERMv2.png b/db/ERMv2.png new file mode 100644 index 0000000000000000000000000000000000000000..dc1a207e90778fb847d2b31e88fe414744642635 GIT binary patch literal 175015 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