Ankündigung

Einklappen
Keine Ankündigung bisher.

Stromzähler (MQTT/Tasmota) decodieren

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

    Stromzähler (MQTT/Tasmota) decodieren

    Hallo, ich glaube ich habe drei Fragen, fangen wir mal mit der ersten an:
    Ich habe einen eBZ Zähler, die Montage und Konfiguration bis ins Item klappt.

    Code:
    >D
    >B
    TelePeriod 30
    =>sensor53 r
    >M 1
    ; Device: eBZ DD3 2R06 ODZ1
    ; protocol is D0 OBIS ASCII
    ; 9600@7E1 for OP-type devices, 9600@8N1 for SM-type devices
    +1,3,o,0,9600,SM,1
    ; Zählerstand zu +A, tariflos,
    ; Zählerstände Auflösung 10 µW*h (6 Vorkomma- und 8 Nachkommastellen)
    1,1-0:1.8.0*255(@0.001,Energie Bezung,Wh,1_8_0,8
    ; Zählerstand zu +A, Tarif 1
    1,1-0:1.8.1*255(@0.001,Energie Bezung T1,Wh,1_8_1,8
    ; Zählerstand zu +A, Tarif 2
    1,1-0:1.8.2*255(@0.001,Energie Bezung T2,Wh,1_8_2,8
    ; Zählerstand zu -A, tariflos
    1,1-0:2.8.0*255(@0.001,Energie Export,Wh,2_8_0,8
    ; Summe der Momentan-Leistungen in allen Phasen, Auflösung 0,01W (5 Vorkomma- und 2 Nachkommastellen)
    1,1-0:16.7.0*255(@1,Leistung,W,16_7_0,18
    ; Momentane Leistung in Phase Lx, Auflösung 0,01W (5 Vorkomma- und 2 Nachkommastellen)
    1,1-0:36.7.0*255(@1,Leistung L1,W,36_7_0,18
    1,1-0:56.7.0*255(@1,Leistung L2,W,56_7_0,18
    1,1-0:76.7.0*255(@1,Leistung L3,W,76_7_0,18
    ; Spannung in Phase Lx, Auflösung 0,1V (nur über MSB)
    1,1-0:32.7.0*255(@1,Spannung L1,V,32_7_0,1
    1,1-0:52.7.0*255(@1,Spannung L2,V,52_7_0,1
    1,1-0:72.7.0*255(@1,Spannung L3,V,72_7_0,1
    ; Statuswort, 4 Byte Information über den Betriebszustand, HEX string
    ; tasmota can decode one string per device only!
    ;1,1-0:96.5.0*255(@#),Status1,,96_5_0,0
    ;1,1-0:96.8.0*255(@#),Status2,,96_8_0,0
    ; Geräte-Identifikation, Nach DIN 43863-5
    1,1-0:96.1.0*255(@#),Identifikation,,96_1_0,0
    ;1,1-0:0.0.0*255(@#),Identifikation,,0_0_0,0
    #
    ​
    Als Item habe ich eins vom Typ "dict", da kommen jetzt auch Werte an, wie:
    Code:
    {'Time': '2024-02-12T20:11:08', 'SM': {'56_7_0': 132.25}}
    Es gibt (aktuell) mehrere Inhalte. Hier 56_7_0, manchmal auch z.B. 16_7_0. Diese kommen nacheinander und überschreiben sich. Mir ist es nicht gelungen, die in Tasmota zu trennen auf verschiedene Telegramme. Daher muss ich nachher trennen:

    Ich habe es mit on_change versucht: .. verbrauch = value['SM']['16_7_0']

    Das führt zu Fehler:
    'On_Change' item-value='{'Time': '2024-02-12T19:57:16', 'SM': {'76_7_0': 44.5}}' problem evaluating value['SM']['16_7_0']: '16_7_0'

    Jemand eine Idee, wie ich das trennen kann?

    #2
    Hi aldaris,

    ich würde vorschlagen das über eine Logik oder Userfunction in try/except Blöcken zu zerlegen und in einzelne Items zu schreiben. Userfunction über eval oder Logik über Dict-item triggern:
    Code:
    def SplitDict():
        myDict = sh.myItem.myDict()
        #myDict = {'Time': '2024-02-12T20:11:08', 'SM': {'56_7_0': 132.25}}
        try:
            myValue=myDict['SM']['56_7_0']
            sh.myItem.SM_56_7_0(myValue)
        except:
            pass
        .......
    oder mit Prüfung auf vorhandene Keys :
    Code:
    def SplitDict():
        myDict = sh.myItem.myDict()
        #myDict = {'Time': '2024-02-12T20:11:08', 'SM': {'56_7_0': 132.25}}
        myValue=myDict['SM'].get('56_7_0',None)
        if (myValue != None):
            #sh.myItem.SM_56_7_0(myValue)
        .......

    Viele Grüße
    Andre

    Kommentar


      #3
      Hallo, danke für die Rückmeldung.
      Logik war mir eigentlich zu fett, aber UserFunc kannte ich noch nicht. Schau ich mir nachher an. Danke

      Kommentar


        #4
        Es gibt im aktuellen develop auch die Möglichkeit, "direkt" auf dicts in Items zuzugreifen, siehe https://smarthomeng.github.io/smarth...er-item-wertes.

        Man könnte also gleich myVal = sh.myItem(key='56_7_0') abfragen. Wenn Wert, dann weiter; wenn None, dann ignorieren.

        Wenn man das geschickt nutzt, könnte man das sogar in einem eval verwenden, ungetestet:

        Code:
        item:
          ...
          item_56_7_0:
            eval: sh...(key='56_7_0') if sh...(key='56_7_0') is not None else None
        ​
        Dann wird das Item nur gesetzt/aktualisiert, wenn es einen Wert bekommt; wenn es None bekommt ("dict-Key nicht gefunden"), bleibt es unverändert. Für jeden Code ein entsprechendes Unteritem einrichten und den Key anpassen sollte gehen.

        Braucht ggf. noch Tests und Optimierung (wenn eval auf "None" anspricht, auch ohne if/else, könnte man auch direkt eval: sh...(key='foo') schreiben, bin aber nicht sicher)

        Kommentar


          #5
          Die grundlegenden Möglichkeiten zum direkten Zugriff auf Elemente von dict Items bzw. list Items sind bereits im Release v1.10 vorhanden.
          Die Beschreibung findest Du hier.
          Viele Grüße
          Martin

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

          Kommentar


            #6
            Das klingt gut. Ich bin aktuell noch auf 1.9.1. Ich muss mir mal Zeit freischaufeln um ein Backup zu machen und mich dann am Update zu versuchen. Die Zeit ist wohl besser investiert als jetzt zu frickeln. Für "inline" geht es also mit 1.9.1 noch nicht?

            Kommentar


              #7
              Du könntest item().get('56_0_7') benutzen, das geht (schon immer) genauso. Ist nur länger und nicht so schön

              Kommentar


                #8
                Hi, also, bitte nicht prügeln, ich hab das mal irgendwie zusammengebaut. Absolut unschön und es ginge sicher besser, aber es funktioniert:
                Code:
                ebz:
                            type: dict
                            mqtt_topic_in: tele/tasmota_XXXXXX/SENSOR
                            sm:
                                type: dict
                                visu_acl: rw
                                eval_trigger: mqtt.strom.ebz
                                eval: sh.mqtt.strom.ebz().get('SM') if sh.mqtt.strom.ebz().get('SM') is not None else None
                                sm1670:
                                    type: num
                                    eval_trigger: mqtt.strom.ebz.sm
                                    eval: sh.mqtt.strom.ebz.sm.sm1670.verbrauch(sh.mqtt.strom.ebz.sm().get('16_7_0')) if sh.mqtt.strom.ebz.sm().get('16_7_0') is not None else None
                                    verbrauch:
                                       type: num
                                       database: yes
                                sm180:
                                   type: num
                                   eval_trigger: mqtt.strom.ebz.sm
                                   eval: sh.mqtt.strom.ebz.sm.sm180.zaehler(sh.mqtt.strom.ebz.sm().get('1_8_0')) if sh.mqtt.strom.ebz.sm().get('1_8_0') is not None else None
                                   zaehler:
                                      type: num
                                      database: yes
                Für den unrealistischen Fall, dass es jemandem hilft, teile ich es mal.

                Gruß
                Aldaris

                Kommentar


                  #9
                  Hallo,

                  mit Version 1.10 und den Dicts sieht das schon etwas besser aus. Der Code funktioniert:
                  Code:
                  EBZ:
                      type: num
                      database: init
                      eval_trigger: EBZ.EBZSM
                      eval: sh.EBZ.EBZSM(key='1_8_0')
                      EBZSM:
                        type: dict
                        eval_trigger: EBZ.EBZSM.EBZRaw
                        eval: sh.EBZ.EBZSM.EBZRaw(key='SM')
                        EBZRaw:
                          type: dict
                          mqtt_topic_in: tele/tasmota_XXXXXX/SENSOR
                  Mir ist es aber nicht gelungen, direkt im Item zweistufig das dict auszulesen, dann könnte ich mir die Hilfsitems sparen (EBZSM, EBZRaw). Sinngemäß wäre mein Ziel das hier gewesen:

                  Code:
                  EBZ:
                      type: num
                      database: init
                      mqtt_topic_in: tele/tasmota_XXXXXX/SENSOR​
                      eval: value()(key='SM')(key='1_8_0') //GEHT NICHT
                  Wenn jemand ne Idee hat bin ich natürlich interessiert, ansonsten wieder zur Doku, wenn nochmal jemand auf so eine Idee kommt.

                  Kommentar


                    #10
                    Zitat von aldaris Beitrag anzeigen
                    value()(key='SM')(key='1_8_0') //GEHT NICHT
                    Was soll das für ein Syntax sein? Mit einer Python Expression hat das wenig zu tun

                    Hast Du mal den Umgang mit dict Items probiert, den es bereits seit mehreren SmartHomeNG Versionen gibt?
                    Das könnte so oder so ähnlich aussehen:
                    Code:
                    eval: value['SM']['1_8_0']
                    Zuletzt geändert von Msinn; 24.03.2024, 13:36.
                    Viele Grüße
                    Martin

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

                    Kommentar


                      #11
                      Hi,

                      Code:
                      eval: value()(key='SM')(key='1_8_0')
                      Das sollte natürlich nur Pseudocode sein.

                      Der Vorschlag von Dir funktioniert leider nur, wenn das Element "SM" sowie "1_8_0" darin vorhanden ist. Daher ja "if" "else" aus Post #8. Das mit dem key ist da gutmütiger und liefert eben "None".

                      Kommentar


                        #12
                        Da innerhalb von eval-Ausdrücken kein Fehlermanagement möglich ist, könnte man das nur zusammenklöppeln:

                        Code:
                        eval: value['key1']['key2'| if ('key1' in value and isinstance(value['key1'], dct) and 'key2' in value['key1']) else None
                        (ungetestet

                        Ich löse ähnliche Probleme tatsächlich auch mit Hilfsitems.

                        Alternativ könntest du ab Python3.9 auch folgendes probieren:

                        Code:
                        eval: ({'key1': {'key2': None}} / value)['key1']['key2']
                        (auch ungetestet; d1 | d2 liefert das Ergebnis von d2.update(d1) zurück, damit wäre der gesuchte Key immer vorhanden; da die Werte von d2 die von d1 überschreiben, ist die Reihenfolge wichtig)

                        Kommentar

                        Lädt...
                        X