#include #include #include "bsec.h" #include #include #include // WLAN-Zugangsdaten #define SSID "" #define PASSWORT "" // API-Konfiguration #define API_HOST "" #define API_PORT 8080 #define API_ENDPOINT "/sensors/push-data/secure" #define CLIENT_ID "" #define API_TOKEN "" const String ALPHABET = ""; const String KEY = ""; // Sensor & Netzwerk Bsec iaqSensor; WiFiClient wifi; HttpClient client = HttpClient(wifi, API_HOST, API_PORT); // NTP-Client WiFiUDP ntpUDP; const long utcOffsetInSeconds = 0; NTPClient timeClient(ntpUDP, "pool.ntp.org", utcOffsetInSeconds); // Sendeintervall unsigned long sendInterval = 30000; // Fehlercode per LED ausgeben (Morse-artig) void errorBlink(int code) { while (true) { for (int i = 0; i < code; i++) { digitalWrite(LED_BUILTIN, HIGH); delay(150); digitalWrite(LED_BUILTIN, LOW); delay(150); } delay(1000); // Pause zwischen Zyklen } } // Werte begrenzen float clampValue(float val) { if (val >= 1000.0) return 999.999; if (val <= -1000.0) return -999.999; return val; } // ISO-Zeitstempel generieren String getTimestamp() { timeClient.update(); unsigned long epochTime = timeClient.getEpochTime(); int year = 1970; unsigned long seconds = epochTime; while (true) { bool leap = (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)); int daysInYear = leap ? 366 : 365; if (seconds >= daysInYear * 86400UL) { seconds -= daysInYear * 86400UL; year++; } else { break; } } int month = 1; const int daysInMonth[] = {31,28,31,30,31,30,31,31,30,31,30,31}; while (month <= 12) { int dim = daysInMonth[month - 1]; if (month == 2 && (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))) { dim = 29; } if (seconds >= dim * 86400UL) { seconds -= dim * 86400UL; month++; } else { break; } } int day = seconds / 86400UL + 1; seconds = seconds % 86400UL; int hour = seconds / 3600UL; seconds = seconds % 3600UL; int minute = seconds / 60UL; int second = seconds % 60UL; char buf[30]; sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02dZ", year, month, day, hour, minute, second); return String(buf); } // API-Health-Check bool checkApiHealth() { HttpClient healthClient = HttpClient(wifi, API_HOST, API_PORT); healthClient.get("/health"); int statusCode = healthClient.responseStatusCode(); healthClient.stop(); return statusCode == 200; } // Funktion zum Substituieren (Verschlüsseln) eines Strings String substituteString(String input, String alphabet, String key) { input.toUpperCase(); String output = ""; for (int i = 0; i < input.length(); i++) { char c = input.charAt(i); int index = alphabet.indexOf(c); if (index == -1) { // Zeichen nicht im Alphabet, unverändert belassen (z.B. Leerzeichen?) output += c; } else { output += key.charAt(index); } } return output; } void setup() { Serial.begin(9600); while (!Serial); Serial.println("Start"); pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, LOW); // WLAN verbinden mit Timeout WiFi.begin(SSID, PASSWORT); unsigned long startAttemptTime = millis(); while (WiFi.status() != WL_CONNECTED && millis() - startAttemptTime < 20000) { delay(500); } if (WiFi.status() != WL_CONNECTED) { errorBlink(1); // Fehlercode 1: WLAN-Fehler } // API-Healthcheck if (!checkApiHealth()) { errorBlink(4); // Fehlercode 4: API nicht erreichbar } Wire.begin(); // Automatische Sensor-Erkennung byte sensorAddress = 0; byte possibleAddresses[] = {0x76, 0x77}; bool sensorFound = false; for (int i = 0; i < 2; i++) { byte addr = possibleAddresses[i]; Wire.beginTransmission(addr); if (Wire.endTransmission() == 0) { sensorAddress = addr; sensorFound = true; break; } } if (!sensorFound) { errorBlink(2); // Fehlercode 2: Sensor nicht gefunden } iaqSensor.begin(sensorAddress, Wire); if (iaqSensor.bsecStatus != BSEC_OK) { errorBlink(3); // Fehlercode 3: Sensor-Init fehlgeschlagen } bsec_virtual_sensor_t sensorList[] = { BSEC_OUTPUT_IAQ, BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE, BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY, BSEC_OUTPUT_RAW_PRESSURE, BSEC_OUTPUT_RAW_GAS }; iaqSensor.updateSubscription(sensorList, 5, BSEC_SAMPLE_RATE_LP); timeClient.begin(); while (!timeClient.update()) { timeClient.forceUpdate(); } digitalWrite(LED_BUILTIN, HIGH); // Alles bereit – LED dauerhaft an } void loop() { if (iaqSensor.run()) { // Kurzes LED-Blink zur Messanzeige digitalWrite(LED_BUILTIN, LOW); delay(100); digitalWrite(LED_BUILTIN, HIGH); float temperature = clampValue(iaqSensor.temperature); float humidity = clampValue(iaqSensor.humidity); float voc = clampValue(iaqSensor.iaq); float gas = clampValue(iaqSensor.gasResistance / 1000.0); float pressure = iaqSensor.pressure / 100.0; String timestamp = getTimestamp(); // Werte in Strings mit z.B. 3 Dezimalstellen String temperatureStr = String(temperature, 3); String humidityStr = String(humidity, 3); String vocStr = String(voc, 3); String gasStr = String(gas, 3); String pressureStr = String(pressure, 3); // Alle Strings verschlüsseln (substituieren) String encryptedTimestamp = substituteString(timestamp, ALPHABET, KEY); String encryptedTemperature = substituteString(temperatureStr, ALPHABET, KEY); String encryptedHumidity = substituteString(humidityStr, ALPHABET, KEY); String encryptedVoc = substituteString(vocStr, ALPHABET, KEY); String encryptedGas = substituteString(gasStr, ALPHABET, KEY); String encryptedPressure = substituteString(pressureStr, ALPHABET, KEY); // JSON-Payload mit verschlüsselten Strings String payload = "{"; payload += "\"timestamp\": \"" + encryptedTimestamp + "\","; payload += "\"temperature\": \"" + encryptedTemperature + "\","; payload += "\"humidity\": \"" + encryptedHumidity + "\","; payload += "\"pressure\": \"" + encryptedPressure + "\","; payload += "\"voc\": \"" + encryptedVoc + "\","; payload += "\"gas\": \"" + encryptedGas + "\""; payload += "}"; // Sende Request String fullPath = String(API_ENDPOINT) + "?client=" + CLIENT_ID; client.beginRequest(); client.post(fullPath); client.sendHeader("Content-Type", "application/json"); client.sendHeader("token", API_TOKEN); client.sendHeader("Content-Length", payload.length()); client.beginBody(); client.print(payload); client.endRequest(); Serial.println(payload); Serial.println(fullPath); int statusCode = client.responseStatusCode(); String response = client.responseBody(); Serial.println(statusCode); Serial.println(response); } delay(sendInterval); }