user29144738
user29144738

Reputation: 21

ESP32 + 9DOF+ RFM95W + Deep Sleep with LoRaWan

I have developed a LoRaWAN sensor that transmits its data to TTN. The hardware is based on an ESP board. The software for the sensor is written using the Arduino IDE and is based on the LMIC library.

When powered on, the sensor operates correctly, transmitting data to TTN as expected. I’m sending one packet every time the 9DOF sensor moves, like every 10 minutes or something.

I tried implementing deep sleep mode to save power. While this partially improved the battery life, I ran into a different problem: the data transmission became unreliable. The node transmits the data as expected, and the packets are received by the gateway.

However, the data does not consistently appear on TTN. Sometimes no data arrives for a long time, and sometimes multiple packets are received in a row. I also have implemented the LMIC_shutdown(); function but it really did not help.

Has anyone experienced similar issues when using deep sleep with LMIC and LoRaWAN? If so, were you able to find a solution? Any advice or insights would be greatly appreciated.

I also uploaded my Code, I hope someone can help me.

#include <Arduino.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_LSM303_U.h>
#include <esp_sleep.h>
#include <Adafruit_9DOF.h>
#include <LSM303.h>
#include <WiFi.h>
#include <Preferences.h>
#include <lmic.h>
#include <hal/hal.h>
#include <lmic.h>
#include <Preferences.h>

// Sensor-Instanzen erstellen
Adafruit_LSM303_Accel_Unified accel = Adafruit_LSM303_Accel_Unified(54321);
Adafruit_LSM303_Mag_Unified mag = Adafruit_LSM303_Mag_Unified(12345);
LSM303 lsm;

// Variablen für Kalibrierung
float closedAccelX, closedAccelY, closedAccelZ;
float closedMagX, closedMagY, closedMagZ;
float openAccelX, openAccelY, openAccelZ;
float openMagX, openMagY, openMagZ;
float tiltedAccelX, tiltedAccelY, tiltedAccelZ;   // Werte für den gekippten Zustand
float tiltedMagX, tiltedMagY, tiltedMagZ;
float halfOpenAccelX, halfOpenAccelY, halfOpenAccelZ; // Werte für den halb offenen Zustand
float halfOpenMagX, halfOpenMagY, halfOpenMagZ;

// Schwellenwerte für Statuserkennung
float accelThreshold = 0.5;  // Toleranzwert für Beschleunigung
float magThreshold = 5.0;    // Toleranzwert für Magnetometer
float halfOpenThreshold = 5.0; // Schwellenwert für "halb offen"
float tiltThreshold = 1.5;   // Schwellenwert für Kipp-Winkel (z.B. y-Achse)
unsigned long tiltStartTime = 0;
const unsigned long tiltDelayTime = 2000; // 2 Sekunden Verzögerung für "gekippt"

// Taster-Pin und Status
const int buttonPin = 13;    // Pin für den Taster
bool lastButtonState = HIGH; // Letzter Tasterstatus
unsigned long lastDebounceTime = 0;
const unsigned long debounceDelay = 50; // Entprellzeit in Millisekunden
Preferences preferences;

// Funktionsprototypen
void calibrateClosedState();
void calibrateOpenState();
void calibrateTiltedState();     // Funktion für gekippten Zustand
void calibrateHalfOpenState();   // Funktion für halb offenen Zustand
void saveCalibrationData();
void loadCalibrationData();
void printCalibrationData();
bool isButtonPressed();
void checkWindowState();
String getWindowState(sensors_event_t *accelEvent, sensors_event_t *magEvent);
float calculateWindowOpenPercentage(sensors_event_t *accelEvent, sensors_event_t *magEvent);
float calculateTiltPercentage(sensors_event_t *accelEvent);


