DIY Bewegungsmelder für Garten & EMA (LD2410 + ESP32/MQTT)

Hallo zusammen,

ich bin jetzt seit einigen Wochen dabei, Bewegungsmelder für meinen Garten zu testen. Mein Ziel war nicht nur eine Lampe einzuschalten (das natürlich auch :wink:), sondern die Bewegungen zusätzlich in meine Einbruchmeldeanlage zu integrieren.
Problem dabei: Das Ganze muss zuverlässig sein und darf keine Fehlalarme auslösen.

Meine beste Lösung bisher: eine Kombination aus:

A) Laser-Lichtschranke im Tordurchgang
B) Radarsensor LD2410 zur Erkennung von Bewegungen im definierten Entfernungsbereich als zweite Absicherung
→ Nur wenn beide eine Bewegung melden, wird Alarm ausgelöst.

Funktionsweise

  • LD2410 misst den Abstand und die Bewegungsenergie.
  • Wenn der Wert zwischen Minimum und Maximum liegt und die Energie über einem Schwellwert liegt → Bewegung erkannt.
  • Ein ESP32 sendet das Ergebnis dann per MQTT an den Broker.

Da vielleicht jemand Interesse am Bastelprojekt hat, poste ich hier auch den Arduino-Code.

#include <MyLD2410.h>  // https://iavorvel.github.io/site/MyLD2410/classMyLD2410.html
#include <WiFi.h>
#include <PubSubClient.h>

// Anschlüsse
#define LEDPin 12    // Eine LED für Bewegung erkannt
#define PotiPin1 A0  // Mindestabstand
#define PotiPin2 A3  // Maximalabstand
#define RX_PIN 16
#define TX_PIN 17

// Netzwerk- und MQTT-Broker-Informationen
const char* ssid = "MeinWLAN";
const char* password = "MeinPasswort";
const char* mqtt_server = "192.168.0.102";
const int mqtt_port = 1883;  // Standardport für MQTT
const char* mqtt_user = "";
const char* mqtt_pass = "";

//Radar Objekt "sensor"
HardwareSerial sensorSerial(1);
MyLD2410 sensor(sensorSerial);

// WiFi und MQTT-Client-Objekte
WiFiClient espClient;
PubSubClient client(espClient);

// Variablen
char mqttMessage[50];
int SetWert = 0;  // Globale Variable zum Speichern des empfangenen Werts
uint32_t lastReading = 0;
bool Bewegung=0;
int Mindestabstand;
int Maximalabstand;

void setup(void) {
  Serial.begin(115200);
  sensorSerial.begin(LD2410_BAUD_RATE, SERIAL_8N1, RX_PIN, TX_PIN);

  if (!sensor.begin()) {
    Serial.println("Sensor nicht verbunden!");
    while (true);
  }
  pinMode(LEDPin, OUTPUT);

  // WLAN-Verbindung herstellen
  setup_wifi();

  // MQTT-Server konfigurieren
  client.setServer(mqtt_server, mqtt_port);
  client.setCallback(callback);
}

void setup_wifi() {
  delay(10);
  Serial.println();
  Serial.print("Verbinde mit ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WLAN verbunden");
  Serial.println("IP-Adresse: ");
  Serial.println(WiFi.localIP());
}

void reconnect() {
  // Versuchen, eine Verbindung zum MQTT-Broker herzustellen
  while (!client.connected()) {
    Serial.print("Versuche, eine Verbindung zum MQTT-Broker herzustellen...");
    // Verbindung mit Benutzername und Passwort
    if (client.connect("ESP32Client", mqtt_user, mqtt_pass)) {
      Serial.println("Verbunden");
      // Abonnieren des "Poti/Set" Topics
      if (client.subscribe("Poti/Set")) {
        Serial.println("Erfolgreich für Poti/Set abonniert");
      } else {
        Serial.println("Abonnement fehlgeschlagen");
      }
    } else {
      Serial.print("Fehler, rc=");
      Serial.print(client.state());
      Serial.println(" Versuche es in 5 Sekunden erneut");
      delay(5000);
    }
  }
}

void callback(char* topic, byte* payload, unsigned int length) {
  // Eingehende Nachrichten verarbeiten
  Serial.print("Nachricht angekommen [");
  Serial.print(topic);
  Serial.print("] ");

  // Payload in eine Zeichenkette umwandeln
  char payloadString[length + 1];
  for (int i = 0; i < length; i++) {
    payloadString[i] = (char)payload[i];
  }
  payloadString[length] = '\0';  // Nullterminierung der Zeichenkette

  Serial.println(payloadString);

  // Konvertieren der Zeichenkette in eine Integer-Variable
  SetWert = atoi(payloadString);
  Serial.print("Empfangener Wert als Integer: ");
  Serial.println(SetWert);
}

void loop() {
  if (!client.connected())  reconnect();
  client.loop();

  auto result = sensor.check();

  if (result == MyLD2410::DATA) {
    //Werte lesen
    bool Bewegung = sensor.movingTargetDetected();
    unsigned long Abstand = sensor.movingTargetDistance();
    byte Energie = sensor.movingTargetSignal();

    Mindestabstand = analogRead(PotiPin1)/40;
    Maximalabstand = analogRead(PotiPin2)/10;
    Serial.print("Bewegung LD2410: ");
    Serial.print(Bewegung ? "Ja " : "Nein ");
    Serial.print("Abstand: ");
    Serial.print(Abstand); Serial.print(" cm");
    Serial.print(" | Mindestabstand: ");
    Serial.print(Mindestabstand);
    Serial.print(" | Maximalabstand: ");
    Serial.print(Maximalabstand);

    Serial.print(" | Energie: ");
    Serial.print(Energie); Serial.print(" % ");

    if ((Abstand > Mindestabstand) && (Abstand < Maximalabstand) && (Energie > 60)) {
      Bewegung = true;
      digitalWrite(LEDPin, HIGH);
    }
    else {
      Bewegung = false;
      digitalWrite(LEDPin, LOW);
    }
    Serial.print(" | Bewegung: ");
    Serial.println(Bewegung ? "JA   " : "NEIN ");

    // Werte in das Topic senden
    snprintf(mqttMessage, sizeof(mqttMessage),  Bewegung ? "erkannt" : "keine");
    client.publish("Radar/Bewegung", mqttMessage);
    snprintf(mqttMessage, 50, "%d", Mindestabstand);
    client.publish("Radar/Mindestabstand", mqttMessage);
    snprintf(mqttMessage, 50, "%d", Abstand);
    client.publish("Radar/Abstand", mqttMessage);    
    snprintf(mqttMessage, 50, "%d", Maximalabstand);
    client.publish("Radar/Maximalabstand", mqttMessage);    

  }

  delay(1000);
}
1 „Gefällt mir“

Meine Rückmeldung nach vielen weiteren Wochen Tests:

Ich glaube, ich habe inzwischen den perfekten Bewegungsmelder gebaut.
Zu meiner bisherigen Kombination aus Laser-Lichtschranke im Tordurchgang und dem Radarsensor LD2410 ist jetzt noch ein Lidar-Sensor dazugekommen.

Den Lidar nutze ich ähnlich wie die Lichtschranke: Ich richte den Laserstrahl auf eine gegenüberliegende Wand – verkürzt sich die gemessene Distanz, ist klar, dass etwas dazwischen steht.

Das Entscheidende ist aber die Auswertung:
Es gibt nur dann Alarm, wenn mindestens zwei von drei Sensoren innerhalb einer bestimmten Zeitspanne auslösen.

Dadurch werden die typischen Fehlalarme, die jeder Sensor für sich allein hat, effektiv herausgefiltert:

  • Lidar hatte bei Starkregen mal eine Falschmessung
  • die Laserlichtschranke vermutlich durch Fledermäuse
  • und der Radarsensor … keine Ahnung, aber ab und zu gab es da auch „Geisterbewegungen“

Alle drei Sensoren erkennen Bewegungen sehr zuverlässig – problematisch sind allein die False Positives. Die Mehrfachabsicherung hat das Thema jetzt praktisch eliminiert.

Was bei mir übrigens gar nicht funktioniert hat:

  • PIR-Sensoren (die drei getesteten Varianten waren bei direkter Sonneneinstrahlung völlig unbrauchbar)
  • Kameras mit Personenerkennung – da gab es fast täglich eine falsche Meldung meist auch durch die Fledermäuse. (ich glaube der IR-Strahler lockt Insekten an).
3 „Gefällt mir“

Danke fürs Teilen! Ich habe mehrere Sensoren hier rumliegen um irgendwann mal ein Presence Sensor mit dem @SmartHomeYourself in nem Livestream zu verbauen. Der wäre zwar Indoor, ich finde aber die Idee gut, mehrere Sensoren zu kombinieren. Ggf geht ein PIR Indoor zuverlässiger für ne schnelle Reaktion und dann MMWave für die statische Erkennung.

Warum hast du alles in Arduino gemacht und nicht mit ESPHome?

Warum nicht in esphome?

  • esphome kann keinen TF-Luna über I2C einbinden.

  • C-Code ist für mich leichter verständlich (ich bin schon zu alt für den ganzen modernen „Sprachen“)

  • ESP-Home hat auch keine Vorteile denke ich. Selbst Over-the-Air geht mit Arduino problemlos (Habs nur nicht gebraucht weil ich sowieso im Garten über USB programmiert habe)

Ich kann am Wochenende aber mal versuchen das in ESPhome umzusetzen und auch zu dokumentieren.
Allerdings ist das Ganze nicht gut zum Nachbauen geeignet. Man muss viel an die Örtlichkeiten anpassen.

1 „Gefällt mir“