Bash => Zerlegen der Daten aus dem Status

  • Hallo,

    ich bastel gerade an einem Bash-Script.

    Mit einer curl-Abfrage:

    Code
    test=$(curl --silent 'http://192.168.0.128/cm?cmnd=Status%205')

    bekomme ich folgende Daten in die Variabel:

    Code
    {"StatusNET":{"Hostname":"tasmota-128","IPAddress":"192.168.0.128","Gateway":"192.168.0.10","Subnetmask":"255.255.255.0","DNSServer":"192.168.0.4","Mac":"xx:xx:xx:xx:xx:xx","Webserver":2,"WifiConfig":4}}

    Ich möchte nun einzelne Daten daraus sicher extrahieren. Bisher habe ich nur die cut-Funktion dafür gefunden:

    Code
    echo $test  | cut -d\" -f10

    So springe ich an die 10. Stelle der Anführungsstriche.

    Ergebnis:

    Code
    192.168.0.128

    Das funktioniert zwar, befriedigt mich aber nicht wirklich. Wenn nämlich irgendwann durch neue weitere Werte sich die Reihenfolge ändert, bekomme ich falsche Ausgaben.

    Hat jemand einen Tipp für mich, wie ich das eleganter handhaben kann?

    Meine Hardware@home: Fritzbox 7590AX, 15xTasmota-Geräte, Syno NAS, Raspberry Pi 4 f. PiHole, ioBroker, Docker, TasmoAdmin, Portainer

    Einmal editiert, zuletzt von Marc (5. April 2020 um 19:18)

  • Ich glaube, dass ich mein Problem gerade selber gelöst habe.

    In einem anderen Thread habe ich einen Hinweis auf "jq" gefunden.

    Hier der Link für die Nachwelt:

    https://wiki.ubuntuusers.de/jq/

    Beispiel:

    Wenn man den Status 10 (StatusSNS) in eine Variable ($test) gespeichert hat, kann man ganz bequem über Pipe einen Wert herauslesen:

    Code
      echo $test | jq ".StatusSNS.ENERGY.TotalStartTime"

    Meine Hardware@home: Fritzbox 7590AX, 15xTasmota-Geräte, Syno NAS, Raspberry Pi 4 f. PiHole, ioBroker, Docker, TasmoAdmin, Portainer

  • alternativ ist das zurückgegebene json doch ein Array.

    Code
    {"StatusNET":{"Hostname":"tasmota-128","IPAddress":"192.168.0.128","Gateway":"192.168.0.10","Subnetmask":"255.255.255.0","DNSServer":"192.168.0.4","Mac":"xx:xx:xx:xx:xx:xx","Webserver":2,"WifiConfig":4}}

    Ich weiß zwar jetzt nicht wie Curl das so anstellt, aber mit praktisch jeder Programmierspache kann man doch einzelne Elemente eines Array direkt auslesen....

    weiß zwar nicht genau was du vorhast, aber bei php würde das dann so aussehen

    Code
    echo $json['StatusNET']['Hostname']

    falls curl sowas in der Art kann, wäre es die 'saubere' Variante

    --- Signaturen werden völlig überbewertet --- X/

  • Lösung lag doch ganz nah

    ... den wunderbaren Thread hatte ich nicht gesehen. Der hätte mich sofort um Meilen nach vorne katapultiert. ;)

    alternativ ist das zurückgegebene json doch ein Array

    Ich habe jetzt ein wenig gesucht, aber auch nur Lösungen mit jq gefunden. Auch 2-3 Versuche die Inhalte wie aus einem Array abzugreifen, schlugen fehl.

    Aber das ist ok. jq funktioniert einwandfrei.

    Ich greife so nur noch 1x auf die Statusmeldungen der Tasmotasteckdose zu, speichere die Ausgabe in Variablen und mit jq kann ich dann einzelne Werte zielsicher aufrufen.

    Meine Hardware@home: Fritzbox 7590AX, 15xTasmota-Geräte, Syno NAS, Raspberry Pi 4 f. PiHole, ioBroker, Docker, TasmoAdmin, Portainer

  • Ich erstelle gerade ein Script, welches das eigene Netzwerk (bzw. einen Bereich davon) auf Tasmota-Geräte scannt, die Verbrauchsdaten dieser Geräte täglich erfasst, speichert, aufarbeitet, für verschiedene Zeitbereiche den Stromverbrauch angibt und pro Gerät und Gesamt die Kosten pro Jahr errechnet. Die Ausgabe erfolgt einerseits übersichtlich auf der Konsole, sowie wird eine HTML-Seite angelegt.

    Ich bin zu 70% fertig. Im Moment folgen noch ein paar kleine Extras und der Feinschliff.

    Meine Hardware@home: Fritzbox 7590AX, 15xTasmota-Geräte, Syno NAS, Raspberry Pi 4 f. PiHole, ioBroker, Docker, TasmoAdmin, Portainer

  • Klingt interessant (auch wenn ich selbst keine Geräte habe, die den Verbrauch messen)

    womit programmierst du? worauf soll das später laufen?

    Hast du ne Datenbank als Backend oder summierst du nur irgendwie auf?

    --- Signaturen werden völlig überbewertet --- X/

    Einmal editiert, zuletzt von Supermicha (16. April 2020 um 18:45)

  • Ich bin ja absoluter Bash-Anfänger, also bitte keine großen Sprünge erwarten. :S;)

    Im Moment habe ich den Teil fertig, wo das Netzwerk in einem vorgegebenem Bereich gescannt wird, alle Geräte die antworten erfasst werden, dann auf Tamota geprüft wird und ob schon Daten vorliegen.

    Beim Speichern der Daten ist das noch sehr rudimentär, aber es funktioniert:

    Im Moment werden die Daten (Yesterday) einmal täglich erfasst und in Textdateien (IP .132 => strom_132_1tag.txt u. strom_132_0gesamt.txt) abgespeichert. Am 1. des Monats werden die Werte vom Vormonat zusammengerechnet, in einer Textdatei (strom_132_2monat.txt) abgelegt und die Textdatei mit den Tageswerten geleert. Das Gleiche passiert am 1.1. des Jahres (strom_132_3jahr2019.txt). Aus dieser Datenbasis (strom_132_0gesamt.txt) berechnet das Script die Verbräuche über die verschiedenen Zeitbereiche (7, 30, 90, 180, 365 und 730 Tage).

    Im Moment betreibe ich Leichenfledderei, sprich das Script V1 und Script V2 verarbeite ich gerade zu Script V3. Es wuchs mir da etwas über den Kopf, das macht V3 leider gerade auch schon wieder. Ich habe drei Bildschirme, könnte aber noch mal drei gebrauchen... :/8o^^

    Eine Baustelle, die ich bisher nicht lösen konnte: jq

    Ich kann damit problemlos aus den Statusmeldungen (JSON) von Tasmota einzelne Werte auslesen. Das klappt wunderbar und zuverlässig.

    Was ich mir für eine Debug-Funktion wünschen würde, wäre ein automatisches Verarbeiten eines beliebigen JSON-Strings (wegen Status1, Status2, Status3, usw.) und einer daraus resultierenden Anzeige, z.B. auf der Konsole oder ein Weiterverarbeiten für eine HTML-Datei. Eigentlich hatte ich erwartet, dass da schon irgendwo ein Script für jq rumschwirrt, aber bisher bin ich nicht fündig geworden. Die Debug-Funktion mit einer übersichtlichen Anzeige aller Werte für ein Gerät ist zwar nicht wichtig, wäre aber bestimmt ein gutes Gimmick um Problemen schnell auf die Spur zu kommen.

    Meine Hardware@home: Fritzbox 7590AX, 15xTasmota-Geräte, Syno NAS, Raspberry Pi 4 f. PiHole, ioBroker, Docker, TasmoAdmin, Portainer

    2 Mal editiert, zuletzt von Marc (17. April 2020 um 13:40)

  • Da Bilder immer mehr sagen wie tausend Worte, habe ich drei Screenshots angefertigt.

    Ausgabe auf der Konsole:

    Die Ausgabe auf der Konsole funktioniert bisher sehr gut. Wenn jemand Geräte mit einem Verbrauch von mehr als 9.999 pro Tag hat, würde sich die Anzeige in der Reihe um ein Zeichen verschieben und somit das klare Bild etwas zerstören.

    Ausgabe HTML:

    Bei manchen Geräten sind noch nicht genug Datensätze vorhanden und so hinkt dort (noch) etwas die Gesamtberechnung.

    Bei der Ausgabe in HTML fehlt mir auch noch ein sehr einfaches responsives HTML-Template, welches sich jeweils auf dem PC, Tablet und Smartphone anpasst. Das Problem sind halt die Anzahl der Spalten. Die meisten Templates gehen damit nicht richtig um. Da überlege ich schon nur die Verbrauchswerte anzuzeigen um Spalten zu "sparen" und darunter in einer zweiten Tabelle noch mal weitere Eckdaten wie Hostname, IP, RSSI, Spannung anzugeben.

    Ausgabe Debugmodus (frühe V1):

    Meine Hardware@home: Fritzbox 7590AX, 15xTasmota-Geräte, Syno NAS, Raspberry Pi 4 f. PiHole, ioBroker, Docker, TasmoAdmin, Portainer

    3 Mal editiert, zuletzt von Marc (17. April 2020 um 13:31)

  • Was ich mir für eine Debug-Funktion wünschen würde, wäre ein Verarbeiten eines beliebigen JSON-Strings (wegen Status1, Status2, Status3, usw.) und einer daraus resultierenden Anzeige, z.B. auf der Konsole oder ein Weiterverarbeiten für eine HTML-Datei.

    Deshalb arbeite ich aktuell auch mehr mit Python, weil dort die Interpretation von JSON als Standardbibliothek zur Verfügung steht. Das bedeutet NICHT, das man jeden beliebigen JSON-String "out-of-the-box" dargestellt bekommt, aber er wird in eine Struktur aus Dictionaries und Listen überführt (das sind zwei Listentypen, die in anderen Programmiersprachen auch (assoziative) Arrays genannt werden), für die es vordefinierte Funktionen und Methoden zum Auslesen von Schlüssel:Wert-Paaren gibt bzw. für Strukturen wie Schlüssel:{Schlüssel1a:Wert_1a, Schlüssel1b:Wert_1b,...}. Mit bash allein ist das sicher komplizierter, aber wahrscheinlich nicht unmöglich. Aber auch unter Python ist es wichtig, dass man vorher weiß, welche Struktur ein JSON-Ausdruck hat. Ich will es an einem Beispiel deutlich machen mit JSON-Strings von zwei Geräten, die verschiedenen Temperatursensoren haben und einem dritten, das Stromsensoren hat:

    Code
    #Gerät 1:
    {"StatusSNS":{"Time":"2020-04-17T12:28:35","DHT11":{"Temperature":17.0,"Humidity":95.0,"DewPoint":16.2},"TempUnit":"C"}}
    
    #Gerät 2:
    {"StatusSNS":{"Time":"2020-04-17T12:29:37","SI7021":{"Temperature":13.7,"Humidity":50.5},"TempUnit":"C"}}
    
    #Gerät3:
    {"StatusSNS":{"Time":"2020-04-17T12:30:33","ENERGY":{"TotalStartTime":"2019-10-24T18:25:25","Total":8.390,"Yesterday":0.160,"Today":0.084,"Power":6,"ApparentPower":19,"ReactivePower":18,"Factor":0.32,"Voltage":243,"Current":0.079}}}

    Für alle Geräte wird der Befehl status 10 verwendet. Aber die Ergebnisse sind verschieden. Bei Gerät 1 und 2 unterscheidet sich nur der Sensorname und die Struktur ist dieselbe, aber beim Gerät 3 haben wir eine andere Verschachtelung der Schlüssel-Wert-Paare. An diesen Stellen arbeite ich dann immer mit if-Abfragen, um solche Abweichungen zu bearbeiten. In menschlicher Sprache ausgedrückt "frage" ich: Gibt es "StatusSNS" und "ENERGY" im Ausdruck, dann mach dieses und jenes sonst: mach was anderes.

    PS: Ich bin sicher, in diesem Forum sind mehr Programmier-Amateure (wie ich) unterwegs als -Profis. Also keine falsche Scheu!

    PPS: Und deine Screenshots lassen einen ziemlich professionelle Herangehensweise vermuten!

  • mehr mit Python

    Bei Gelegenheit arbeite ich mich da mal ein. Bash hatte bisher alles lösen können, aber vielleicht wäre es mal Zeit für einen weiteren Schritt nach vorn.

    Für alle Geräte wird der Befehl status 10 verwendet. Aber die Ergebnisse sind verschieden. Bei Gerät 1 und 2 unterscheidet sich nur der Sensorname und die Struktur ist dieselbe, aber beim Gerät 3 haben wir eine andere Verschachtelung der Schlüssel-Wert-Paare. An diesen Stellen arbeite ich dann immer mit if-Abfragen, um solche Abweichungen zu bearbeiten. In menschlicher Sprache ausgedrückt "frage" ich: Gibt es "StatusSNS" und "ENERGY" im Ausdruck, dann mach dieses und jenes sonst: mach was anderes.

    Ich habe leider nur Geräte mit und ohne Strommessung.

    Da arbeite ich schon mit einer IF-Anweisung, die mit jq prüft, ob Stromdaten vorliegen. Falls keine vorliegen, wird der Teil mit dem Strom übersprungen.

    ziemlich professionelle Herangehensweise

    Danke.

    Wenn ich sehe, wie andere Scripte aufgebaut sind, wie in manchen Foren über Code diskutiert wird, sehe ich mich bei 10 Klassen in der Grundschule (Klasse 2). Aber ich arbeite hart an der Versetzung in Klasse 3. ;)

    Um es auf kleinen Viewports vernünftig aussehen zu lassen, wäre vielleicht auch denkbar, das du die nicht so wichtigen Spalten je nach Bildschirmbreite ausblendest

    Mit Bash selber kann ich nur den HTML-Code mit Werten in eine Datei gießen.

    Das wäre also die Aufgabe vom HTML-Template, welches responsive sein müsste. Da fehlt mir noch irgendwie das richtige Template.

    Ich habe schon ein paar probiert, die funktionieren auch grundsätzlich alle irgendwie, aber bei vielen Spalten gibt es da schnell Probleme.

    Ungern würde ich Krückenlösungen einsetzen, z.B. wie früher 2x HTML, sprich extra ein Template für Smartphones und eins für große Bildschirme.

    Meine Hardware@home: Fritzbox 7590AX, 15xTasmota-Geräte, Syno NAS, Raspberry Pi 4 f. PiHole, ioBroker, Docker, TasmoAdmin, Portainer

  • okay, ich bastel mein HTML immer selber.... mit CSS wärs machbar, "unwichtige" Spalten automatisch auszublenden...

    z.B. https://www.mediaevent.de/css/table-responsive.html

    mit fertigen Templates wird das wohl nicht so einfach, ich weiß nicht, wie einfach die sich anpassen lassen...

    Alternativ könntest du vielleicht komplett von einer Tabelle weggehen und jedes Gerät quasi in eine kleine Box stecken... wo dann alle Inhalte untereinander angezeigt werden und mehrere dieser Boxen dann, je nach Bildschirmbreite, automatisch nebeneinander positioniert werden.

    --- Signaturen werden völlig überbewertet --- X/