// Variablen für Deep Sleep und Interrupt
unsigned long noMagneticChangeDuration = 0; // Zeit ohne Magnetfeldänderung
const unsigned long noMagneticChangeThreshold = 10000; // 10 Sekunden ohne Änderung, um in Sleep zu gehen
const unsigned long stayAwakeDurationAfterWakeup = 5000; // 5 Sekunden wach bleiben nach dem Aufwachen
const unsigned long outputInterval = 1000; // Zeitintervall zwischen Ausgaben in Millisekunden
unsigned long lastOutputTime = 0;    // Zeitpunkt der letzten Ausgabe
unsigned long wakeupStartTime = 0;   // Zeitpunkt, an dem der ESP aufgewacht ist
const int sda = 21;
const int scl = 22;
const int intPin = 15; // Interrupt-Pin für LSM303

// Magnetfeldänderungsschwellenwert
float magneticThreshold = 5.0;
// Flag, um festzustellen, ob der ESP nach dem Wakeup wach bleiben soll
bool stayAwakeAfterWakeup = false;

unsigned long noMovementDuration = 0;  // Dauer ohne Bewegung
const unsigned long noMovementThreshold = 5000; // Zeit ohne Bewegung (5 Sekunden)
bool movementDetected = false; // Flag für die Bewegungserkennung

// TTN Keys (Little Endian Format)
static const u1_t PROGMEM DEVEUI[8] = { };  // DevEUI
static const u1_t PROGMEM APPEUI[8] = { };  // AppEUI
static const u1_t PROGMEM APPKEY[16] = {}; // AppKey
char mydata[32];  // Speicher für die Nachricht
static osjob_t sendjob;



unsigned long halfOpenStartTime = 0;  // Startzeit des halb offenen Zustands
const unsigned long halfOpenTimeout = 10000;  // Timeout für 10 Sekunden
float previousAccelMovement = 0;
float previousMagMovement = 0;
unsigned long lastMovementCheckTime = 0;
float fluctuationThreshold = 0.05; // 5% fluctuation threshold
float lastAccelY = 0;   // Variable für die vorherige Beschleunigung auf der Y-Achse
bool isTilted = false;  // Zustand "Gekippt" merken

// Pin mapping for the ESP32 (adjust for your setup)
const lmic_pinmap lmic_pins = {
    .nss = 5,       // LoRa Chip Select (NSS)
    .rxtx = LMIC_UNUSED_PIN,
    .rst = 14,      // Reset Pin
    .dio = {26, 33, 32}  // DIO0, DIO1, DIO2
};
// Provide keys to the LMIC library
void os_getArtEui(u1_t *buf) { memcpy_P(buf, APPEUI, 8); }
void os_getDevEui(u1_t *buf) { memcpy_P(buf, DEVEUI, 8); }
void os_getDevKey(u1_t *buf) { memcpy_P(buf, APPKEY, 16); }
bool sendComplete = false; // Flag für abgeschlossene Übertragung
unsigned long lastMovementTime = 0;  // Zeit der letzten Bewegung

// Handle LoRaWAN events
void onEvent(ev_t ev) {
    switch(ev) {
        case EV_TXCOMPLETE:
            Serial.println("LoRa-Übertragung abgeschlossen.");
            if (LMIC.txrxFlags & TXRX_ACK) {
                Serial.println("ACK erhalten.");
            }
            sendComplete = true;  // Übertragung ist abgeschlossen
            break;
        case EV_JOINING:
            Serial.println("Starte LoRaWAN-Join...");
            break;
        case EV_JOINED:
            Serial.println("Erfolgreich bei TTN verbunden!");
            break;
        default:
            Serial.print("Unbekanntes Ereignis: ");
            Serial.println((unsigned)ev);
            break;
    }
}
void do_send(osjob_t *j) {
    if (LMIC.opmode & OP_TXRXPEND) {
        Serial.println(F("OP_TXRXPEND, not sending"));
    } else {
        sensors_event_t accelEvent, magEvent;
        mag.getEvent(&magEvent);
        accel.getEvent(&accelEvent);

        // Bestimme den aktuellen Fensterstatus
        String windowState = getWindowState(&accelEvent, &magEvent);
        uint8_t status = 0;      // 0 = Unbekannt, 1 = Gekippt, 2 = Offen
        uint8_t percentage = 0;  // Prozentwert (0–100)

        if (windowState == "Gekippt") {
            status = 1; // Gekippt
            percentage = static_cast<uint8_t>(calculateTiltPercentage(&accelEvent));
        } else if (windowState == "Offen") {
            status = 2; // Offen
            percentage = static_cast<uint8_t>(calculateWindowOpenPercentage(&accelEvent, &magEvent));
        }

        // Nachricht zusammenstellen (2 Byte)
        uint8_t message[2] = {status, percentage};

        // Nachricht an TTN senden
        LMIC_setTxData2(1, message, sizeof(message), 0);

        // Debug-Ausgabe
        Serial.print(F("Packet queued: Status = "));
        Serial.print(status);
        Serial.print(", Percentage = ");
        Serial.println(percentage);
    }
}


void setup(void) {
    Serial.begin(115200);
    Wire.begin(sda, scl); // I2C Initialisierung
    pinMode(buttonPin, INPUT_PULLUP);
    pinMode(intPin, INPUT);  // Setzt den Interrupt-Pin für den LSM303

     Serial.println(F("Starting LoRaWAN..."));
    os_init();
    LMIC_reset();
    LMIC_startJoining();
    do_send(&sendjob);



    Serial.println("Fensterstatus-Erkennung gestartet.");
    // Sensoren initialisieren
    if (!accel.begin()) {
        Serial.println("Sensorinitialisierung fehlgeschlagen!");
        while (1);
    }
    if (!mag.begin()) {
        Serial.println("Magnetometerinitialisierung fehlgeschlagen!");
        while (1);
    }
    // Kalibrierungswerte laden oder initialisieren
    preferences.begin("calibration", false); // Namespace öffnen
    if (preferences.getBool("calibrated", false)) {
        loadCalibrationData();
        printCalibrationData();
    } else {
        Serial.println("Bitte das Fenster in den *geschlossenen Zustand* bringen.");
        delay(5000);
        calibrateClosedState();
        Serial.println("Bitte das Fenster in den *offenen Zustand* bringen.");
        delay(10000);
        calibrateOpenState();
        Serial.println("Bitte das Fenster in den *gekippten Zustand* bringen.");
        delay(5000);
        calibrateTiltedState();
        Serial.println("Bitte das Fenster in den *halb offenen Zustand* bringen.");
        delay(10000);
        calibrateHalfOpenState();
        saveCalibrationData();
        printCalibrationData();
    }
    // Magnetometer-Register konfigurieren
    lsm.writeMagReg(LSM303::CRA_REG_M, 0x10);        // 15 Hz Output-Datenrate für das Magnetometer
    lsm.writeMagReg(LSM303::MR_REG_M, 0x00);         // Continuous-Conversion-Mode
    lsm.writeMagReg(LSM303::INT_CTRL_M, 0xF8);       // Interrupt auf X, Y und Z aktivieren
    lsm.writeMagReg(LSM303::INT_THS_L_M, 0x20);      // Schwellenwert (Low-Byte, z. B. 0x20 = ~0.25 Gauss)
    lsm.writeMagReg(LSM303::INT_THS_H_M, 0x00);      // Schwellenwert (High-Byte)

    // ESP32 auf externen Interrupt über GPIO12 vorbereiten
    esp_sleep_enable_ext0_wakeup(GPIO_NUM_15, 1); // Interrupt bei steigender Flanke auf GPIO12 (INT LSM303)


    WiFi.mode(WIFI_OFF);    // WiFi deaktivieren, um Strom zu sparen
    btStop();               // Bluetooth deaktivieren
    setCpuFrequencyMhz(80); // CPU-Frequenz reduzieren für geringeren Stromverbrauch

    // Lese aktuelle Magnetometer- und Accelerometerdaten
    sensors_event_t magEvent, accelEvent;
    mag.getEvent(&magEvent);
    accel.getEvent(&accelEvent);

    // Nach dem Wakeup wach bleiben
    stayAwakeAfterWakeup = true;
    wakeupStartTime = millis(); // Speichere die Zeit des Wakeups
}



