bbzw-horizon/arduino/firmware-encry
2025-05-02 13:26:16 +02:00

252 lines
6.8 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <WiFiNINA.h>
#include <Wire.h>
#include "bsec.h"
#include <ArduinoHttpClient.h>
#include <WiFiUdp.h>
#include <NTPClient.h>
// 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);
}