Rauchmelder mit RTL433

Allgemeine Fragen rund um die "Smart Home" Hardware/Komponenten

Moderatoren: seppy, udo1toni

Antworten
klaus1
Beiträge: 95
Registriert: 11. Jan 2022 13:48
Answers: 0

Rauchmelder mit RTL433

Beitrag von klaus1 »

Hi,

ich verwende das RTL433 Projekt am Raspberypi und kann meine Rauchmelder per GenericMQTTBroker auslesen in Openhab.
Die Rauchmelder senden nur im Alarmfall folgendes (Mosquitto auszug):

rtl_433/raspberrypi/events {"time":"2024-04-25 14:51:29","model":"Smoke-GS558","id":494,"unit":0,"learn":0,"code":"c03dc0"}
rtl_433/raspberrypi/devices/Smoke-GS558/494/time 2024-04-25 14:51:29
rtl_433/raspberrypi/devices/Smoke-GS558/494/id 494
rtl_433/raspberrypi/devices/Smoke-GS558/494/unit 0
rtl_433/raspberrypi/devices/Smoke-GS558/494/learn 0
rtl_433/raspberrypi/devices/Smoke-GS558/494/code c03dc0

Unterschiedlich sind hier die IDs je Gerät. Ich verwende übrigens Visor Tech RWM-460f.

Meine Frage: wie kann ich sinnvoll einen Alarm auswerten.
Ich habe einen MQTT Broker angelegt, und darauf ein Generic MQTT Thing.

Mein Versuch:
MQTT State Topic:
rtl_433/raspberrypi/devices/Smoke-GS558/

Wie kann ich jetzt die ID dahinter auswerten in einem Item oder die Time damit ich die letzte Meldung speichern könnte wann welcher Melder ausgelöst hat ? Beispiel: /494 ? Ich bräuchte konkret in einer Rule dann die ID und vermutlich innerhalb einer Zeitspanne von 60min meinen telegramAction.sendTelegram aufruf. (da im Brandfall der Melder alle 5sec sendet, soll nur 1x innerhalb 60min die Rule greifen).
Ich würde gerne die unterschiedlichen ID's abprüfen um die Räume mitzusenden.

oder wäre besser je Raum ein Item?
rtl_433/raspberrypi/devices/Smoke-GS558/494/time verwenden und ein ITem je Raum zu erstellen mit String auswertung.
Ist aber vielleicht nicht schön, weil ich dann je Raum ein Item benötige.
danke,
Klaus

Benutzeravatar
udo1toni
Beiträge: 14001
Registriert: 11. Apr 2018 18:05
Answers: 222
Wohnort: Darmstadt

Re: Rauchmelder mit RTL433

Beitrag von udo1toni »

Grundsätzlich gibt es verschiedene Herangehensweisen.
Möglichkeit 1: Du wertest das Topic rtl_433/raspberrypi/events aus. Dieses liefert Dir ein JSON Objekt, aus dem die ID auslesbar ist.
Den Channel kannst Du als String Channel definieren und anschließend mit einem String Item verlinken.
Das String Item kannst Du einer Rule zuführen, welche die eigentliche Auswertung übernimmt, z.B.

Code: Alles auswählen

import java.util.HashMap

rule "RTL433 Alarm auswerten"
when 
    Item RTL433JSON changed
then
    if(!(newState.toString.contains("{"))) {
        logInfo("rtl433","RTL433 liefert kein JSON ({}) Abbruch.",newState)
        return;
    }
    if(!(newState.toString.contains("Smoke"))) {
        logInfo("rtl433","JSON enthält keinen Rauchmelder ({}) Abbruch.",newState)
        return;
    }
    val HashMap hmSmoke = newHashMap( "494" -> "Wohnzimmer",   // zum Beispiel...
                                      "498" -> "Schlafzimmer",
                                      "47"  -> "Flur"
    )
    val nId = transform("JSONPATH","$.id",newState)
    val strRaum = hmSmoke.get(nId)
    logWarn("rtl433","WARNUNG! Alarmmeldung durch id {} ({})",nId,strRaum)
    // whatever sonst noch...
