mirror of
https://github.com/michivonah/bbzw-horizon.git
synced 2025-12-22 17:16:27 +01:00
Update firmware-encry
This commit is contained in:
parent
cd80cfd77a
commit
bec06107dc
1 changed files with 84 additions and 78 deletions
|
|
@ -4,8 +4,6 @@
|
||||||
#include <ArduinoHttpClient.h>
|
#include <ArduinoHttpClient.h>
|
||||||
#include <WiFiUdp.h>
|
#include <WiFiUdp.h>
|
||||||
#include <NTPClient.h>
|
#include <NTPClient.h>
|
||||||
#include <Crypto.h>
|
|
||||||
#include <AES.h>
|
|
||||||
|
|
||||||
// WLAN-Zugangsdaten
|
// WLAN-Zugangsdaten
|
||||||
#define SSID ""
|
#define SSID ""
|
||||||
|
|
@ -14,52 +12,12 @@
|
||||||
// API-Konfiguration
|
// API-Konfiguration
|
||||||
#define API_HOST ""
|
#define API_HOST ""
|
||||||
#define API_PORT 8080
|
#define API_PORT 8080
|
||||||
#define API_ENDPOINT "/sensors/push-data-encrypted"
|
#define API_ENDPOINT "/sensors/push-data/secure"
|
||||||
#define CLIENT_ID ""
|
#define CLIENT_ID ""
|
||||||
#define API_TOKEN ""
|
#define API_TOKEN ""
|
||||||
|
|
||||||
// AES-Schlüssel (128 Bit)
|
const String ALPHABET = "";
|
||||||
AES128 aes;
|
const String KEY = "";
|
||||||
byte aes_key[] = {
|
|
||||||
};
|
|
||||||
|
|
||||||
// Base64-Zeichen
|
|
||||||
const char base64_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
||||||
|
|
||||||
// Funktionen für Base64-Encoding
|
|
||||||
String base64Encode(byte* data, int len) {
|
|
||||||
String out = "";
|
|
||||||
for (int i = 0; i < len; i += 3) {
|
|
||||||
int val = (data[i] << 16) + (i + 1 < len ? data[i + 1] << 8 : 0) + (i + 2 < len ? data[i + 2] : 0);
|
|
||||||
out += base64_chars[(val >> 18) & 0x3F];
|
|
||||||
out += base64_chars[(val >> 12) & 0x3F];
|
|
||||||
out += (i + 1 < len) ? base64_chars[(val >> 6) & 0x3F] : '=';
|
|
||||||
out += (i + 2 < len) ? base64_chars[val & 0x3F] : '=';
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
String padToBlock(String input) {
|
|
||||||
int pad = 16 - (input.length() % 16);
|
|
||||||
for (int i = 0; i < pad; i++) input += '\0';
|
|
||||||
return input;
|
|
||||||
}
|
|
||||||
|
|
||||||
String encryptAndBase64(String plainText) {
|
|
||||||
String padded = padToBlock(plainText);
|
|
||||||
int len = padded.length();
|
|
||||||
byte plain[len];
|
|
||||||
byte encrypted[len];
|
|
||||||
|
|
||||||
padded.getBytes((unsigned char*)plain, len + 1);
|
|
||||||
|
|
||||||
aes.setKey(aes_key, sizeof(aes_key));
|
|
||||||
for (int i = 0; i < len; i += 16) {
|
|
||||||
aes.encryptBlock(encrypted + i, plain + i);
|
|
||||||
}
|
|
||||||
|
|
||||||
return base64Encode(encrypted, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sensor & Netzwerk
|
// Sensor & Netzwerk
|
||||||
Bsec iaqSensor;
|
Bsec iaqSensor;
|
||||||
|
|
@ -74,6 +32,7 @@ NTPClient timeClient(ntpUDP, "pool.ntp.org", utcOffsetInSeconds);
|
||||||
// Sendeintervall
|
// Sendeintervall
|
||||||
unsigned long sendInterval = 30000;
|
unsigned long sendInterval = 30000;
|
||||||
|
|
||||||
|
// Fehlercode per LED ausgeben (Morse-artig)
|
||||||
void errorBlink(int code) {
|
void errorBlink(int code) {
|
||||||
while (true) {
|
while (true) {
|
||||||
for (int i = 0; i < code; i++) {
|
for (int i = 0; i < code; i++) {
|
||||||
|
|
@ -82,16 +41,18 @@ void errorBlink(int code) {
|
||||||
digitalWrite(LED_BUILTIN, LOW);
|
digitalWrite(LED_BUILTIN, LOW);
|
||||||
delay(150);
|
delay(150);
|
||||||
}
|
}
|
||||||
delay(1000);
|
delay(1000); // Pause zwischen Zyklen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Werte begrenzen
|
||||||
float clampValue(float val) {
|
float clampValue(float val) {
|
||||||
if (val >= 1000.0) return 999.999;
|
if (val >= 1000.0) return 999.999;
|
||||||
if (val <= -1000.0) return -999.999;
|
if (val <= -1000.0) return -999.999;
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ISO-Zeitstempel generieren
|
||||||
String getTimestamp() {
|
String getTimestamp() {
|
||||||
timeClient.update();
|
timeClient.update();
|
||||||
unsigned long epochTime = timeClient.getEpochTime();
|
unsigned long epochTime = timeClient.getEpochTime();
|
||||||
|
|
@ -104,18 +65,24 @@ String getTimestamp() {
|
||||||
if (seconds >= daysInYear * 86400UL) {
|
if (seconds >= daysInYear * 86400UL) {
|
||||||
seconds -= daysInYear * 86400UL;
|
seconds -= daysInYear * 86400UL;
|
||||||
year++;
|
year++;
|
||||||
} else break;
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int month = 1;
|
int month = 1;
|
||||||
const int daysInMonth[] = {31,28,31,30,31,30,31,31,30,31,30,31};
|
const int daysInMonth[] = {31,28,31,30,31,30,31,31,30,31,30,31};
|
||||||
while (month <= 12) {
|
while (month <= 12) {
|
||||||
int dim = daysInMonth[month - 1];
|
int dim = daysInMonth[month - 1];
|
||||||
if (month == 2 && (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))) dim = 29;
|
if (month == 2 && (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))) {
|
||||||
|
dim = 29;
|
||||||
|
}
|
||||||
if (seconds >= dim * 86400UL) {
|
if (seconds >= dim * 86400UL) {
|
||||||
seconds -= dim * 86400UL;
|
seconds -= dim * 86400UL;
|
||||||
month++;
|
month++;
|
||||||
} else break;
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int day = seconds / 86400UL + 1;
|
int day = seconds / 86400UL + 1;
|
||||||
|
|
@ -130,6 +97,7 @@ String getTimestamp() {
|
||||||
return String(buf);
|
return String(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// API-Health-Check
|
||||||
bool checkApiHealth() {
|
bool checkApiHealth() {
|
||||||
HttpClient healthClient = HttpClient(wifi, API_HOST, API_PORT);
|
HttpClient healthClient = HttpClient(wifi, API_HOST, API_PORT);
|
||||||
healthClient.get("/health");
|
healthClient.get("/health");
|
||||||
|
|
@ -138,25 +106,49 @@ bool checkApiHealth() {
|
||||||
return statusCode == 200;
|
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() {
|
void setup() {
|
||||||
|
|
||||||
|
Serial.begin(9600);
|
||||||
|
while (!Serial);
|
||||||
|
Serial.println("Start");
|
||||||
|
|
||||||
pinMode(LED_BUILTIN, OUTPUT);
|
pinMode(LED_BUILTIN, OUTPUT);
|
||||||
digitalWrite(LED_BUILTIN, LOW);
|
digitalWrite(LED_BUILTIN, LOW);
|
||||||
|
|
||||||
|
// WLAN verbinden mit Timeout
|
||||||
WiFi.begin(SSID, PASSWORT);
|
WiFi.begin(SSID, PASSWORT);
|
||||||
unsigned long startAttemptTime = millis();
|
unsigned long startAttemptTime = millis();
|
||||||
while (WiFi.status() != WL_CONNECTED && millis() - startAttemptTime < 20000) {
|
while (WiFi.status() != WL_CONNECTED && millis() - startAttemptTime < 20000) {
|
||||||
delay(500);
|
delay(500);
|
||||||
}
|
}
|
||||||
if (WiFi.status() != WL_CONNECTED) {
|
if (WiFi.status() != WL_CONNECTED) {
|
||||||
errorBlink(1);
|
errorBlink(1); // Fehlercode 1: WLAN-Fehler
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// API-Healthcheck
|
||||||
if (!checkApiHealth()) {
|
if (!checkApiHealth()) {
|
||||||
errorBlink(4);
|
errorBlink(4); // Fehlercode 4: API nicht erreichbar
|
||||||
}
|
}
|
||||||
|
|
||||||
Wire.begin();
|
Wire.begin();
|
||||||
|
|
||||||
|
// Automatische Sensor-Erkennung
|
||||||
byte sensorAddress = 0;
|
byte sensorAddress = 0;
|
||||||
byte possibleAddresses[] = {0x76, 0x77};
|
byte possibleAddresses[] = {0x76, 0x77};
|
||||||
bool sensorFound = false;
|
bool sensorFound = false;
|
||||||
|
|
@ -171,12 +163,12 @@ void setup() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sensorFound) {
|
if (!sensorFound) {
|
||||||
errorBlink(2);
|
errorBlink(2); // Fehlercode 2: Sensor nicht gefunden
|
||||||
}
|
}
|
||||||
|
|
||||||
iaqSensor.begin(sensorAddress, Wire);
|
iaqSensor.begin(sensorAddress, Wire);
|
||||||
if (iaqSensor.bsecStatus != BSEC_OK) {
|
if (iaqSensor.bsecStatus != BSEC_OK) {
|
||||||
errorBlink(3);
|
errorBlink(3); // Fehlercode 3: Sensor-Init fehlgeschlagen
|
||||||
}
|
}
|
||||||
|
|
||||||
bsec_virtual_sensor_t sensorList[] = {
|
bsec_virtual_sensor_t sensorList[] = {
|
||||||
|
|
@ -193,53 +185,67 @@ void setup() {
|
||||||
timeClient.forceUpdate();
|
timeClient.forceUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
digitalWrite(LED_BUILTIN, HIGH);
|
digitalWrite(LED_BUILTIN, HIGH); // Alles bereit – LED dauerhaft an
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
if (iaqSensor.run()) {
|
if (iaqSensor.run()) {
|
||||||
|
// Kurzes LED-Blink zur Messanzeige
|
||||||
|
digitalWrite(LED_BUILTIN, LOW);
|
||||||
|
delay(100);
|
||||||
|
digitalWrite(LED_BUILTIN, HIGH);
|
||||||
|
|
||||||
float temperature = clampValue(iaqSensor.temperature);
|
float temperature = clampValue(iaqSensor.temperature);
|
||||||
float humidity = clampValue(iaqSensor.humidity);
|
float humidity = clampValue(iaqSensor.humidity);
|
||||||
float voc = clampValue(iaqSensor.iaq);
|
float voc = clampValue(iaqSensor.iaq);
|
||||||
float gas = clampValue(iaqSensor.gasResistance / 1000.0);
|
float gas = clampValue(iaqSensor.gasResistance / 1000.0);
|
||||||
float pressure = iaqSensor.pressure / 100.0;
|
float pressure = iaqSensor.pressure / 100.0;
|
||||||
|
|
||||||
String timestamp = getTimestamp();
|
String timestamp = getTimestamp();
|
||||||
|
|
||||||
String jsonPayload = "{";
|
// Werte in Strings mit z.B. 3 Dezimalstellen
|
||||||
jsonPayload += "\"timestamp\": \"" + timestamp + "\",";
|
String temperatureStr = String(temperature, 3);
|
||||||
jsonPayload += "\"temperature\": " + String(temperature, 3) + ",";
|
String humidityStr = String(humidity, 3);
|
||||||
jsonPayload += "\"humidity\": " + String(humidity, 3) + ",";
|
String vocStr = String(voc, 3);
|
||||||
jsonPayload += "\"pressure\": " + String(pressure, 3) + ",";
|
String gasStr = String(gas, 3);
|
||||||
jsonPayload += "\"voc\": " + String(voc, 3) + ",";
|
String pressureStr = String(pressure, 3);
|
||||||
jsonPayload += "\"gas\": " + String(gas, 3);
|
|
||||||
jsonPayload += "}";
|
|
||||||
|
|
||||||
String encryptedPayload = encryptAndBase64(jsonPayload);
|
// 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;
|
String fullPath = String(API_ENDPOINT) + "?client=" + CLIENT_ID;
|
||||||
|
|
||||||
client.beginRequest();
|
client.beginRequest();
|
||||||
client.post(fullPath);
|
client.post(fullPath);
|
||||||
client.sendHeader("Content-Type", "text/plain");
|
client.sendHeader("Content-Type", "application/json");
|
||||||
client.sendHeader("token", API_TOKEN);
|
client.sendHeader("token", API_TOKEN);
|
||||||
client.sendHeader("Content-Length", encryptedPayload.length());
|
client.sendHeader("Content-Length", payload.length());
|
||||||
client.beginBody();
|
client.beginBody();
|
||||||
client.print(encryptedPayload);
|
client.print(payload);
|
||||||
client.endRequest();
|
client.endRequest();
|
||||||
|
|
||||||
|
Serial.println(payload);
|
||||||
|
Serial.println(fullPath);
|
||||||
|
|
||||||
int statusCode = client.responseStatusCode();
|
int statusCode = client.responseStatusCode();
|
||||||
client.responseBody();
|
String response = client.responseBody();
|
||||||
|
Serial.println(statusCode);
|
||||||
|
Serial.println(response);
|
||||||
|
|
||||||
if (statusCode == 200) {
|
|
||||||
digitalWrite(LED_BUILTIN, LOW);
|
|
||||||
delay(100);
|
|
||||||
digitalWrite(LED_BUILTIN, HIGH);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (statusCode < 200 || statusCode >= 300) {
|
|
||||||
digitalWrite(LED_BUILTIN, LOW);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
delay(sendInterval);
|
delay(sendInterval);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue