JsonMod als TCP Service?

Begonnen von Adimarantis, 25 November 2024, 16:24:22

Vorheriges Thema - Nächstes Thema

Adimarantis

Hallo,

Ich habe die Idee meine Videokamera als verbesserten Bewegungsmelder zu nutzen. Die kann Menschen erkennen und dann ein Datenpaket (Alarm) an einen TCP Port schicken. Das ist etwas weniger willkürlich als normale Bewegungsmelder (meine Lampe geht aktuell bei jedem Auto dass vorbeifährt an).

Mit einem primitiven Pythonscript, dass ein listen() auf einen Socket macht und die Daten einfach ausgibt, bekomme ich sowas:

Connected to client IP: ('192.168.1.167', 60567)
Received data: b'\xff\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe4\x05\xc0\x00\x00\x00{ "Address" '
Received data: b': "0xA701A8C0", "Channel" : 0, "'
Received data: b'Descrip" : "", "Event" : "HumanD'
Received data: b'etect", "SerialID" : "62d0233832'
Received data: b'c19556", "StartTime" : "2024-11-'
Received data: b'25 15:51:55", "Status" : "Stop",'
Received data: b' "Type" : "Alarm" }\n'
Received data: b''

Also im Prinzip ein JSON mit ein paar binären Headerdaten am Anfang.
Die grundsätzliche Funktionalität sollte JSONMod können, nur nach meinem Verständnis macht das immer einen HTTP Request.
Hier brauche ich das andersrum: JSONMod müsste auf einem bestimmten Port auf Daten warten und diese dann entschlüsseln.
Außerdem muss es in der Lage sein den binären Müll am Anfang zu überlesen.

Gibt es da schon irgendwas und ich habs nur nicht gefunden?
Wäre es interessant JSONMod entsprechend zu erweitern? (Ich hab mir den Code noch nicht angeschaut, aber evtl. könnte ich da was beitragen)

Der Plan wäre dann den Bewegungsmelder stillzulegen (fest auf an), eine Zigbee Glübirne rein und mit der bereits vorhandenen Kamera das Licht einzuschalten, wenn jemand vor der Tür steht.

Jörg
Raspberry 4 + HM-MOD-RPI-PCB (pivCCU) + RfxTrx433XL + 2xRaspberry 1
Module: 50_Signalbot, 52_I2C_ADS1x1x , 58_RPI_1Wire, (50_SPI_MAX31865)

betateilchen

Wenn Du doch eh schon ein (externes) Skript hast, warum kannst Du dann nicht einfach das Licht aus dem Skript heraus einschalten (set Befehl an FHEM schicken oder HTTPAPI nutzen) oder einfach ein Trigger an FHEM schicken? Wozu brauchst Du da unbedingt noch JsonMod?
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

Adimarantis

#2
Zum einen hab ich bisher nur ein dummes "höre auf einen Port und schreibe alles raus was kommt" Script, das lediglich als PoC gedacht war um rauszufinden, was die Kamera überhaupt ausspuckt, zum anderen mag ich einfach generische integrierte Lösungen.

Hab jetzt ein wenig rumgebastelt und es ist tatsächlich nicht so schwer JsonMod in einen Servermodus zu bringen. Ich hab jetzt nur ein Verständnisproblem mit den TcpServerUtils.

Solange ich mich mit telnet interaktiv auf den Port verbinde und mein JSON eintippe/paste und telnet interaktiv beende klappt es schon recht schön.
Wenn ich aber sowas mache:
echo '{ "Key1": "Value1", "Key2": "Value2" }\n' | telnet localhost 15002wird die Verbindung irgendwie schneller beendet als ich die Daten lesen kann.
D.h. meine "read" Funktion im Modul wird zwar aufgerufen, aber ein sysread liefert 0 Bytes.
Ich hab auch schon ein sleep(1) probiert und dann nochmal gelesen - sind einfach keine Daten mehr da.

Kann man den Socket/TcpServerUtils irgendwie so einstellen, dass ich meine Daten noch bekomme?

Edit: Ich glaube mein Fehler war zu glaube, dass man den telnet Befehl per pipe befüllen kann. Gerade die Kamera mit meinem Prototyp verbunden und es klappt!
Ich werde den Code noch ein bisschen aufräumen, dann poste ich den hier mal
Raspberry 4 + HM-MOD-RPI-PCB (pivCCU) + RfxTrx433XL + 2xRaspberry 1
Module: 50_Signalbot, 52_I2C_ADS1x1x , 58_RPI_1Wire, (50_SPI_MAX31865)

xenos1984

Mit netcat statt telnet sollten die Daten komplett ankommen:

echo '{ "Key1": "Value1", "Key2": "Value2" }\n' | nc -N localhost 15002

Adimarantis

Danke für den Tipp - mit netcat klappt es tatsächlich. Das ist hilfreich für weitere Tests.
Raspberry 4 + HM-MOD-RPI-PCB (pivCCU) + RfxTrx433XL + 2xRaspberry 1
Module: 50_Signalbot, 52_I2C_ADS1x1x , 58_RPI_1Wire, (50_SPI_MAX31865)