end
Die Rule prüft, ob ein JSON vorliegt (nun ja... also, ob überhaupt, annähernd, etwas wie JSON drin sein könnte...)
Anschließend prüft sie, ob der Teilstring Smoke vorkommt. Ist das nicht der Fall, kam das Event von etwas anderem :)
In der HashMap hmSmoke stellst Du eine Verknüpfung zwischen IDs und Klartextnamen her. Anschließend liest die Rule die ID mittels JSONPATH aus dem JSON Objekt aus und ermittelt anhand der HashMap den Klartextnamen. (Es versteht sich von selbst, dass hierfür die JSONPATH Transformation installiert sein muss).

Natürlich kannst Du auch für jede ID ein eigenes Topic mit eigenem Item anlegen, jedoch musst Du immer das vollständige Topic angeben. Und dann wäre die Frage, was Du zur Anzeige bringen willst (evtl. am sinnvollsten der Zeitstempel als DateTime Item). Gerade bei solchen Alarmfunktionen ist aber eine Sammeladresse sicherlich sinnvoller. Den Zeitstempel kannst Du auch innerhalb der obigen Rule ermitteln, Du musst nur den JSONPath entsprechend anpassen. Mutmaßlich musst Du aber den Zeitstempel parsen lassen, weil er sich nicht an das vorgegebene Format hält :) das wäre aber auch in separaten Items der Fall. die einfachste Lösung wäre hier, die aktuelle Zeit zu verwenden, die liegt ja ohnehin vor und sollte weitgehend mit dem Zeitstempel im JSON Objekt übereinstimmen.

Eine (schlechte) Möglichkeit wäre noch, alle IDs jeweils gemeinsam abzufragen, z.B. mit dem Topic rtl_433/raspberrypi/devices/Smoke-GS558/+/id, welches dann die ID im Klartext liefert, also z.B. 494. Das + bedeutet, dass dieses Level im Topic unbeachtet bleibt (im dem Sinne, dass egal ist, was da steht... das Level muss aber vorhanden sein). Schlecht ist diese Lösung deshalb, weil Du, wenn Du nun die anderen Untertopics auf die gleiche Weise einsammelst (also z.B. time und code) keine Möglichkeit hast, sicherzustellen, dass die empfangenden Topics auch wirklich zueinander gehören, denn was an der Stelle des + steht, ist ja egal.
Im Gegensatz dazu hast Du bei der Rule oben immer die Gewissheit, dass alle Einträge des JSON Objekts zu einem "Datensatz" gehören, also die selbe Meldung betreffen.
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.2.2, LXC), mit openHABian eingerichtet

klaus1
Beiträge: 95
Registriert: 11. Jan 2022 13:48
Answers: 0

Re: Rauchmelder mit RTL433

Beitrag von klaus1 »

