Ankündigung

Einklappen
Keine Ankündigung bisher.

MQTT Topic, JSON zerlegen - Wie geht man das an?

Einklappen
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

    MQTT Topic, JSON zerlegen - Wie geht man das an?

    Hallo,

    ich habe das MQTT Plugin bei mir erfolgreich integriert und bekomme von einem SONOFF auf fleissig die Daten (Testumgebung).
    So wie ich es verstanden habe, kommen die Topics als JSON String.
    Das MQTT Plugin versucht die Daten in das Format zu bringen, das bei der Itemdefinition als "type" definiert wurde.

    Das der Konsole des SONOFF habe ich hier den gesendeten Inhalt in einem Topic:
    tele/sonoff_1/STATE = {"Time":"2017-12-29T09:28:57","Uptime":17,"Vcc":3.178,"POWER":"OFF" ,"Wifi":{"AP":1,"SSId":"WLAN-Access","RSSI":52,"APMac":"C0:25:06:15:95:57"}}
    Dieses weise ich einem Item, dass als dict definiert wurde, zu:
    Status_dict:
    type: dict
    mqtt_topic_in: tele/sonoff_1/STATE

    Voltage:
    type: num
    eval_trigger: Sonoff.wz_Tasmota.Status_dict
    eval: value['Vcc']

    SSId:
    type: num
    eval_trigger: Sonoff.wz_Tasmota.Status_dict
    eval: value['SSId']
    Damit möchte ich die einzelnen Werte aus dem JSON extrahieren.
    Mit der Methode, die smai mal vergeschlagen hat, funktioniert es nicht immer. Es sieht so aus, dass man damit nur die Infos aus der "ersten Ebene" des JSON auslesen kann. Bei SSId, das im JSON in der "zweiten Ebene" steht, kommt im Log:
    WARNING Sonoff.wz_Tasmota.Status_dict.SSId Item Sonoff.wz_Tasmota.Status_dict.SSId: problem evaluating value['SSId']: 'SSId'
    Der Inhalt des dict im Backend sieht so aus:
    {'Time': '2017-12-29T10:04:15', 'Wifi': {'RSSI': 54, 'SSId': 'WLAN-Access', 'APMac': 'C0:25:06:15:95:57', 'AP': 1}, 'Vcc': 3.178, 'Uptime': 18, 'POWER': 'OFF'}
    Daher die Frage, wie man am besten des JSON zerlegen kann, um an die Infos zu kommen? Braucht man da noch einen JSON endocer bzw. decoder?
    So wie ich gesehen habe, sind die einzelnen Informationen im dem JSON auch oft in anderer Reihenfolge.

    Danke für Eure "Best Practices"!
    Zuletzt geändert von Sisamiwe; 29.12.2017, 10:08.

    #2
    Am besten liest Du die MQTT Message in ein Item vom Typ dict ein. Die einzelnen Strings übernimmst Du dann per eval Attribut in weitere Items:
    Code:
    test:
    
        var_dict:
            type: dict
            value: '{"k1": "v1", "k2": "v2"}'
    
        var_str1:
            type: str
            eval: sh.test.var_dict()['k1']
            eval_trigger: test.var_dict
    
        var_str2:
            type: str
            eval: sh.test.var_dict()['k2']
            eval_trigger: test.var_dict
    Ich habe im Beispiel das dict-Item mal vorbelegt. Du kannst das natürlich zum Test auch einfach über das Backend machen.

    Wenn var_dict sich ändert, wird der Wert zum Key "k1" in das Item var_str1 eingelesen und der Wert zum Key "k2" in das Item var_str2.
    Viele Grüße
    Martin

    There is no cloud. It's only someone else's computer.

    Kommentar


      #3
      Msinn
      Danke!

      Noch eine Frage: Wie geht das mit Informationen aus der "zweiten Ebene", also da, wo ein dict im dict ist?

      Beispiel:
      {'DS18B20': {'Temperature': 12.4}, 'Time': '2017-12-29T11:58:51', 'TempUnit': 'C'}
      Hier steckt die Information 'Temperature' im 'DS18B20' mit drin?

      Kommentar


        #4
        Wie in Python mit dicts üblich:
        Code:
         sh.test.var_dict()['DS18B20']['Temperature']
        Wenn Du nur
        Code:
         sh.test.var_dict()['DS18B20']
        aufrufst, erhältst Du wieder ein dict, was Du einem dict-Item zuweisen könntest.
        Viele Grüße
        Martin

        There is no cloud. It's only someone else's computer.

        Kommentar


          #5
          Msinn
          Danke, nun klappts.

          Es geht sogar noch einfacher:
          Code:
                  Temp_dict:
                      type: dict
                      mqtt_topic_in: tele/sonoff_1/SENSOR
                      #{'DS18B20': {'Temperature': 12.4}, 'Time': '2017-12-29T11:58:51', 'TempUnit': 'C'}
          
                      Temp:
                          type: num
                          eval: value['DS18B20']['Temperature']
                          eval_trigger: Sonoff.wz_Tasmota.Temp_dict
          
                      TempUnit:
                          type: str
                          eval: value['TempUnit']
                          eval_trigger: Sonoff.wz_Tasmota.Temp_dict
          Anstatt sh.test.var_dict() kann man auch value nutzen.

          Kommentar


            #6
            Das funktioniert nicht! Woher sollte value auch wissen, dass es auf Temp_Dict zugreifen soll.

            Value greift den Wert den Temp vor dem eval hat (was immer das gerade ist). Schau Dir das bitte in der Doku an, sonst wirst Du viele Wunder erleben.
            Viele Grüße
            Martin

            There is no cloud. It's only someone else's computer.

            Kommentar


              #7
              Ich habe die Doku gelesen und ich weiß, was value macht. Trotzdem wollte ich den Tipp von smai mit value testen.
              Es funktioniert, wobei ich mir auch nicht erklären kann, warum.

              Kommentar


                #8
                Ich würde es bleiben lassen. Ich kenne den Quellcode, smai nicht.
                Viele Grüße
                Martin

                There is no cloud. It's only someone else's computer.

                Kommentar


                  #9
                  Ich habe die Off-Topic Grundsatz Diskussion zum Thema "Bedeutung von value" mal in den Thread Nutzung/Bedeutung von Value in eval Ausdrücken ausgelagert.
                  Viele Grüße
                  Martin

                  There is no cloud. It's only someone else's computer.

                  Kommentar


                    #10
                    Hallo,

                    ich habe noch ein Frage zum Auslesen eines dict bzw. dem Zerlegen eines JSON.
                    Ich weise einem Item vom Type dict folgendes JSON zu:

                    Code:
                     
                     {"software_version": "NRZ-2017-100", "age":"112", "sensordatavalues":[{"value_type":"SDS_P1","value":"2.73"},{"value_type":"SDS_P2","value":"1.93"},{"value_type":"BME280_temperature","value":"13.62"},{"value_type":"BME280_humidity","value":"64.09"},{"value_type":"BME280_pressure","value":"94819.56"},{"value_type":"samples","value":"613704"},{"value_type":"min_micro","value":"234"},{"value_type":"max_micro","value":"27006"},{"value_type":"signal","value":"-88"}]}
                    Das mache ich mit einer Logik:
                    import json
                    import requests

                    response = requests.get("http://192.168.2.26/data.json")
                    json_data = response.json()
                    sh.json_test.device_1.reading(json_data)
                    Im Item kommt folgendes an:
                    Code:
                    {'sensordatavalues': [{'value_type': 'SDS_P1', 'value': '2.73'}, {'value_type': 'SDS_P2', 'value': '1.93'}, {'value_type': 'BME280_temperature', 'value': '13.62'}, {'value_type': 'BME280_humidity', 'value': '64.09'}, {'value_type': 'BME280_pressure', 'value': '94819.56'}, {'value_type': 'samples', 'value': '613704'}, {'value_type': 'min_micro', 'value': '234'}, {'value_type': 'max_micro', 'value': '27006'}, {'value_type': 'signal', 'value': '-88'}], 'software_version': 'NRZ-2017-100', 'age': '123'}
                    Wie kann ich mit dem eval eines anderen Items den Wert "2.73" übernehmen. Das wäre im (unter-)dict "sensordatavalues" und bei "value_type"="SDS_P1" der Wert des "value".

                    Leider reichen meine Kenntnisse dafür nicht.
                    Könnte ihr helfen?

                    DANKE.
                    Zuletzt geändert von Sisamiwe; 11.03.2018, 17:32.

                    Kommentar


                      #11
                      Lesbarer aufbereitet sieht das dict folgendermaßen aus:

                      Code:
                      {'sensordatavalues': [{'value': '1.40', 'value_type': 'SDS_P1'},
                                            {'value': '1.30', 'value_type': 'SDS_P2'},
                                            {'value': '14.57', 'value_type': 'BME280_temperature'},
                                            {'value': '61.30', 'value_type': 'BME280_humidity'},
                                            {'value': '94825.89', 'value_type': 'BME280_pressure'},
                                            {'value': '611982', 'value_type': 'samples'},
                                            {'value': '235', 'value_type': 'min_micro'},
                                            {'value': '27729', 'value_type': 'max_micro'},
                                            {'value': '-90', 'value_type': 'signal'}],
                      'age': '25',
                      'software_version': 'NRZ-2017-100'}
                      • mit ['sensordatavalues'] greifst Du auf die Liste der Sensordaten zu
                      • ['sensordatavalues'][0] liefert das dict mit den Informationen zum ersten Sensorwert
                      • ['sensordatavalues'][0]['value'] liefert Dir dann den gewünschten Wert '1.40'

                      Viele Grüße
                      Martin

                      There is no cloud. It's only someone else's computer.

                      Kommentar


                        #12
                        Msinn

                        Super, Danke für die schnelle Antwort.
                        Es klappt.
                        Kann man auch gezielt den 'value' von SDS_P1 auslesen? Ich bin mir nicht sicher, ob dieser Value auch immer der erste in der Reihe ist.

                        Kommentar


                          #13
                          Nein
                          Viele Grüße
                          Martin

                          There is no cloud. It's only someone else's computer.

                          Kommentar


                            #14
                            Msinn

                            Danke, verstanden.

                            Kann ich bei der Zuweisung des Werten zu einem Item durch eval auch gleich noch eine Berechnung durchführen?

                            Code:
                                        Pres:
                                            type: num
                                            eval: (sh...()['sensordatavalues'][4]['value']) / 100
                                            eval_trigger: ..
                            Ich möchte beim Luftdruck den Wert aus dem dict durch 100 dividieren, um auf hPa zu kommen.
                            So wie ich es formuliert habe, kommt eine Fehlermeldung im Log:
                            2018-03-11 18:31:44 WARNING json_test.device_1.reading.Pres Item json_test.device_1.reading.Pres: problem evaluating (sh.json_test.device_1.reading()['sensordatavalues'][4]['value']) / 100: unsupported operand type(s) for /: 'str' and 'int'
                            Wie wäre der richtige Ausdruck?

                            Kommentar


                              #15
                              Du musst den Sensorwert erst von einem String in eine Zahl umwandeln (mit float( ... ) ). Du hast den sh... Wert ja bereits in Klammern gesetzt

                              Vor (sh.... sollte ein ‚float‘ also reichen.
                              Viele Grüße
                              Martin

                              There is no cloud. It's only someone else's computer.

                              Kommentar

                              Lädt...
                              X