Ankündigung

Einklappen
Keine Ankündigung bisher.

MQTT Subscribe Server(LBS19001052) Beispiel 1Wire-owfs-ioBroker -MQTT-Server-Edomi

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

    #16
    Servus. Vielleicht hilft dir dieser link?
    Dort ist beschrieben, wie man viele Temperatursensor schnell auslesen kann.

    https://www.domoticz.com/forum/viewtopic.php?t=9912

    Kommentar


      #17
      Hi Carsten,
      ich habe noch nicht ganz verstanden, warum es architektonisch besser ist, wenn ein Python Script die 1-wire Sensoren ausliest und dann per MQTT an Edomi sendet, im Gegensatz zum Auslesen direkt durch EDOMI. Ich würde es verstehen, wenn OWFS selbst eine MQTT Schnittstelle anbietet, denn dann käme es ja out-of-the-box für das gesamte 1-wire Netz, aber so ist es nur eine Verlagerung, oder hab ich da jetzt was missverstanden?

      Kommentar


        #18
        Grüß euch,
        Also ich habe 1wire auch vom Edomi Server entfernt, da dieser damit ziemlich schnell gedenkpausen einlegt und einfach hängen bleibt. Habe ca. 60 1wire Sensoren.
        Ich mache jedoch auch nicht den Zwischenschritt über mqtt, sonder Speise die Temperaturen direkt ins knx ein. Somit kann diese Edomi ohne Hänger verwenden.

        SG Joe

        Kommentar


          #19
          Hallo André,

          die bisherige Lösung mit den OWFS-LBS war und ist klasse, weil absolut stabil und verlässlich. Hänger hatte ich nie (derzeit 35 Sensoren).

          Aber...zwei Punkte sehe ich architektonisch zur Verbesserung:
          • Harmonisierung der Protokolle; ich möchte nach Möglichkeit (d.h. wo sinnvoll machbar) neben nativ (http/REST/API) nur noch MQTT nutzen als etablierte, stabile, verlässliche, performante und schlanke Lösung = Industrie-Standard
          • Reduzierung von Komplexität und Abhängigkeiten
          Beide führt zu KISS: Keep it simpel stupid

          Zu Punkt 1 will ich möglichst viele remote-Quellen darüber laufen lassen (z.B. diverse ESP8266 im inbound/Sensoren und outbound/Aktoren). Alles schön einfach, weil alles gleich ist. Ich mag Diversifikation, aber hier im technischen Kontext finde ich "einfältig" = "nur 1 Fall" am besten...

          Vor allem der 2. Punkt hat aber reale Wirkung: Jede zusätzliche Installation abseits des edomi-Standards erhöht für mich die Fehlerquellen und vor allem: Wenn sich an der Quelle etwas ändert, dann weiß vor allem die Quelle am besten, was dort zu tun ist. Am besten genau nur dort. Wenn es also irgendwann mal Änderungen an 1-wire gibt oder OWFS (oder wie auch immer die Bibliothek morgen für 1-wire heißt), dann kümmere ich mich genau dort quellnah darum. Nur dort. Und dort hat man auch alle Optionen. Und keine Bibliotheken-Updates im edomi oder Abhängigkeiten. Wenn es also an irgend einem Atom unserer durchaus komplexen LAN-IT-Welt Änderungen gibt (1-wire, MikroTik, PV-Anlage, FritzBox,..), muss ich immer möglichst nur an 1 Stelle ändern/updaten, nicht an 2. In edomi kommt im schlimmsten Fall nur nichts mehr an, erkenne das verlässlich und generiere eine Warn-Mail.

          Das Prinzip versuche ich beim Umzug-in-progress meiner 1.64-PROD auf die künftige 2.xx-PROD so weit wie sinnvoll möglich durchzuziehen. Bisher komme ich mit MQTT und MikroTik (kritische Komponente und MQTT an Quelle keine Option) hin. Aber ich bin noch am Umziehen und werde im Zuge dessen vielleicht noch weitere Bibliotheken letztlich nicht gänzlich herumkommen...

          Dafür fällt MQTT hoffentlich irgendwann weg, wenn MQTT direkt von edomi unterstützt wird.

          VG,
          Carsten
          Zuletzt geändert von saegefisch; 03.08.2020, 15:15.

          Kommentar


            #20
            Auch wenn es mein erstes Python ist - so funktioniert es bereits; ist ja auch keine Raketenwisschaft. Für jedwede konstruktive Kritik bin ich dankbar, bestimmt kann man das ein oder andere besser lösen in python.

            Und natürlich ist es hoffentlich anderen mit den gleichen Zielen dienlich. Jetzt muss es sich mal eine Weile beweisen, dass es so stabil ist, wie die bisherige OWFS-LBS-Lösung... Dann kann jeder mit 1-wire selber entscheiden, welcher Weg sinnvoller erscheint; mit dem ioBrocker sind es nun 3 Optionen:

            Code:
            #!/usr/bin/env python
            # coding: utf-8
            
            import paho.mqtt.client as mqtt
            import datetime
            
            from pyownet import protocol
            
            # The callback for when the client receives a CONNACK response from the server.
            def on_connect(client, userdata, flags, rc):
            print("Connected with result code "+str(rc))
            
            # === Publisher ===
            # >>>> Open with TLS + user/PW
            client = mqtt.Client()
            client.on_connect = on_connect
            client.tls_set('/etc/ssl/meineca/cacert.pem')
            client.username_pw_set(username="edomi", password="MK6wpXLg_4uxJs")
            client.connect("HAL-30.int", 8883, 60)
            
            # >>>>Workload
            #
            # >> open connect to 1-wire (owserver)
            owproxy = protocol.proxy(host="localhost", port=4304, persistent=False, verbose=False)
            
            # get data
            topic_pre = '1wire'
            for sensor in owproxy.dir(slash=False, bus=False):
            try:
            type = '/temperature'
            val = float(owproxy.read(sensor + type))
            topic = topic_pre + sensor.replace(".", "/") + type
            client.publish(topic, val)
            
            temp = "{0:.2f}".format(val)
            except protocol.OwnetError:
            temp = ''
            
            try:
            type = '/humidity'
            val = float(owproxy.read(sensor + type))
            topic = topic_pre + sensor.replace(".", "/") + type
            client.publish(topic, val)
            
            hum = "{0:.6f}".format(val)
            except protocol.OwnetError:
            hum = ''
            
            try:
            type = '/vis'
            val = float(owproxy.read(sensor + type))
            topic = topic_pre + sensor.replace(".", "/") + type
            client.publish(topic, val)
            
            vis = "{0:.6f}".format(val)
            except protocol.OwnetError:
            vis = ''
            
            try:
            type = '/VDD'
            val = float(owproxy.read(sensor + type))
            topic = topic_pre + sensor.replace(".", "/") + type
            client.publish(topic, val)
            
            vdd = "{0:.6f}".format(val)
            except protocol.OwnetError:
            vdd = ''
            try:
            type = '/VAD'
            val = float(owproxy.read(sensor + type))
            topic = topic_pre + sensor.replace(".", "/") + type
            client.publish(topic, val)
            
            vad = "{0:.6f}".format(val)
            except protocol.OwnetError:
            vad = ''
            
            # For tests with output
            # print('{0:<17} {1:<7} {2:>7} {3:>7} {3:>7} {5:>7}'.format(sensor, temp, hum, vis, vdd, vad))
            
            
            # TS as publisher-alive-indicator for subscribers
            client.publish("1wire/ts_utc", str(datetime.datetime.utcnow()).split('.')[0])
            
            # >>>> Close connections
            client.disconnect()
            
            # ============================================
            # pyownet can be considered a replacement for ownet (which can be found in module/ownet/python in the owfs source tree). The main reason for writing PYONET code was
            # the observation that the ‘official' ownet has an incomplete set of features, it is not maintained anymore, and that there is no support for Python3.
            # - OW -> http://owfs.sourceforge.net/owpython.html
            # - PYOWNET -> https://pyownet.readthedocs.io/en/latest/protocol.html | https://pypi.org/project/pyownet/
            Ablage zum Beispiel hier: /usr/local/bin/1wire2mqtt.py

            Eintrag in /etc/crontab für 2-minütlichen Aufruf:
            # Run frequently to publish all available values from 1-wire via MQTT
            */2 * * * * root /usr/bin/python /usr/local/bin/1wire2mqtt.py


            in edomi:
            Parser E2 = "1wire/#"
            Parser E6 = z.B. "28/065BED060000/temperature"

            mqtt.JPG

            Den timestamp (oder jeden anderen Wert) per Watchdog prüfen und bei Ausbleiben z.B. nach 10min Warn-Mail, nach 2h Alarm-Mail senden. Am besten notiert man in der Mail bereits seine Erfahrungen, wie man das Problem schon mal gelöst hat.

            So bleibt ein Ausbleiben/Instabilität der Lösung nicht unerkannt und im Fehlerfall hat man die Anleitung direkt auf dem smartphone und kann ggf. jemandem Zuhause zur Lösung anleiten.

            Jetzt muss es sich nur gegen die bisherige Lösung beweisen... ich bin gespannt...

            Update 05.08.2020: Bis jetzt sehr stabil, der Watchdog musste noch nicht bellen...
            Wer könnte da nur auf die Idee kommen, das über eine zusätzliche ioBrocker-Komponente laufen lassen zu wollen...
            mqtt.JPG
            Zuletzt geändert von saegefisch; 05.08.2020, 20:58.

            Kommentar


              #21
              Hi Carsten,

              da ist man mal zwei Wochen im Urlaub, schon hast du in 3 Tagen alles fix und fertig. Respekt!
              Da kann ich ja nur noch ergänzen und meine Ansätze informativ nochmal beitragen.

              Beim OWFS habe ich mir angewöhnt die Sensoren mit einem Alias zu versehen.
              Dadurch spare ich mir in nachgelagerten Anwendungen das 28.55ddff... in konkrete Sensorstandorte "umzudenken".
              Diese Alias Datei heißt, bzw. liegt in /etc/ow-alias.
              Meine sieht dabei wie folgt aus:
              Code:
              28.922620060000 = 1w.temp.Gaestezimmer.EG
              28.934320060000 = 1w.temp.Bad.EG
              28.A064DE030000 = 1w.temp.Aussen.Hof
              28.CC5BDE030000 = 1w.temp.WW.Boiler
              28.6C81DE030000 = 1w.temp.Heizungsraum
              28.5C9E1B030000 = 1w.temp.WW.Boiler.Ruecklauf
              28.62A31B030000 = 1w.temp.Heizung.Ruecklauf
              28.F2A91B030000 = 1w.temp.Solar.Vorlauf
              28.4560CE040000 = 1w.temp.Solar.Rueckladung
              28.ADCA1B030000 = 1w.temp.Heizung.Vorlauf
              28.7D901B030000 = 1w.temp.WW.Boiler.Vorlauf
              28.EB75AF030000 = 1w.temp.Solar.Ruecklauf
              26.B789C6010000 = 1w.hum.Gaestezimmer.EG
              26.30CAC6010000 = 1w.hum.Huxelkeller.UG
              26.5EE0C6010000 = 1w.hum.Bad.EG
              28.833920060000 = 1w.temp.Kueche.EG
              26.D9C5C6010000 = 1w.hum.Kueche.EG
              12.54907C000000 = 1w.switch.Ladepumpe.Boiler
              12.6A177D000000 = 1w.switch.Garagentor
              28.FFD72F661403 = 1w.temp.Aussen.Garten
              FF.C20700000100 = 1w.lcd.raspberry.netzwerkrack
              28.48DE84000003 = 1w.voc.Schlafzimmer.OG
              26.49DE84000003 = 1w.hum.Schlafzimmer.OG
              28.A3D984001605 = 1w.voc.Kinderzimmer.OG
              26.A3D984001605 = 1w.hum.Kinderzimmer.OG
              28.97F81F060000 = 1w.temp.Huxelkeller.UG
              26.4FDE84000003 = 1w.hum.Flur.UG
              12.14177D000000 = 1w.switch.Ampel.Schlafzimmer.OG
              12.C2157D000000 = 1w.switch.Ampel.Kinderzimmer.OG
              01.1027791A0000 = 1w.id.Waschkueche.Wassermelder
              20.5ADE84000003 = 1w.multi.Waschkueche
              26.52DE84000003 = 1w.hum.Keller
              26.4EDE84000003 = 1w.hum.Heizungsraum
              1D.F9DD84000003 = 1w.count.power1
              1D.FADD84000003 = 1w.count.power2
              01.50B0620D0000 = 1w.id.H3.Device
              01.4AC5620D0000 = 1w.id.H3K1.FK.Dachfenster.KiZi
              01.4ACD620D0000 = 1w.id.H3K2.FK.KiZi.OG.re
              01.D1D9620D0000 = 1w.id.H3K3.FK.KiZi.OG.li
              01.23D5620D0000 = 1w.id.H3K4.FK.KiZi.OG.hinten
              01.3DD0620D0000 = 1w.id.H3K5.FK.Huxelkeller
              01.FAC4620D0000 = 1w.id.H2.Device
              01.54A1620D0000 = 1w.id.H2K1.FK.Bad.OG
              01.6FA0620D0000 = 1w.id.H2K2.FK.Dachfenster.SZ
              01.02C3620D0000 = 1w.id.H2K3.FK.SZ.Gaube.li
              01.D4C6620D0000 = 1w.id.H2K4.FK.SZ.Gaube.re
              01.F2B1620D0000 = 1w.id.H2K5.FK.Dachfenster.Bad
              01.BBD0620D0000 = 1w.id.H1.Device
              01.9AB6620D0000 = 1w.id.H1K1.FK.Keller.hinten.li
              01.5BC7620D0000 = 1w.id.H1K2.FK.Keller.hinten.re
              01.1DC8620D0000 = 1w.id.H1K3.TK.Waschkueche.Tuer
              01.3AC0620D0000 = 1w.id.H1K4.FK.Waschkueche.re
              01.E1C1620D0000 = 1w.id.H1K5.FK.Waschkueche.li
              26.53DE84000003 = 1w.hum.Aussen.Garten
              Diese muss natürlich in /etc/owfs.conf mit
              Code:
              alias = /etc/ow-alias
              eingebunden sein.

              Da ich für meine Heim-IT die Monitoringlösung CheckMK verwende, habe ich die Abfrage nicht über Cronjob erledigt, sondern über den CheckMK-Agenten der ohnehin jede Minute läuft.
              Mein Script gibt daher nicht nur die Werte an MQTT weiter, sondern auch per Textausgabe auf der CLI im CheckMK local check Plugin Format aus.
              Im CheckMK sieht der Graph dann etwa so aus:

              graph-collection.png

              Das Script selbst hat keine Sicherheit eingebaut was die Verbindung zum MQTT Broker angeht!
              Das komplette Segment (inkl. Edomi) hängt ohnehin in einem separaten Firewall Segment.
              Das natürlich auch um die Geräte im Hausautomatisierungs-LAN Segment (vor allem den KNX Router!) vor zu viel Netzwerkballast (ARP, Broadcasts, sonstiger non-KNX-Multicast, ...) zu schützen.
              (Stichwort: Eigene Broadcast Domain)
              Aber das ist ja ein anderes Thema.

              In meinem Script treffe ich gleich eine Vorauswahl an Sensortypen und behandle nur die für mich interessanten.
              Auch einfache Umrechnungen, wie z.B. für den VOC Sensor von tm3d, erledige ich direkt dort.
              Nun aber genug gelabert - Hier der Code den ich verwende:
              Code:
              #!/usr/bin/env python
              # -*- encoding: utf-8; py-indent-offset: 4 -*-
              from __future__ import print_function
              from pyownet import protocol
              import pprint
              import math
              import paho.mqtt.publish as publish
              
              ### Zum OneWire System auf RPi mit 17channel Onewire-HAT verbinden (10.1.22.21) ###
              owproxy = protocol.proxy(host="10.1.22.21", port=4304)
              
              def lesen(a): return owproxy.read(a)
              def inhalt(b): return owproxy.dir(b)
              
              ### variablen definieren: ###
              sensoren = inhalt('')
              alarme = inhalt('/alarm')
              ds_temp = []
              ds_hum = []
              ds_count = []
              ds_multi = []
              ### Zum MQTT Server verbinden (Docker Container auf RPi (10.1.22.21) ###
              mqtthost = '10.1.22.21'
              
              for i in sensoren:
              if i in alarme:
              salarm_s = 'aktiv'
              else:
              salarm_s = 'inaktiv'
              stype = lesen(i + 'type')
              if 'DS18B20' in stype: # Sensortyp DS18B20
              stemp = float(lesen(i + 'temperature'))
              smin = float(lesen(i + 'templow'))
              smax = float(lesen(i + 'temphigh'))
              if 'voc' in i:
              sco2 = (stemp * 75) + 400
              stemp *= 2
              sminco2 = -2
              smaxco2 = 1500
              swarnco2_upper = 1000
              swarnco2_lower = -1
              else:
              sco2 = ''
              stemp = '{0:.2f}'.format(stemp)
              swarn_upper = smax - 5
              swarn_lower = smin + 5
              ds_temp.append([i, salarm_s, stype, stemp, swarn_lower, swarn_upper, smin, smax])
              if 'voc' in i:
              print('P {0} voc={3}|co2={8};{9}:{10};{11}:{12} Type: VOC-{2} - Sensoralarm: {1}'.format(i[1:-1], salarm_s, stype, stemp, swarn_lower, swarn_upper, smin, smax, sco2, swarnco2_lower, swarnco2_upper, sminco2, smaxco2))
              else:
              print('P {0} temperature={3};{4}:{5};{6}:{7} Type: {2} - Sensoralarm: {1}'.format(i[1:-1], salarm_s, stype, stemp, swarn_lower, swarn_upper, smin, smax))
              if 'DS2438' in stype: # Sensortyp DS2438
              stemp = float(lesen(i + 'temperature'))
              stemp = '{0:.2f}'.format(stemp)
              shumidity = float(lesen(i + 'humidity'))
              shumidity = '{0:.2f}'.format(shumidity)
              ds_hum.append([i, salarm_s, stype, stemp, shumidity])
              print('P {0} temperature={3}|humidity={4} Type: {2} - Sensoralarm: {1}'.format(i[1:-1], salarm_s, stype, stemp, shumidity))
              if 'DS2423' in stype: # Sensortyp DS2423
              countera = int(lesen(i + 'counter.A'))
              counterb = int(lesen(i + 'counter.B'))
              ds_count.append([i, salarm_s, stype, countera, counterb])
              print('P {0} countera={3}|counterb={4} Type: {2} - Sensoralarm: {1}'.format(i[1:-1], salarm_s, stype, countera, counterb))
              if 'DS2450' in stype: # Sensortyp DS2450
              stemp = float(lesen(i + 'volt.A'))
              stemp = (stemp - 2.56) * 128
              stemp = '{0:.2f}'.format(stemp)
              shumidity = float(lesen(i + 'volt.B'))
              shumidity = shumidity * 128
              shumidity = '{0:.2f}'.format(shumidity)
              sbrightness = float(lesen(i + 'volt.C'))
              sbrightness = math.exp(((sbrightness - 2.56) * 12.8))
              sbrightness = '{0:.2f}'.format(sbrightness)
              spressure = float(lesen(i + 'volt.D'))
              spressure = spressure * 400
              spressure = '{0:.2f}'.format(spressure)
              ds_multi.append([i, salarm_s, stype, stemp, shumidity, sbrightness, spressure])
              print('P {0} temperature={3}|humidity={4}|ambient={5}|pressure_ hpa={6} Type: {2} - Sensoralarm: {1}'.format(i[1:-1], salarm_s, stype, stemp, shumidity, sbrightness, spressure))
              
              ### senden an mqtt broker
              
              for to_mqtt in ds_temp:
              publish.single('1-wire/' + to_mqtt[0][1:-1] + '/temperature', to_mqtt[3], hostname=mqtthost)
              
              for more_to_mqtt in ds_hum:
              publish.single('1-wire/' + more_to_mqtt[0][1:-1] + '/temperature', more_to_mqtt[3], hostname=mqtthost)
              publish.single('1-wire/' + more_to_mqtt[0][1:-1] + '/humidity', more_to_mqtt[4], hostname=mqtthost)
              
              for much_more_to_mqtt in ds_multi:
              msgs = [{'topic':'1-wire/' + much_more_to_mqtt[0][1:-1] + '/temperature', 'payload':much_more_to_mqtt[3]}, {'topic':'1-wire/' + much_more_to_mqtt[0][1:-1] + '/humidity', 'payload':much_more_to_mqtt[4]}, {'topic':'1-wire/' + much_more_to_mqtt[0][1:-1] + '/ambient', 'payload':much_more_to_mqtt[5]}, {'topic':'1-wire/' + much_more_to_mqtt[0][1:-1] + '/pressure', 'payload':much_more_to_mqtt[6]}]
              publish.multiple(msgs, hostname=mqtthost)
              
              for counter_to_mqtt in ds_count:
              publish.single('1-wire/' + counter_to_mqtt[0][1:-1] + '/counter.A', counter_to_mqtt[3], hostname=mqtthost)
              publish.single('1-wire/' + counter_to_mqtt[0][1:-1] + '/counter.B', counter_to_mqtt[4], hostname=mqtthost)
              Leider behält der Editor hier die eingerückten Zeilen nicht bei.
              Hier das Python Script zum herunterladen:
              maxim_onewire.txt

              Der Code ist bestimmt für einen Python Profi vom Aufbau her lächerlich. Dafür vom ungeübten Python-Gelegenheitsuser 100% Handarbeit ;-)
              Wie gesagt, ist für mich in meinem Umfeld eine sinnvolle Lösung - kann sich bei jedem anderen natürlich als unbrauchbar entpuppen.


              Da die Vorarbeit mit den Alias nun gemacht ist, kann ich in Edomi wunderbar mit Sensornamen arbeiten, statt dem HEX ID-Wert.
              Bilder sagen mehr als viele Worte:
              edomi_mqtt.png
              Da mein Abonnement hier mit # alles umfasst, habe ich noch einen Regexp Filter gesetzt, auf die Werte die mich interessieren:
              Code:
              /.+hum.+./|/.+temp.*/|/.+multi.+/|/.+voc.+/|/Device.+/|/Energy.+/|/FS20.+/
              Bitte nicht über das FS20 wundern. Das ist eine Altlast aus FHEM Zeiten, die mein CUNO2 Device ebenfalls an den MQTT Broker sendet.

              Okay - soweit so gut.
              Vielleicht kann ja der ein oder andere damit was anfangen, bzw. was nützliches finden.

              Viele Grüße
              Markus
              Angehängte Dateien
              Zuletzt geändert von kctnetworx; 13.08.2020, 14:27. Grund: Tippfehler mal in die Tonne gekloppt....

              Kommentar

              Lädt...
              X