void loop(void) {

    static String lastWindowState = ""; // Zustand speichern
    static unsigned long lastStatusTime = 0;
    const unsigned long statusRepeatInterval = 2000; // Status alle 2 Sekunden wiederholen
    static unsigned long noMovementDuration = millis();

    os_runloop_once();  // Process LoRaWAN events
    // Button für Kalibrierung überprüfen
    if (isButtonPressed()) {
        Serial.println("Kalibrierung wird zurückgesetzt...");
        delay(5000);
        calibrateClosedState();
        delay(5000);
        calibrateOpenState();
        delay(10000);
        calibrateTiltedState();
        delay(5000);
        calibrateHalfOpenState();
        saveCalibrationData();
        printCalibrationData();
        delay(2000);
    }

    // Nach Wakeup kurze Verzögerung
    if (millis() - wakeupStartTime < 2000) {
        delay(2000);
    }

    // Magnetometer- und Accelerometer-Daten abrufen
    sensors_event_t magEvent;
    mag.getEvent(&magEvent);
    sensors_event_t accelEvent;
    accel.getEvent(&accelEvent);


   // Fensterstatus bestimmen
    String currentWindowState = getWindowState(&accelEvent, &magEvent);
    if (millis() - lastStatusTime > statusRepeatInterval) {
        lastStatusTime = millis();
        if (isTilted) {
            float tiltPercentage = calculateTiltPercentage(&accelEvent);
            Serial.print("Fenster gekippt, Kippwinkel: ");
            Serial.print(tiltPercentage, 1);
            Serial.println("%");
        } else if (currentWindowState == "Offen") {
            float openPercentage = calculateWindowOpenPercentage(&accelEvent, &magEvent);
            Serial.print("Fenster offen: ");
            Serial.print(openPercentage, 1);
            Serial.println("%");
        }
    }

    float accelMovementClosed = sqrt(pow(accelEvent.acceleration.x - closedAccelX, 2) +
                                     pow(accelEvent.acceleration.y - closedAccelY, 2) +
                                     pow(accelEvent.acceleration.z - closedAccelZ, 2));
    float accelMovementOpen = sqrt(pow(accelEvent.acceleration.x - openAccelX, 2) +
                                   pow(accelEvent.acceleration.y - openAccelY, 2) +
                                   pow(accelEvent.acceleration.z - openAccelZ, 2));
    float accelMovementTilted = sqrt(pow(accelEvent.acceleration.x - tiltedAccelX, 2) +
                                     pow(accelEvent.acceleration.y - tiltedAccelY, 2) +
                                     pow(accelEvent.acceleration.z - tiltedAccelZ, 2));
    float accelMovementHalfOpen = sqrt(pow(accelEvent.acceleration.x - halfOpenAccelX, 2) +
                                       pow(accelEvent.acceleration.y - halfOpenAccelY, 2) +
                                       pow(accelEvent.acceleration.z - halfOpenAccelZ, 2));
    // Minimalen Bewegungswert aus allen Zuständen berechnen
    float accelMovement = min(min(accelMovementClosed, accelMovementOpen),
                              min(accelMovementTilted, accelMovementHalfOpen));
    // Analog für Magnetometerdaten
    float magMovementClosed = sqrt(pow(magEvent.magnetic.x - closedMagX, 2) +
                                   pow(magEvent.magnetic.y - closedMagY, 2) +
                                   pow(magEvent.magnetic.z - closedMagZ, 2));
    float magMovementOpen = sqrt(pow(magEvent.magnetic.x - openMagX, 2) +
                                 pow(magEvent.magnetic.y - openMagY, 2) +
                                 pow(magEvent.magnetic.z - openMagZ, 2));
    float magMovementTilted = sqrt(pow(magEvent.magnetic.x - tiltedMagX, 2) +
                                   pow(magEvent.magnetic.y - tiltedMagY, 2) +
                                   pow(magEvent.magnetic.z - tiltedMagZ, 2));
    float magMovementHalfOpen = sqrt(pow(magEvent.magnetic.x - halfOpenMagX, 2) +
                                     pow(magEvent.magnetic.y - halfOpenMagY, 2) +
                                     pow(magEvent.magnetic.z - halfOpenMagZ, 2));
    // Minimalen Bewegungswert aus allen Zuständen berechnen
    float magMovement = min(min(magMovementClosed, magMovementOpen),
                            min(magMovementTilted, magMovementHalfOpen));


        float accelFluctuation = abs(accelMovement - previousAccelMovement) / previousAccelMovement;
        float magFluctuation = abs(magMovement - previousMagMovement) / previousMagMovement;

        // Überprüfe, ob die Fluktuationen größer als der Schwellenwert (5%) sind
        if (sendComplete) {
    // Fluktuationen prüfen, um zu entscheiden, ob Deep Sleep aktiviert wird
    if (accelFluctuation <= fluctuationThreshold && magFluctuation <= fluctuationThreshold) {
        Serial.println("Fensterzustand stabil, Deep Sleep aktivieren.");
        LMIC_shutdown();  // Shutdown LMIC to prevent reinitialization issues
         Serial.println("LMIC SHUTDOWN");
        delay(1000);
        esp_deep_sleep_start(); // Deep Sleep aktivieren
    } else {
        // Wenn Bewegung oder Änderung erkannt wird, speichere die neuen Werte
        previousAccelMovement = accelMovement;
        previousMagMovement = magMovement;
        lastMovementCheckTime = millis();
    }

    // Überprüfen, ob keine Bewegung erkannt wurde und in den Deep Sleep gehen
    if (accelMovement > accelThreshold) {
        noMovementDuration = millis();  // Timer zurücksetzen bei Bewegungserkennung
        movementDetected = true;
    } else {
        movementDetected = false;
    }

    // Keine Bewegung für länger als den Schwellwert -> Deep Sleep
    if (millis() - noMovementDuration > noMovementThreshold) {
        Serial.println("Keine Bewegung erkannt, prüfe Übertragungsstatus...");
        if (sendComplete) {  // Nur in den Deep Sleep gehen, wenn die Übertragung abgeschlossen ist
            Serial.println("Übertragung abgeschlossen, ESP geht in Deep Sleep...");
            LMIC_shutdown();  // Shutdown LMIC to prevent reinitialization issues
            Serial.println("LMIC SHUTDOWN");
            delay(1000);
            esp_deep_sleep_start(); // Deep-Sleep aktivieren
        } else {
            Serial.println("Warte auf abgeschlossene Übertragung...");
        }
    }


        // LoRaWAN Status überprüfen und Daten nur senden, wenn keine Übertragung anhängig ist

        if (!(LMIC.opmode & OP_TXRXPEND) && sendComplete) {
            Serial.println("Sende Daten über LoRa...");
            sendComplete = false;  // Übertragung gestartet
            do_send(&sendjob);     // Send-Job anlegen
        }
    }

}
float calculateWindowOpenPercentage(sensors_event_t *accelEvent, sensors_event_t *magEvent) {
    // Berechne die Differenz im Magnetfeld (Magnetometer)
    float magDiffFromClosed = sqrt(
        pow(magEvent->magnetic.x - closedMagX, 2) +
        pow(magEvent->magnetic.y - closedMagY, 2) +
        pow(magEvent->magnetic.z - closedMagZ, 2)
    );
    float magDiffFromOpen = sqrt(
        pow(magEvent->magnetic.x - openMagX, 2) +
        pow(magEvent->magnetic.y - openMagY, 2) +
        pow(magEvent->magnetic.z - openMagZ, 2)
    );
    // Berechne den Prozentsatz der Fensteröffnung anhand der Magnetometerdaten
    float magPercentage = (magDiffFromClosed / (magDiffFromClosed + magDiffFromOpen)) * 100.0;
    // Begrenze den Prozentsatz zwischen 0 und 100
    magPercentage = constrain(magPercentage, 0, 100);
    return magPercentage; // Prozentsatz der Fensteröffnung
}
float calculateTiltPercentage(sensors_event_t *accelEvent) {
    float currentTiltY = abs(accelEvent->acceleration.y);
    float tiltDiffY = abs(currentTiltY - closedAccelY);
    // Prozentuale Berechnung basierend auf gekipptem Zustand
    float tiltPercentage = (tiltDiffY / abs(tiltedAccelY - closedAccelY)) * 100.0;
    tiltPercentage = constrain(tiltPercentage, 0, 100); // Begrenzen auf 0-100%
    return tiltPercentage;
}