danke gefällt mir super deine Lösung.
ich komme allerdings nicht über diese Zeile (transform("JSONPATH".....):

Code: Alles auswählen

rule "Brandmelder"
when
    Item Generic_MQTT_Thing_RTL433_JSON_ARRAY changed
then
    if(newState.toString.contains("Smoke")){
        val HashMap hmSmoke = newHashMap( "873" -> "Wohnzimmer",   // zum Beispiel...
                                      "30887" -> "Schlafzimmer",
                                      "47"  -> "Flur")
        logWarn("rtl433","NewState: {}",newState)
        val nId = transform("JSONPATH","$.id",newState)
        logWarn("rtl433","nId: {}",nId)

Ausgabe:

Code: Alles auswählen

2024-04-25 19:05:27.336 [WARN ] [org.openhab.core.model.script.rtl433] - NewState: {"time":"2024-04-25 19:05:26","model":"Smoke-GS558","id":30887,"unit":28,"learn":0,"code":"cf14fc"}
2024-04-25 19:05:27.338 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'brandmelder-1' failed: An error occurred during the script execution: Could not invoke method: org.openhab.core.model.script.actions.Transformation.transform(java.lang.String,java.lang.String,java.lang.String) on instance: null in brandmelder
Ich habe unter Einstellungen
JSONPath Transformation installiert:
Information
Source
openHAB Distribution
Provided By
openHAB
checkmark_seal_fill
Version
4.1.2
Type
transformation
Content Type
Karaf Feature
Provisioned With
Karaf

klaus1
Beiträge: 95
Registriert: 11. Jan 2022 13:48
Answers: 0

Re: Rauchmelder mit RTL433

Beitrag von klaus1 »

habs schon. transform( ) benötigt 3 Strings, daher der dritte Paramter nur mit .toString möglich. - Danke

Benutzeravatar
udo1toni
Beiträge: 14001
Registriert: 11. Apr 2018 18:05
Answers: 222
Wohnort: Darmstadt

Re: Rauchmelder mit RTL433

Beitrag von udo1toni »

Ja, eigentlich sollte openHAB so schlau sein und selbst ein .toString ausführen... Prima, dass Du es selbst lösen konntest!
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.2.2, LXC), mit openHABian eingerichtet

klaus1
Beiträge: 95
Registriert: 11. Jan 2022 13:48
Answers: 0

Re: Rauchmelder mit RTL433

Beitrag von klaus1 »

danke für die hilfe!
jetzt wäre noch wichtig, das ich nicht mit Telegram und Alexa nachrichten geflutet werde.
Darum mein Versuch: Innerhalb von 10min nur einmal je ID das ganze zu bekommen. Ich versuche es über eine Map (lastAlertTime), die ID und Zeit beinhaltet.

Code: Alles auswählen

import org.joda.time.DateTime
import java.util.HashMap

//var lastAlertTime = now.minusMinutes(15)  // set the lastAlertTime to 15 minutes ago so we get alerts immediately
var HashMap<String, DateTime> lastAlertTime = new HashMap()

rule "Brandmelder"
when
    Item Generic_MQTT_Thing_RTL433_JSON_ARRAY changed
then
    //if(newState.toString.contains("Smoke")){
    if(newState.toString.contains("Prologue-TH")){        
        val HashMap<String, String> hmSmoke = newHashMap( "873" -> "Wohnzimmer",   // zum Beispiel...
                                      "30887" -> "Schlafzimmer",
                                      "47"  -> "Flur",
                                      "3" -> "PoolSensor")
        val nId = transform("JSONPATH","$.id",newState.toString)
        val strRaum = hmSmoke.get(nId)
        logWarn("rtl433","nid: ",nId)
        if((lastAlertTime.get(nId)) == null){
            lastAlertTime.put(nId,now.minusMinutes(15))
        }
        if(now.minusMinutes(10).isAfter(lastAlertTime.get(nId))) {
            val telegramAction = getActions("telegram","telegram:telegramBot:xxxx")
            telegramAction.sendTelegram("ALARM: Brandmelder mit ID "+nId+" ("+strRaum+") hat ausgelöst.")
            AlexaTextToSpeechVolume.postUpdate(10)
            AlexaTextToSpeech.sendCommand("Alarm! - Brandmelder Wohnzimmer hat angeschlagen.")        
            logWarn("rtl433","ALARM: Brandmeldung mit ID {} ({}) hat ausgelöst.",nId,strRaum)
                
            lastAlertTime.put(nId,now) // Setze die letzte Alarmzeit auf die aktuelle Zeit, da eine Änderung stattgefunden hat
        }
    }
end
leider merkwürdiger fehler ohne zeilenangabe:

Code: Alles auswählen

2024-04-25 21:27:40.517 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'brandmelder-1' failed: Unknown variable or command '=='; line 20, column 12, length 32 in brandmelder
danke

klaus1
Beiträge: 95
Registriert: 11. Jan 2022 13:48
Answers: 0

Re: Rauchmelder mit RTL433

Beitrag von klaus1 »

ok mit ZoneDateTime und === statt == Vergleich klappts. ;-)

Benutzeravatar
udo1toni
Beiträge: 14001
Registriert: 11. Apr 2018 18:05
Answers: 222
Wohnort: Darmstadt

Re: Rauchmelder mit RTL433

Beitrag von udo1toni »

Du hast oben geschrieben:
klaus1 hat geschrieben: 25. Apr 2024 15:03 Die Rauchmelder senden nur im Alarmfall
Ich hoffe doch sehr, dass Dein Haus nicht regulär in Brand steht...

Eventuell gibt der Code ja noch weitere Auskünfte.

Ansonsten noch ein Hinweis bezüglich der Definition von HashMaps: Da es sich bei HashMaps nicht um gewöhnliche Variablen handelt, kannst Du HashMaps tatsächlich immer als val anlegen. Es handelt sich um einen fixen (also unveränderlichen) Zeiger auf einen Speicherbereich. Lese- und Schreibzugriffe erfolgen auf den Speicherbereich (per get/put), nicht auf den Zeiger selbst.

In der Zeile für AlexaTextToSpeech solltest Du noch den fixen Text "Wohnzimmer" durch den Inhalt von strRaum ersetzen :)
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.2.2, LXC), mit openHABian eingerichtet

Antworten