Adimarantis

Und hier wie versprochen meine Modifikation.

Mit der Syntax
define <name> JsonMod <port> [global]versetzt man das Modul in den Server Mode.

Eingehende Nachrichten werden als JSON ausgewertet und entsprechend der üblichen Regeln des Moduls in Readings geschrieben. Dabei wird alles was vor und nach den geschweiften Klammern steht ignoriert - also 'trash { "key": "value" } trash' funktioniert trotzdem.

Vielleicht kann es ja jemand brauchen - oder der Autor des Modul möchte die Änderung übernehmen.

Raspberry 4 + HM-MOD-RPI-PCB (pivCCU) + RfxTrx433XL + 2xRaspberry 1
Module: 50_Signalbot, 52_I2C_ADS1x1x , 58_RPI_1Wire, (50_SPI_MAX31865)

Adimarantis

Vielleicht noch ein Nachtrag zu den Nutzungmöglichkeiten:
Ich habe mehrere verschiedene IP Cameras aus China, die alle die Möglichkeit haben die Benachrichtigung an einen "Alarm Server" einzurichten. Ich vermute daher, das dies ein "Pseudo Standard" ist.
Trägt man dort die IP seines FHEM Servers ein (Port ist üblicherweise 15002, kann man so lassen), dann braucht man nur das modifizierte Modul mit dem Argument "15002 global" zu definieren und am Besten erstmal das Attribut "readingList" auf "complete()" setzen, dann empfängt man alle möglichen Alarme - siehe Bild (was um 3:51 Uhr nachts wohl ein "false positive" war  :) )

Kann man z.B. auch nutzen um sich auf die Schnelle einen Snapshot zu holen und sich den per Messenger auf Handy zu senden.

Raspberry 4 + HM-MOD-RPI-PCB (pivCCU) + RfxTrx433XL + 2xRaspberry 1
Module: 50_Signalbot, 52_I2C_ADS1x1x , 58_RPI_1Wire, (50_SPI_MAX31865)

betateilchen

Die Idee an sich finde ich ja gut.

Aber was mir nicht gefällt, ist das hier:

Zitat von: Adimarantis am 26 November 2024, 13:59:21Dabei wird alles was vor und nach den geschweiften Klammern steht ignoriert - also 'trash { "key": "value" } trash' funktioniert trotzdem.

Damit hätten wir zum ersten Mal die Situation, dass ein an sich nicht korrekter json-Input trotzdem automatisch zur Verarbeitung angenommen wird. Im Moment zweifle ich etwas daran, dass dieses Verhalten gut und sicher ist.
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

Adimarantis

Leider kann ich die Firmware an der Quelle nicht ändern, somit muss ich dort filtern wo ich es kann.
Das Verhalten könnte man evtl. optional machen oder fest definieren wieviele Bytes er überlesen soll.

Es wird ja außerdem trotzdem nur korrekter JSON Input akzeptiert - innerhalb der Klammern.
Spontan fällt mir nicht ein warum das Ignorieren von Informationen die davor oder dahinter stehen unsicher sein soll.
Hast du ein Beispiel?
Raspberry 4 + HM-MOD-RPI-PCB (pivCCU) + RfxTrx433XL + 2xRaspberry 1
Module: 50_Signalbot, 52_I2C_ADS1x1x , 58_RPI_1Wire, (50_SPI_MAX31865)

betateilchen

Zitat von: Adimarantis am 27 November 2024, 11:30:39Es wird ja außerdem trotzdem nur korrekter JSON Input akzeptiert - innerhalb der Klammern.

Hast Du mal überlegt, was in Deiner "Fehlerbehandlung" passiert, wenn

{'trash'} { "key": "value" } {'trash'}

ankommt?
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

Adimarantis

Das wird als fehlerhaft erkannt - das hat aber gar nichts damit zu tun, dass ich "Müll" abschneide, denn dein Beispiel hat ja vorne und hinten eine geschweifte Klammer und wird vollständig an die JSON Routine vom Originalmodul übergeben.

Richtig ist, das jedgliche Fehlerbehandlung bisher fehlt.
Ich schreibe die Fehlermeldung jetzt ins "state" und update die Readings nur wenn das soweit ok ist.
Inwieweit die Originalroutinen fehlerhafte Eingaben korrekt abfangen, habe ich mir nicht angeschaut. Das wäre aber dann bei einem http-request das selbe Problem. Dein Beispiel liefert zumindest jetzt
Malformed JSON: Expected string while parsing object at line 1, offset 1 at ./FHEM/98_JsonMod.pm line 1079.Die Angabe der Zeilennummer finde ich jetzt etwas zuviel, aber das kommt aus dem Originalcode.
Raspberry 4 + HM-MOD-RPI-PCB (pivCCU) + RfxTrx433XL + 2xRaspberry 1
Module: 50_Signalbot, 52_I2C_ADS1x1x , 58_RPI_1Wire, (50_SPI_MAX31865)