String getWindowState(sensors_event_t *accelEvent, sensors_event_t *magEvent) {
    // Berechne die Änderung auf der Y-Achse (Beschleunigung)
    float accelChangeY = abs(accelEvent->acceleration.y - lastAccelY);
    lastAccelY = accelEvent->acceleration.y;
    // Wenn der Y-Wert sich signifikant ändert, Fenster als "Gekippt" erkennen
    if (accelChangeY > tiltThreshold) {  // Jede Änderung größer als tiltThreshold (z.B. 1.5)
        isTilted = true;  // Zustand "Gekippt" merken
    } else {
        // Wenn der Kippwinkel zurück zu 0% geht (also der Zustand neutral ist), zurücksetzen
        if (isTilted) {
            float tiltPercentage = calculateTiltPercentage(accelEvent);
            if (tiltPercentage < 10) { // Wenn der Kippwinkel fast 0% erreicht, setze den Zustand zurück
                isTilted = false;  // Kippzustand zurücksetzen
            }
        }
    }
    // Wenn das Fenster "Gekippt" ist, geben wir diesen Zustand zurück
    if (isTilted) {
        return "Gekippt";
    } else {
        // Berechne den Öffnungsgrad des Fensters basierend auf dem Magnetometer
        float openPercentage = calculateWindowOpenPercentage(accelEvent, magEvent);
        if (openPercentage > 0) {
            return "Offen";
        }
    }
    return "Unbekannt";
}

void calibrateClosedState() {
    sensors_event_t accelEvent;
    sensors_event_t magEvent;
    accel.getEvent(&accelEvent);
    mag.getEvent(&magEvent);
    closedAccelX = accelEvent.acceleration.x;
    closedAccelY = accelEvent.acceleration.y;
    closedAccelZ = accelEvent.acceleration.z;
    closedMagX = magEvent.magnetic.x;
    closedMagY = magEvent.magnetic.y;
    closedMagZ = magEvent.magnetic.z;
    // Ausgabe der kalibrierten Daten
    Serial.println("Geschlossener Zustand kalibriert:");
    Serial.print("Accel: ");
    Serial.print(closedAccelX); Serial.print(", ");
    Serial.print(closedAccelY); Serial.print(", ");
    Serial.println(closedAccelZ);
    Serial.print("Mag: ");
    Serial.print(closedMagX); Serial.print(", ");
    Serial.print(closedMagY); Serial.print(", ");
    Serial.println(closedMagZ);
}

void calibrateOpenState() {
    sensors_event_t accelEvent;
    sensors_event_t magEvent;
    accel.getEvent(&accelEvent);
    mag.getEvent(&magEvent);
    openAccelX = accelEvent.acceleration.x;
    openAccelY = accelEvent.acceleration.y;
    openAccelZ = accelEvent.acceleration.z;
    openMagX = magEvent.magnetic.x;
    openMagY = magEvent.magnetic.y;
    openMagZ = magEvent.magnetic.z;
    // Ausgabe der kalibrierten Daten
    Serial.println("Offener Zustand kalibriert:");
    Serial.print("Accel: ");
    Serial.print(openAccelX); Serial.print(", ");
    Serial.print(openAccelY); Serial.print(", ");
    Serial.println(openAccelZ);
    Serial.print("Mag: ");
    Serial.print(openMagX); Serial.print(", ");
    Serial.print(openMagY); Serial.print(", ");
    Serial.println(openMagZ);
}

void calibrateTiltedState() {
    sensors_event_t accelEvent;
    sensors_event_t magEvent;
    accel.getEvent(&accelEvent);
    mag.getEvent(&magEvent);
    tiltedAccelX = accelEvent.acceleration.x;
    tiltedAccelY = accelEvent.acceleration.y;
    tiltedAccelZ = accelEvent.acceleration.z;
    tiltedMagX = magEvent.magnetic.x;
    tiltedMagY = magEvent.magnetic.y;
    tiltedMagZ = magEvent.magnetic.z;
    // Ausgabe der kalibrierten Daten
    Serial.println("Gekippter Zustand kalibriert:");
    Serial.print("Accel: ");
    Serial.print(tiltedAccelX); Serial.print(", ");
    Serial.print(tiltedAccelY); Serial.print(", ");
    Serial.println(tiltedAccelZ);
    Serial.print("Mag: ");
    Serial.print(tiltedMagX); Serial.print(", ");
    Serial.print(tiltedMagY); Serial.print(", ");
    Serial.println(tiltedMagZ);
}

void calibrateHalfOpenState() {
    sensors_event_t accelEvent;
    sensors_event_t magEvent;
    accel.getEvent(&accelEvent);
    mag.getEvent(&magEvent);
    halfOpenAccelX = accelEvent.acceleration.x;
    halfOpenAccelY = accelEvent.acceleration.y;
    halfOpenAccelZ = accelEvent.acceleration.z;
    halfOpenMagX = magEvent.magnetic.x;
    halfOpenMagY = magEvent.magnetic.y;
    halfOpenMagZ = magEvent.magnetic.z;
    // Ausgabe der kalibrierten Daten
    Serial.println("Halb-offener Zustand kalibriert:");
    Serial.print("Accel: ");
    Serial.print(halfOpenAccelX); Serial.print(", ");
    Serial.print(halfOpenAccelY); Serial.print(", ");
    Serial.println(halfOpenAccelZ);
    Serial.print("Mag: ");
    Serial.print(halfOpenMagX); Serial.print(", ");
    Serial.print(halfOpenMagY); Serial.print(", ");
    Serial.println(halfOpenMagZ);
}

void saveCalibrationData() {
    preferences.putFloat("closedAccelX", closedAccelX);
    preferences.putFloat("closedAccelY", closedAccelY);
    preferences.putFloat("closedAccelZ", closedAccelZ);
    preferences.putFloat("closedMagX", closedMagX);
    preferences.putFloat("closedMagY", closedMagY);
    preferences.putFloat("closedMagZ", closedMagZ);
    preferences.putFloat("openAccelX", openAccelX);
    preferences.putFloat("openAccelY", openAccelY);
    preferences.putFloat("openAccelZ", openAccelZ);
    preferences.putFloat("openMagX", openMagX);
    preferences.putFloat("openMagY", openMagY);
    preferences.putFloat("openMagZ", openMagZ);
    preferences.putFloat("tiltedAccelX", tiltedAccelX);
    preferences.putFloat("tiltedAccelY", tiltedAccelY);
    preferences.putFloat("tiltedAccelZ", tiltedAccelZ);
    preferences.putFloat("tiltedMagX", tiltedMagX);
    preferences.putFloat("tiltedMagY", tiltedMagY);
    preferences.putFloat("tiltedMagZ", tiltedMagZ);
    preferences.putFloat("halfOpenAccelX", halfOpenAccelX);
    preferences.putFloat("halfOpenAccelY", halfOpenAccelY);
    preferences.putFloat("halfOpenAccelZ", halfOpenAccelZ);
    preferences.putFloat("halfOpenMagX", halfOpenMagX);
    preferences.putFloat("halfOpenMagY", halfOpenMagY);
    preferences.putFloat("halfOpenMagZ", halfOpenMagZ);
    preferences.putBool("calibrated", true);
    preferences.end();
}
void loadCalibrationData() {
    closedAccelX = preferences.getFloat("closedAccelX", 0);
    closedAccelY = preferences.getFloat("closedAccelY", 0);
    closedAccelZ = preferences.getFloat("closedAccelZ", 0);
    closedMagX = preferences.getFloat("closedMagX", 0);
    closedMagY = preferences.getFloat("closedMagY", 0);
    closedMagZ = preferences.getFloat("closedMagZ", 0);
    openAccelX = preferences.getFloat("openAccelX", 0);
    openAccelY = preferences.getFloat("openAccelY", 0);
    openAccelZ = preferences.getFloat("openAccelZ", 0);
    openMagX = preferences.getFloat("openMagX", 0);
    openMagY = preferences.getFloat("openMagY", 0);
    openMagZ = preferences.getFloat("openMagZ", 0);
    tiltedAccelX = preferences.getFloat("tiltedAccelX", 0);
    tiltedAccelY = preferences.getFloat("tiltedAccelY", 0);
    tiltedAccelZ = preferences.getFloat("tiltedAccelZ", 0);
    tiltedMagX = preferences.getFloat("tiltedMagX", 0);
    tiltedMagY = preferences.getFloat("tiltedMagY", 0);
    tiltedMagZ = preferences.getFloat("tiltedMagZ", 0);
    halfOpenAccelX = preferences.getFloat("halfOpenAccelX", 0);
    halfOpenAccelY = preferences.getFloat("halfOpenAccelY", 0);
    halfOpenAccelZ = preferences.getFloat("halfOpenAccelZ", 0);
    halfOpenMagX = preferences.getFloat("halfOpenMagX", 0);
    halfOpenMagY = preferences.getFloat("halfOpenMagY", 0);
    halfOpenMagZ = preferences.getFloat("halfOpenMagZ", 0);
}
void printCalibrationData() {
    Serial.println("Kalibrierungsdaten:");
    Serial.print("Geschlossen: Accel("); Serial.print(closedAccelX); Serial.print(", "); Serial.print(closedAccelY); Serial.print(", "); Serial.print(closedAccelZ); Serial.println(") Mag("); Serial.print(closedMagX); Serial.print(", "); Serial.print(closedMagY); Serial.print(", "); Serial.print(closedMagZ); Serial.println(")");
    Serial.print("Offen: Accel("); Serial.print(openAccelX); Serial.print(", "); Serial.print(openAccelY); Serial.print(", "); Serial.print(openAccelZ); Serial.println(") Mag("); Serial.print(openMagX); Serial.print(", "); Serial.print(openMagY); Serial.print(", "); Serial.print(openMagZ); Serial.println(")");
    Serial.print("Gekippt: Accel("); Serial.print(tiltedAccelX); Serial.print(", "); Serial.print(tiltedAccelY); Serial.print(", "); Serial.print(tiltedAccelZ); Serial.println(") Mag("); Serial.print(tiltedMagX); Serial.print(", "); Serial.print(tiltedMagY); Serial.print(", "); Serial.print(tiltedMagZ); Serial.println(")");
    Serial.print("Halb offen: Accel("); Serial.print(halfOpenAccelX); Serial.print(", "); Serial.print(halfOpenAccelY); Serial.print(", "); Serial.print(halfOpenAccelZ); Serial.println(") Mag("); Serial.print(halfOpenMagX); Serial.print(", "); Serial.print(halfOpenMagY); Serial.print(", "); Serial.print(halfOpenMagZ); Serial.println(")");
}
bool isButtonPressed() {
    bool buttonState = digitalRead(buttonPin) == LOW; // LOW = gedrückt
    if (buttonState && (millis() - lastDebounceTime > debounceDelay)) {
        lastDebounceTime = millis();
        return true;
    }
    return false;
}

I also tried to connect it to a another TTN account or to give shorter messages to TTN but all this stuff didnt work.

Upvotes: 2

Views: 31

Answers (0)

Related Questions