Skip to content
  • Home
  • Aktuell
  • Tags
  • 0 Ungelesen 0
  • Kategorien
  • Unreplied
  • Beliebt
  • GitHub
  • Docu
  • Hilfe
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Standard: (Kein Skin)
  • Kein Skin
Einklappen
ioBroker Logo

Community Forum

donate donate
  1. ioBroker Community Home
  2. Deutsch
  3. Hardware
  4. Kamstrup Multical 403 mit Raspberry Pi auslesen

NEWS

  • Neuer Blogbeitrag: Monatsrückblick - Dezember 2025 🎄
    BluefoxB
    Bluefox
    6
    1
    56

  • Weihnachtsangebot 2025! 🎄
    BluefoxB
    Bluefox
    24
    1
    1.4k

  • UPDATE 31.10.: Amazon Alexa - ioBroker Skill läuft aus ?
    apollon77A
    apollon77
    48
    3
    9.3k

Kamstrup Multical 403 mit Raspberry Pi auslesen

Geplant Angeheftet Gesperrt Verschoben Hardware
auslesenkamstrupoptischraspberryvolkszählerwärmemengenzählerweidmannoptokopf
5 Beiträge 4 Kommentatoren 3.3k Aufrufe 4 Watching
  • Älteste zuerst
  • Neuste zuerst
  • Meiste Stimmen
Antworten
  • In einem neuen Thema antworten
Anmelden zum Antworten
Dieses Thema wurde gelöscht. Nur Nutzer mit entsprechenden Rechten können es sehen.
  • -cs-- Offline
    -cs-- Offline
    -cs-
    schrieb am zuletzt editiert von -cs-
    #1

    Hallo zusammen,

    seit langem versuche ich an die Daten eines Kamstrup Multical 403 zu kommen, leider finde ich nichts brauchbares was mir als Laien weiterhilft.
    Ich habe zwar schon einiges mit den Raspberrys und auch ioBroker gemacht, aber hier komme ich gar nicht weiter.
    (zur Info, es handelt sich um den Wärmemengenzähler eines örtlichen, befreundeten Lieferanten, der sich in dieser Beziehung aber überhaupt nicht auskennt, aber informiert ist)

    WMZ.jpg

    Der Wärmemengenzähler hat zwar ein M-BUS Modul verbaut, aber direkt verdrahtet möchte ich dann doch nicht eingreifen zudem funktioniert dieses ja schon mit der Steuerung der Übergabestation und des Pufferspeichers.

    M-Bus.jpg

    Angestoßen vom Lesekopf von @Jaschkopf kam das Thema wieder hoch, nur hat Kamstrup ja angeblich sein eigenes Übergabeprotokoll wozu ich als "kleiner Mann" keine Infos bekomme.

    Bis jetzt habe ich nur rausgefunden, das der Multical 403 die Daten "freiwillig" senden sollte wenn der Ringmagnet des Lesekopfes aufgelegt ist, also keinen "Anstoß" dafür brauchen soll und es es ziemlich gleich wie beim 402 sein soll, wobei der 402 einen "Anstoß" brauchte.

    Evtl. ist hier jemand, der dies schon mal gemacht hat oder weiter weis?
    Am liebsten wäre die Daten mit dem Lesekopf abzufangen und in ioBroker zu verarbeiten.

    Schöne Grüße
    Christian

    -cs-- 1 Antwort Letzte Antwort
    0
    • -cs-- -cs-

      Hallo zusammen,

      seit langem versuche ich an die Daten eines Kamstrup Multical 403 zu kommen, leider finde ich nichts brauchbares was mir als Laien weiterhilft.
      Ich habe zwar schon einiges mit den Raspberrys und auch ioBroker gemacht, aber hier komme ich gar nicht weiter.
      (zur Info, es handelt sich um den Wärmemengenzähler eines örtlichen, befreundeten Lieferanten, der sich in dieser Beziehung aber überhaupt nicht auskennt, aber informiert ist)

      WMZ.jpg

      Der Wärmemengenzähler hat zwar ein M-BUS Modul verbaut, aber direkt verdrahtet möchte ich dann doch nicht eingreifen zudem funktioniert dieses ja schon mit der Steuerung der Übergabestation und des Pufferspeichers.

      M-Bus.jpg

      Angestoßen vom Lesekopf von @Jaschkopf kam das Thema wieder hoch, nur hat Kamstrup ja angeblich sein eigenes Übergabeprotokoll wozu ich als "kleiner Mann" keine Infos bekomme.

      Bis jetzt habe ich nur rausgefunden, das der Multical 403 die Daten "freiwillig" senden sollte wenn der Ringmagnet des Lesekopfes aufgelegt ist, also keinen "Anstoß" dafür brauchen soll und es es ziemlich gleich wie beim 402 sein soll, wobei der 402 einen "Anstoß" brauchte.

      Evtl. ist hier jemand, der dies schon mal gemacht hat oder weiter weis?
      Am liebsten wäre die Daten mit dem Lesekopf abzufangen und in ioBroker zu verarbeiten.

      Schöne Grüße
      Christian

      -cs-- Offline
      -cs-- Offline
      -cs-
      schrieb am zuletzt editiert von -cs-
      #2

      Leider schlief das Thema ein, aber durch andere Projekte würde mich es schon reizen, dies hinzubekommen.

      So, dann möchte ich mal Updaten, evtl. hat sich ja im letzten Jahr was getan, hier meine Erkenntnisse:

      Mit dem Optokopf von Weidmann konnte ich über Windows 10 und dem Programm Metertool von Kamstrup auf den Zähler zugreifen und die Zählerdaten auslesen, leider keine Werte.
      Soweit ich jetzt weis braucht der Multical 403 nicht extra aufwecken oder regelmäßig abgefragt zu werden um nicht abzuschalten (der Multical 402 tat dies ja anscheinend nach ca. 30 min.)

      Des weiteren habe ich im Domoticz – Forum hier ein paar Sachen gefunden.
      (Meine Beiträge in diesem Forum wurden vom Moderator gelöscht, da ich sie angeblich nicht richtig übersetzt hätte)
      In diesem Thread ist am 22.Nov.2020 auch ein Script auf Github



      <
      #! / usr / bin / env python3

      --------------------------------------------- ---------------------------

      "DIE BIERWARENLIZENZ" (Revision 42):

      phk@FreeBSD.ORG hat diese Datei geschrieben. Solange Sie diesen Hinweis behalten

      kann mit diesem Zeug machen, was immer du willst. Wenn wir uns eines Tages treffen und Sie denken

      dieses Zeug ist es wert, du kannst mir dafür ein Bier kaufen. Poul-Henning Kamp

      --------------------------------------------- ---------------------------

      Geändert für Domotics und Einzelanfragen.

      Modifiziert von Ronald van der Meer, Frank Reijn und Paul Bonnemaijers für die

      Kamstrup Multical 402

      Modifiziert von Tim van Werkhoven 20201112 für den generischen Gebrauch (zB mqtt / influxdb).

      Auch überflüssige Zählerablesung aus dem Skript beschnitten, um die Batterie des Zählers zu schonen

      life (vorherige Version hat alle 30 Variablen gelesen und nicht verwendete Daten verworfen)

      Verwendung: file <ComPort>

      aus future import print_function

      Sie benötigen pySerial

      Seriennummer importieren
      Mathe importieren
      sys importieren
      Datum / Uhrzeit importieren
      Import - Anfragen
      Paho importieren . mqtt . Kunde als Paho

      urllib importieren

      importiere urllib.request

      Codecs importieren

      Variablen

      reader = codecs . getreader ( "utf-8" )

      Debug = 1

      multical_var = { # Dezimalzahl im Befehl für Kamstrup Multical
      0x003C : " Wärmeenergie (E1)" , # 60
      0x0050 : "Power" , # 80
      0x0056 : "Temp1" , # 86
      0x0057 : "Temp2" , # 87
      0x0059 : "Tempdiff" , # 89
      0x004A : "Flow" , # 74
      0x0044 : "Volume" , # 68
      0x008D : "MinFlow_M" , # 141
      0x008B : "MaxFlow_M" , # 139
      0x008C : "MinFlowDate_M" , # 140
      0x008A : "MaxFlowDate_M" , # 138
      0x0091 : "MinPower_M" , # 145
      0x008F : "MaxPower_M" , # 143
      0x0095 : "AvgTemp1_M" , # 149
      0x0096 : "AvgTemp2_M" , # 150
      0x0090 : "MinPowerDate_M" , # 144
      0x008E : "MaxPowerDate_M" , # 142
      0x007E : "MinFlow_Y" , # 126
      0x007C : "MaxFlow_Y" , # 124
      0x007D : "MinFlowDate_Y" , # 125
      0x007B : "MaxFlowDate_Y" , # 123
      0x0082 : "MinPower_Y" , # 130
      0x0080 : "MaxPower_Y" , # 128
      0x0092 : "AvgTemp1_Y" , # 146
      0x0093 : "AvgTemp2_Y" , # 147
      0x0081 : "MinPowerDate_Y" , # 129
      0x007F : "MaxPowerDate_Y" , # 127
      0x0061 : "Temp1xm3" , # 97
      0x006E : "Temp2xm3" , # 110
      0x0071 : "Infoevent" , # 113
      0x03EC : "HourCounter" , # 1004
      }}

      multical_var_si = { # Dezimalzahl im Befehl für Kamstrup Multical
      0x003C : 1E + 0 , # Quelldaten bereits in Joule - " Wärmeenergie (E1)", # 60
      0x0050 : 1E-3 , # Quelldaten in MilliWatt - "Power", # 80
      0x0056 : 1E-9 , # Quelldaten in nanoCelcius - "Temp1", # 86
      0x0057 : 1E-9 , # Quelldaten in nanoCelcius - "Temp2", # 87
      0x0059 : 1E-9 , # Quelldaten in nanoCelcius - "Tempdiff", # 89
      0x004A : 1E-12 / 3600 , # Quelldaten Nanoliter / Stunde - "Flow", # 74
      0x0044 : 1E + 0 , # Quelldaten TBD - "Volume", # 68
      0x008D : 1E + 0 , # Quelldaten TBD - "MinFlow_M", # 141
      0x008B : 1E + 0 , # Quelldaten TBD - "MaxFlow_M", # 139
      0x008C : 1E + 0 , # Quelldaten TBD - "MinFlowDate_M", # 140
      0x008A : 1E + 0 , # Quelldaten TBD - "MaxFlowDate_M", # 138
      0x0091 : 1E + 0 , # Quelldaten TBD - "MinPower_M", # 145
      0x008F : 1E + 0 , # Quelldaten TBD - "MaxPower_M", # 143
      0x0095 : 1E + 0 , # Quelldaten TBD - "AvgTemp1_M", # 149
      0x0096 : 1E + 0 , # Quelldaten TBD - "AvgTemp2_M", # 150
      0x0090 : 1E + 0 , # Quelldaten TBD - "MinPowerDate_M", # 144
      0x008E : 1E + 0 , # Quelldaten TBD - "MaxPowerDate_M", # 142
      0x007E : 1E + 0 , # Quelldaten TBD - "MinFlow_Y", # 126
      0x007C : 1E + 0 , # Quelldaten TBD - "MaxFlow_Y", # 124
      0x007D : 1E + 0 , # Quelldaten TBD - "MinFlowDate_Y", # 125
      0x007B : 1E + 0 , # Quelldaten TBD - "MaxFlowDate_Y", # 123
      0x0082 : 1E + 0 , # Quelldaten TBD - "MinPower_Y", # 130
      0x0080 : 1E + 0 , # Quelldaten TBD - "MaxPower_Y", # 128
      0x0092 : 1E + 0 , # Quelldaten TBD - "AvgTemp1_Y", # 146
      0x0093 : 1E + 0 , # Quelldaten TBD - "AvgTemp2_Y", # 147
      0x0081 : 1E + 0 , # Quelldaten TBD - "MinPowerDate_Y", # 129
      0x007F : 1E + 0 , # Quelldaten TBD - "MaxPowerDate_Y", # 127
      0x0061 : 1E + 0 , # Quelldaten TBD - "Temp1xm3", # 97
      0x006E : 1E + 0 , # Quelldaten TBD - "Temp2xm3", # 110
      0x0071 : 1E + 0 , # Quelldaten TBD - "Infoevent", # 113
      0x03EC : 1E + 0 , # Quelldaten TBD - "HourCounter", # 1004
      }}

      #################################################### #######################

      Einheiten, bereitgestellt von Erik Jensen

      Einheiten = {
      0 : '' , 1 : 'Wh' , 2 : 'kWh' , 3 : 'MWh' , 4 : 'GWh' , 5 : 'j' , 6 : 'kj' , 7 : 'Mj' ,
      8 : 'Gj' , 9 : 'Cal' , 10 : 'kCal' , 11 : 'Mcal' , 12 : 'Gcal' , 13 : 'varh' ,
      14 : 'kvarh' , 15 : 'Mvarh' , 16 : 'Gvarh' , 17 : 'VAh' , 18 : 'kVAh' ,
      19 : 'MVAh' , 20 : 'GVAh' , 21 : 'kW' , 22 : 'kW' , 23 : 'MW' , 24 : 'GW' ,
      25 : 'kvar' , 26 : 'kvar' , 27 : 'Mvar' , 28 : 'Gvar' , 29 : 'VA' , 30 : 'kVA' ,
      31 : 'MVA' , 32 : 'GVA' , 33 : 'V' , 34 : 'A' , 35 : 'kV' , 36 : 'kA' , 37 : 'C' ,
      38 : 'K' , 39 : 'l' , 40 : 'm3' , 41 : 'l / h' , 42 : 'm3 / h' , 43 : 'm3xC' ,
      44 : 'ton' , 45 : 'ton / h' , 46 : 'h' , 47 : 'hh: mm: ss' , 48 : 'yy: mm: dd' ,
      49 : 'yyyy: mm: dd' , 50 : 'mm: dd' , 51 : '' , 52 : 'Bar' , 53 : 'RTC' ,
      54 : 'ASCII' , 55 : 'm3 x 10' , 56 : 'ton x 10' , 57 : 'GJ x 10' ,
      58 : 'Minuten' , 59 : 'Bitfeld' , 60 : 's' , 61 : 'ms' , 62 : 'Tage' ,
      63 : 'RTC-Q' , 64 : 'Datetime'
      }}

      #################################################### #######################

      Kamstrup verwendet das "echte" CCITT CRC-16

      def crc_1021 ( Nachricht ):
      poly = 0x1021
      reg = 0x0000
      für Byte in Nachricht :
      Maske = 0x80
      while ( Maske > 0 ):
      reg << = 1
      wenn Byte & Maske :
      reg | = 1
      Maske >> = 1
      if reg & 0x10000 :
      reg & = 0xffff
      reg ^ = poly
      Rückgabe reg

      #################################################### #######################

      Bytewerte, die vor der Übertragung maskiert werden müssen

      entkommt = {
      0x06 : Wahr ,
      0x0d : Wahr ,
      0x1b : Wahr ,
      0x40 : Wahr ,
      0x80 : Richtig ,
      }}

      #################################################### #######################

      Und es geht los....

      Klasse Kamstrup ( Objekt ):

      def  __init__ ( self , serial_port ):
          Selbst . debug_fd  =  open ( "/ tmp / _kamstrup" , "a" )
          Selbst . debug_fd . Schreiben ( " \ n \ n Start \ n " )
          Selbst . debug_id  =  Keine
      
          Selbst . ser  =  serial . Seriennummer (
              port  =  serial_port ,
              Baudrate  =  1200 ,
              Zeitüberschreitung  =  5,0 ,
              Bytesize  =  seriell . EIGHTBITS ,
              Parität  =  seriell . PARITY_NONE ,
              Stopbits  =  seriell . STOPBITS_TWO )
      

      xonxoff = 0,

      rtscts = 0)

      timeout = 20

      def  debug ( self , dir , b ):
          für  i  in  b :
              wenn  dir  ! =  Selbst . debug_id :
                  wenn  selbst . debug_id  ! =  Keine :
                      Selbst . debug_fd . schreiben ( " \ n " )
                  Selbst . debug_fd . schreibe ( dir  +  " \ t " )
                  Selbst . debug_id  =  dir
              Selbst . debug_fd . schreibe ( "% 02x"  %  i )
          Selbst . debug_fd . Flush ()
      
      def  debug_msg ( self , msg ):
          wenn  selbst . debug_id  ! =  Keine :
              Selbst . debug_fd . schreiben ( " \ n " )
          Selbst . debug_id  =  "Msg"
          Selbst . debug_fd . schreiben ( "Msg \ t "  +  msg )
          Selbst . debug_fd . Flush ()
      
      def  wr ( self , b ):
          b  =  Bytearray ( b )
          Selbst . Debug ( "Wr" , b );
          Selbst . ser . schreibe ( b )
      
      def  rd ( Selbst ):
          a  =  Selbst . ser . lesen ( 1 )
          wenn  len ( a ) ==  0 :
              Selbst . debug_msg ( "Rx Timeout" )
              Rückgabe  Keine
          b  =  Bytearray ( a ) [ 0 ]
          Selbst . Debug ( "Rd" , Bytearray (( b ,)));
          Rückkehr  b
      
      def  send ( self , pfx , msg ):
          b  =  Bytearray ( msg )
      
          b . anhängen ( 0 )
          b . anhängen ( 0 )
          c  =  crc_1021 ( b )
          b [ - 2 ] =  c  >>  8
          b [ - 1 ] =  c  &  0xff
      
          c  =  bytearray ()
          c . anhängen ( pfx )
          für  i  in  b :
              wenn  ich  in  entkommt :
                  c . anhängen ( 0x1b )
                  c . anhängen ( i  ^  0xff )
              sonst :
                  c . anhängen ( i )
          c . anhängen ( 0x0d )
          Selbst . wr ( c )
      
      def  recv ( Selbst ):
          b  =  bytearray ()
          während  wahr :
              d  =  Selbst . rd ()
              wenn  d  ==  Keine :
                  Rückgabe  Keine
              wenn  d  ==  0x40 :
                  b  =  bytearray ()
              b . anhängen ( d )
              wenn  d  ==  0x0d :
                  brechen
          c  =  bytearray ()
          i  =  1 ;
          während  i  <  len ( b ) -  1 :
              wenn  b [ i ] ==  0x1b :
                  v  =  b [ i  +  1 ] ^  0xff
                  wenn  v  nicht  in  entkommt :
                      Selbst . debug_msg (
                          "Fehlende Flucht% 02x"  %  v )
                  c . anhängen ( v )
                  i  + =  2
              sonst :
                  c . anhängen ( b [ i ])
                  i  + =  1
          wenn  crc_1021 ( c ):
              Selbst . debug_msg ( "CRC-Fehler" )
          return  c [: - 2 ]
      
      def  readvar ( self , nbr ):
          # Ich wäre nicht überrascht, wenn Sie mehr verlangen könnten als
          # eine Variable zu der Zeit, vorausgesetzt, die Länge ist
          # in der Antwort codiert. Habe es nicht versucht.
      
          Selbst . send ( 0x80 , ( 0x3f , 0x10 , 0x01 , nbr  >>  8 , nbr  &  0xff ))
      
          b  =  Selbst . recv ()
          if  b  ==  Keine :
              return ( Keine , Keine )
          wenn  b [ 0 ] ! =  0x3f  oder  b [ 1 ] ! =  0x10 :
              return ( Keine , Keine )
          
          wenn  b [ 2 ] ! =  nbr  >>  8  oder  b [ 3 ] ! =  nbr  &  0xff :
             return ( Keine , Keine )
      
          wenn  b [ 4 ] in  Einheiten :
              u  =  Einheiten [ b [ 4 ]]
          sonst :
              u  =  Keine
      
          # Dekodiere die Mantisse
          x  =  0
          für  i  im  Bereich ( 0 , b [ 5 ]):
              x << = 8
              x | = b [ i  +  7 ]
      
          # Dekodiere den Exponenten
          i  =  b [ 6 ] &  0x3f
          wenn  b [ 6 ] &  0x40 :
              i  =  - i
          i  =  math . pow ( 10 , i )
          wenn  b [ 6 ] &  0x80 :
              i  =  - i
          x  * =  i
      
          wenn  falsch :
              # Drucken debuggen
              s  =  ""
              für  i  in  b [: 4 ]:
                  s  + =  "% 02x"  %  i
              s  + =  "|"
              für  i  in  b [ 4 : 7 ]:
                  s  + =  "% 02x"  %  i
              s  + =  "|"
              für  i  in  b [ 7 :]:
                  s  + =  "% 02x"  %  i
      
              print ( s , "=" , x , Einheiten [ b [ 4 ]])
      
          return ( x , u )
      

      def influxdb_update ( Wert , prot = 'http' , ip = '127.0.0.1' , port = '8086' , db = "smarthome" , querybase = "Energie, Menge = Wärme, Quelle = multical, Typ = Verbrauchswert =" ):
      "" "
      Drücken Sie das Update mit zweiter Genauigkeit auf influxdb
      "" "

      # Der Wert ist in GJ, wir konvertieren nach Joule, um SI in influxdb zu erhalten
      value_joule  =  value * 1000000000
      
      # So etwas wie req_url = "http: // localhost: 8086 / write? Db = smarthometest & präzise = s"
      req_url  =  "{}: // {}: {} / write? db = {} & präzise = s" . Format ( prot , ip , port , db )
      # So etwas wie post_data = "Energie, Typ = Wärme, Gerät = Landisgyr-Wert = 10"
      # Alternativ wie post_data = "energy landisgyr = 10"
      post_data  =  "{} {: d}" . Format ( Abfragebasis , int ( value_joule ))
      
      wenn  Debug  >  0 :
          print ( "Daten '{}' an influxdb senden" . format ( post_data ))
      
      
      versuchen Sie :
          httpresponse  =  Anfragen . post ( req_url , data = post_data , verify = False , timeout = 5 )
      außer  Ausnahme  als  inst :
          print ( "Zählerstand konnte nicht aktualisiert werden: {}" . format ( inst ))
          bestehen
      

      def mqtt_update ( Nutzlast , IP , Port , Benutzer , Passwort , Thema ):
      "" "
      In mqtt veröffentlichen
      http://www.steves-internet-guide.com/publishing-messages-mqtt-client/
      https://pypi.org/project/paho-mqtt/#publishing
      "" "
      # Broker = "192.168.1.184"
      # port = 1883

      client1  =  paho . Client ( client_id = "multical" )
      client1 . username_pw_set ( user , passwd )
      
      versuchen Sie :
          client1 . verbinden ( ip , int ( port ))
      außer :
          print ( 'Verbindung zum mqtt-Broker konnte nicht hergestellt werden' )
      
      versuchen Sie :
          ret  =  client1 . veröffentlichen ( Thema , Nutzlast )
      außer :
          print ( 'mqtt-Wert konnte nicht veröffentlicht werden' )
      

      if name == "main" :

       Importzeit
      
      versuchen Sie :
          comport  =  sys . argv [ 1 ]
      außer  IndexError :
          print ( "Gerät erforderlich. Beispiel: / dev / ttyUSB0" )
          sys . exit ()
      
      # Das vorherige Skript hatte mehrere Argumente und wurde für unterschiedliche Zwecke auskommentiert
      #
      #command = int (sys.argv [2], 0)
      
      versuchen Sie :
          index  =  str ( sys . argv [ 2 ])
      außer  IndexError :
          print ( "Multical Befehle erforderlich." )
          sys . exit ()
      
      index  =  index . split ( ',' )
      
      wenn  Debug  >  0 :
          print ( "Parameter angegeben:" )
          für  i  im  Index :
              print ( "+"  +  i )
      
      foo  =  kamstrup ( comport )
      heat_timestamp  =  datetime . Datum / Uhrzeit . strftime ( datetime . datetime . today (), "% Y-% m-% d% H:% M:% S" )
      
      
      für  i  im  Index :
          ii  =  int ( i )
          multical_var [ ii ]
          x , u  =  foo . readvar ( ii )
      
          # In SI-Einheiten umrechnen
          xsi  =  x  *  multical_var_si [ ii ]
          
          print ( "{}, {}, {}" . Format ( multical_var [ ii ], xsi , u ))
      
      
      # influxdb_update (xsi)
      # mqtt_update (Nutzlast, IP, Port, Benutzer, Passwort, Thema)
      

      />


      Sorry, aber ich weis nicht warum es den Code im Spoiler so komisch anzeigt? :anguished:

      (darum hier der Link)


      verlinkt, leider sagt mir dieses Script ziemlich wenig, und ich bin zu doof es für mich anzupassen. (ob das überhaupt geht?).

      Schön währe es, das Script auf dem Raspi Slave (R3+) zum laufen zu bringen (evtl. alle 15 min mit cronjob?)und die Daten dann in ioBroker zu schreiben (MQTT?)

      Oder stehe ich mit dieser Absicht wieder mal komplett auf dem Schlauch?
      Hatte ja gehofft das es viell. irgend wann mal mit dem Smartmeter- Adapter funktionieren könnte, aber da liege ich wohl auch falsch.

      Oder gibt es zwischenzeitlich von jemanden eine andere Lösung?
      Eine Wired- Lösung habe ich komplett verworfen, da ich in das System selber nicht eingreifen möchte.

      Schöne Grüße
      Christian

      capitaenzC H 2 Antworten Letzte Antwort
      0
      • -cs-- -cs-

        Leider schlief das Thema ein, aber durch andere Projekte würde mich es schon reizen, dies hinzubekommen.

        So, dann möchte ich mal Updaten, evtl. hat sich ja im letzten Jahr was getan, hier meine Erkenntnisse:

        Mit dem Optokopf von Weidmann konnte ich über Windows 10 und dem Programm Metertool von Kamstrup auf den Zähler zugreifen und die Zählerdaten auslesen, leider keine Werte.
        Soweit ich jetzt weis braucht der Multical 403 nicht extra aufwecken oder regelmäßig abgefragt zu werden um nicht abzuschalten (der Multical 402 tat dies ja anscheinend nach ca. 30 min.)

        Des weiteren habe ich im Domoticz – Forum hier ein paar Sachen gefunden.
        (Meine Beiträge in diesem Forum wurden vom Moderator gelöscht, da ich sie angeblich nicht richtig übersetzt hätte)
        In diesem Thread ist am 22.Nov.2020 auch ein Script auf Github



        <
        #! / usr / bin / env python3

        --------------------------------------------- ---------------------------

        "DIE BIERWARENLIZENZ" (Revision 42):

        phk@FreeBSD.ORG hat diese Datei geschrieben. Solange Sie diesen Hinweis behalten

        kann mit diesem Zeug machen, was immer du willst. Wenn wir uns eines Tages treffen und Sie denken

        dieses Zeug ist es wert, du kannst mir dafür ein Bier kaufen. Poul-Henning Kamp

        --------------------------------------------- ---------------------------

        Geändert für Domotics und Einzelanfragen.

        Modifiziert von Ronald van der Meer, Frank Reijn und Paul Bonnemaijers für die

        Kamstrup Multical 402

        Modifiziert von Tim van Werkhoven 20201112 für den generischen Gebrauch (zB mqtt / influxdb).

        Auch überflüssige Zählerablesung aus dem Skript beschnitten, um die Batterie des Zählers zu schonen

        life (vorherige Version hat alle 30 Variablen gelesen und nicht verwendete Daten verworfen)

        Verwendung: file <ComPort>

        aus future import print_function

        Sie benötigen pySerial

        Seriennummer importieren
        Mathe importieren
        sys importieren
        Datum / Uhrzeit importieren
        Import - Anfragen
        Paho importieren . mqtt . Kunde als Paho

        urllib importieren

        importiere urllib.request

        Codecs importieren

        Variablen

        reader = codecs . getreader ( "utf-8" )

        Debug = 1

        multical_var = { # Dezimalzahl im Befehl für Kamstrup Multical
        0x003C : " Wärmeenergie (E1)" , # 60
        0x0050 : "Power" , # 80
        0x0056 : "Temp1" , # 86
        0x0057 : "Temp2" , # 87
        0x0059 : "Tempdiff" , # 89
        0x004A : "Flow" , # 74
        0x0044 : "Volume" , # 68
        0x008D : "MinFlow_M" , # 141
        0x008B : "MaxFlow_M" , # 139
        0x008C : "MinFlowDate_M" , # 140
        0x008A : "MaxFlowDate_M" , # 138
        0x0091 : "MinPower_M" , # 145
        0x008F : "MaxPower_M" , # 143
        0x0095 : "AvgTemp1_M" , # 149
        0x0096 : "AvgTemp2_M" , # 150
        0x0090 : "MinPowerDate_M" , # 144
        0x008E : "MaxPowerDate_M" , # 142
        0x007E : "MinFlow_Y" , # 126
        0x007C : "MaxFlow_Y" , # 124
        0x007D : "MinFlowDate_Y" , # 125
        0x007B : "MaxFlowDate_Y" , # 123
        0x0082 : "MinPower_Y" , # 130
        0x0080 : "MaxPower_Y" , # 128
        0x0092 : "AvgTemp1_Y" , # 146
        0x0093 : "AvgTemp2_Y" , # 147
        0x0081 : "MinPowerDate_Y" , # 129
        0x007F : "MaxPowerDate_Y" , # 127
        0x0061 : "Temp1xm3" , # 97
        0x006E : "Temp2xm3" , # 110
        0x0071 : "Infoevent" , # 113
        0x03EC : "HourCounter" , # 1004
        }}

        multical_var_si = { # Dezimalzahl im Befehl für Kamstrup Multical
        0x003C : 1E + 0 , # Quelldaten bereits in Joule - " Wärmeenergie (E1)", # 60
        0x0050 : 1E-3 , # Quelldaten in MilliWatt - "Power", # 80
        0x0056 : 1E-9 , # Quelldaten in nanoCelcius - "Temp1", # 86
        0x0057 : 1E-9 , # Quelldaten in nanoCelcius - "Temp2", # 87
        0x0059 : 1E-9 , # Quelldaten in nanoCelcius - "Tempdiff", # 89
        0x004A : 1E-12 / 3600 , # Quelldaten Nanoliter / Stunde - "Flow", # 74
        0x0044 : 1E + 0 , # Quelldaten TBD - "Volume", # 68
        0x008D : 1E + 0 , # Quelldaten TBD - "MinFlow_M", # 141
        0x008B : 1E + 0 , # Quelldaten TBD - "MaxFlow_M", # 139
        0x008C : 1E + 0 , # Quelldaten TBD - "MinFlowDate_M", # 140
        0x008A : 1E + 0 , # Quelldaten TBD - "MaxFlowDate_M", # 138
        0x0091 : 1E + 0 , # Quelldaten TBD - "MinPower_M", # 145
        0x008F : 1E + 0 , # Quelldaten TBD - "MaxPower_M", # 143
        0x0095 : 1E + 0 , # Quelldaten TBD - "AvgTemp1_M", # 149
        0x0096 : 1E + 0 , # Quelldaten TBD - "AvgTemp2_M", # 150
        0x0090 : 1E + 0 , # Quelldaten TBD - "MinPowerDate_M", # 144
        0x008E : 1E + 0 , # Quelldaten TBD - "MaxPowerDate_M", # 142
        0x007E : 1E + 0 , # Quelldaten TBD - "MinFlow_Y", # 126
        0x007C : 1E + 0 , # Quelldaten TBD - "MaxFlow_Y", # 124
        0x007D : 1E + 0 , # Quelldaten TBD - "MinFlowDate_Y", # 125
        0x007B : 1E + 0 , # Quelldaten TBD - "MaxFlowDate_Y", # 123
        0x0082 : 1E + 0 , # Quelldaten TBD - "MinPower_Y", # 130
        0x0080 : 1E + 0 , # Quelldaten TBD - "MaxPower_Y", # 128
        0x0092 : 1E + 0 , # Quelldaten TBD - "AvgTemp1_Y", # 146
        0x0093 : 1E + 0 , # Quelldaten TBD - "AvgTemp2_Y", # 147
        0x0081 : 1E + 0 , # Quelldaten TBD - "MinPowerDate_Y", # 129
        0x007F : 1E + 0 , # Quelldaten TBD - "MaxPowerDate_Y", # 127
        0x0061 : 1E + 0 , # Quelldaten TBD - "Temp1xm3", # 97
        0x006E : 1E + 0 , # Quelldaten TBD - "Temp2xm3", # 110
        0x0071 : 1E + 0 , # Quelldaten TBD - "Infoevent", # 113
        0x03EC : 1E + 0 , # Quelldaten TBD - "HourCounter", # 1004
        }}

        #################################################### #######################

        Einheiten, bereitgestellt von Erik Jensen

        Einheiten = {
        0 : '' , 1 : 'Wh' , 2 : 'kWh' , 3 : 'MWh' , 4 : 'GWh' , 5 : 'j' , 6 : 'kj' , 7 : 'Mj' ,
        8 : 'Gj' , 9 : 'Cal' , 10 : 'kCal' , 11 : 'Mcal' , 12 : 'Gcal' , 13 : 'varh' ,
        14 : 'kvarh' , 15 : 'Mvarh' , 16 : 'Gvarh' , 17 : 'VAh' , 18 : 'kVAh' ,
        19 : 'MVAh' , 20 : 'GVAh' , 21 : 'kW' , 22 : 'kW' , 23 : 'MW' , 24 : 'GW' ,
        25 : 'kvar' , 26 : 'kvar' , 27 : 'Mvar' , 28 : 'Gvar' , 29 : 'VA' , 30 : 'kVA' ,
        31 : 'MVA' , 32 : 'GVA' , 33 : 'V' , 34 : 'A' , 35 : 'kV' , 36 : 'kA' , 37 : 'C' ,
        38 : 'K' , 39 : 'l' , 40 : 'm3' , 41 : 'l / h' , 42 : 'm3 / h' , 43 : 'm3xC' ,
        44 : 'ton' , 45 : 'ton / h' , 46 : 'h' , 47 : 'hh: mm: ss' , 48 : 'yy: mm: dd' ,
        49 : 'yyyy: mm: dd' , 50 : 'mm: dd' , 51 : '' , 52 : 'Bar' , 53 : 'RTC' ,
        54 : 'ASCII' , 55 : 'm3 x 10' , 56 : 'ton x 10' , 57 : 'GJ x 10' ,
        58 : 'Minuten' , 59 : 'Bitfeld' , 60 : 's' , 61 : 'ms' , 62 : 'Tage' ,
        63 : 'RTC-Q' , 64 : 'Datetime'
        }}

        #################################################### #######################

        Kamstrup verwendet das "echte" CCITT CRC-16

        def crc_1021 ( Nachricht ):
        poly = 0x1021
        reg = 0x0000
        für Byte in Nachricht :
        Maske = 0x80
        while ( Maske > 0 ):
        reg << = 1
        wenn Byte & Maske :
        reg | = 1
        Maske >> = 1
        if reg & 0x10000 :
        reg & = 0xffff
        reg ^ = poly
        Rückgabe reg

        #################################################### #######################

        Bytewerte, die vor der Übertragung maskiert werden müssen

        entkommt = {
        0x06 : Wahr ,
        0x0d : Wahr ,
        0x1b : Wahr ,
        0x40 : Wahr ,
        0x80 : Richtig ,
        }}

        #################################################### #######################

        Und es geht los....

        Klasse Kamstrup ( Objekt ):

        def  __init__ ( self , serial_port ):
            Selbst . debug_fd  =  open ( "/ tmp / _kamstrup" , "a" )
            Selbst . debug_fd . Schreiben ( " \ n \ n Start \ n " )
            Selbst . debug_id  =  Keine
        
            Selbst . ser  =  serial . Seriennummer (
                port  =  serial_port ,
                Baudrate  =  1200 ,
                Zeitüberschreitung  =  5,0 ,
                Bytesize  =  seriell . EIGHTBITS ,
                Parität  =  seriell . PARITY_NONE ,
                Stopbits  =  seriell . STOPBITS_TWO )
        

        xonxoff = 0,

        rtscts = 0)

        timeout = 20

        def  debug ( self , dir , b ):
            für  i  in  b :
                wenn  dir  ! =  Selbst . debug_id :
                    wenn  selbst . debug_id  ! =  Keine :
                        Selbst . debug_fd . schreiben ( " \ n " )
                    Selbst . debug_fd . schreibe ( dir  +  " \ t " )
                    Selbst . debug_id  =  dir
                Selbst . debug_fd . schreibe ( "% 02x"  %  i )
            Selbst . debug_fd . Flush ()
        
        def  debug_msg ( self , msg ):
            wenn  selbst . debug_id  ! =  Keine :
                Selbst . debug_fd . schreiben ( " \ n " )
            Selbst . debug_id  =  "Msg"
            Selbst . debug_fd . schreiben ( "Msg \ t "  +  msg )
            Selbst . debug_fd . Flush ()
        
        def  wr ( self , b ):
            b  =  Bytearray ( b )
            Selbst . Debug ( "Wr" , b );
            Selbst . ser . schreibe ( b )
        
        def  rd ( Selbst ):
            a  =  Selbst . ser . lesen ( 1 )
            wenn  len ( a ) ==  0 :
                Selbst . debug_msg ( "Rx Timeout" )
                Rückgabe  Keine
            b  =  Bytearray ( a ) [ 0 ]
            Selbst . Debug ( "Rd" , Bytearray (( b ,)));
            Rückkehr  b
        
        def  send ( self , pfx , msg ):
            b  =  Bytearray ( msg )
        
            b . anhängen ( 0 )
            b . anhängen ( 0 )
            c  =  crc_1021 ( b )
            b [ - 2 ] =  c  >>  8
            b [ - 1 ] =  c  &  0xff
        
            c  =  bytearray ()
            c . anhängen ( pfx )
            für  i  in  b :
                wenn  ich  in  entkommt :
                    c . anhängen ( 0x1b )
                    c . anhängen ( i  ^  0xff )
                sonst :
                    c . anhängen ( i )
            c . anhängen ( 0x0d )
            Selbst . wr ( c )
        
        def  recv ( Selbst ):
            b  =  bytearray ()
            während  wahr :
                d  =  Selbst . rd ()
                wenn  d  ==  Keine :
                    Rückgabe  Keine
                wenn  d  ==  0x40 :
                    b  =  bytearray ()
                b . anhängen ( d )
                wenn  d  ==  0x0d :
                    brechen
            c  =  bytearray ()
            i  =  1 ;
            während  i  <  len ( b ) -  1 :
                wenn  b [ i ] ==  0x1b :
                    v  =  b [ i  +  1 ] ^  0xff
                    wenn  v  nicht  in  entkommt :
                        Selbst . debug_msg (
                            "Fehlende Flucht% 02x"  %  v )
                    c . anhängen ( v )
                    i  + =  2
                sonst :
                    c . anhängen ( b [ i ])
                    i  + =  1
            wenn  crc_1021 ( c ):
                Selbst . debug_msg ( "CRC-Fehler" )
            return  c [: - 2 ]
        
        def  readvar ( self , nbr ):
            # Ich wäre nicht überrascht, wenn Sie mehr verlangen könnten als
            # eine Variable zu der Zeit, vorausgesetzt, die Länge ist
            # in der Antwort codiert. Habe es nicht versucht.
        
            Selbst . send ( 0x80 , ( 0x3f , 0x10 , 0x01 , nbr  >>  8 , nbr  &  0xff ))
        
            b  =  Selbst . recv ()
            if  b  ==  Keine :
                return ( Keine , Keine )
            wenn  b [ 0 ] ! =  0x3f  oder  b [ 1 ] ! =  0x10 :
                return ( Keine , Keine )
            
            wenn  b [ 2 ] ! =  nbr  >>  8  oder  b [ 3 ] ! =  nbr  &  0xff :
               return ( Keine , Keine )
        
            wenn  b [ 4 ] in  Einheiten :
                u  =  Einheiten [ b [ 4 ]]
            sonst :
                u  =  Keine
        
            # Dekodiere die Mantisse
            x  =  0
            für  i  im  Bereich ( 0 , b [ 5 ]):
                x << = 8
                x | = b [ i  +  7 ]
        
            # Dekodiere den Exponenten
            i  =  b [ 6 ] &  0x3f
            wenn  b [ 6 ] &  0x40 :
                i  =  - i
            i  =  math . pow ( 10 , i )
            wenn  b [ 6 ] &  0x80 :
                i  =  - i
            x  * =  i
        
            wenn  falsch :
                # Drucken debuggen
                s  =  ""
                für  i  in  b [: 4 ]:
                    s  + =  "% 02x"  %  i
                s  + =  "|"
                für  i  in  b [ 4 : 7 ]:
                    s  + =  "% 02x"  %  i
                s  + =  "|"
                für  i  in  b [ 7 :]:
                    s  + =  "% 02x"  %  i
        
                print ( s , "=" , x , Einheiten [ b [ 4 ]])
        
            return ( x , u )
        

        def influxdb_update ( Wert , prot = 'http' , ip = '127.0.0.1' , port = '8086' , db = "smarthome" , querybase = "Energie, Menge = Wärme, Quelle = multical, Typ = Verbrauchswert =" ):
        "" "
        Drücken Sie das Update mit zweiter Genauigkeit auf influxdb
        "" "

        # Der Wert ist in GJ, wir konvertieren nach Joule, um SI in influxdb zu erhalten
        value_joule  =  value * 1000000000
        
        # So etwas wie req_url = "http: // localhost: 8086 / write? Db = smarthometest & präzise = s"
        req_url  =  "{}: // {}: {} / write? db = {} & präzise = s" . Format ( prot , ip , port , db )
        # So etwas wie post_data = "Energie, Typ = Wärme, Gerät = Landisgyr-Wert = 10"
        # Alternativ wie post_data = "energy landisgyr = 10"
        post_data  =  "{} {: d}" . Format ( Abfragebasis , int ( value_joule ))
        
        wenn  Debug  >  0 :
            print ( "Daten '{}' an influxdb senden" . format ( post_data ))
        
        
        versuchen Sie :
            httpresponse  =  Anfragen . post ( req_url , data = post_data , verify = False , timeout = 5 )
        außer  Ausnahme  als  inst :
            print ( "Zählerstand konnte nicht aktualisiert werden: {}" . format ( inst ))
            bestehen
        

        def mqtt_update ( Nutzlast , IP , Port , Benutzer , Passwort , Thema ):
        "" "
        In mqtt veröffentlichen
        http://www.steves-internet-guide.com/publishing-messages-mqtt-client/
        https://pypi.org/project/paho-mqtt/#publishing
        "" "
        # Broker = "192.168.1.184"
        # port = 1883

        client1  =  paho . Client ( client_id = "multical" )
        client1 . username_pw_set ( user , passwd )
        
        versuchen Sie :
            client1 . verbinden ( ip , int ( port ))
        außer :
            print ( 'Verbindung zum mqtt-Broker konnte nicht hergestellt werden' )
        
        versuchen Sie :
            ret  =  client1 . veröffentlichen ( Thema , Nutzlast )
        außer :
            print ( 'mqtt-Wert konnte nicht veröffentlicht werden' )
        

        if name == "main" :

         Importzeit
        
        versuchen Sie :
            comport  =  sys . argv [ 1 ]
        außer  IndexError :
            print ( "Gerät erforderlich. Beispiel: / dev / ttyUSB0" )
            sys . exit ()
        
        # Das vorherige Skript hatte mehrere Argumente und wurde für unterschiedliche Zwecke auskommentiert
        #
        #command = int (sys.argv [2], 0)
        
        versuchen Sie :
            index  =  str ( sys . argv [ 2 ])
        außer  IndexError :
            print ( "Multical Befehle erforderlich." )
            sys . exit ()
        
        index  =  index . split ( ',' )
        
        wenn  Debug  >  0 :
            print ( "Parameter angegeben:" )
            für  i  im  Index :
                print ( "+"  +  i )
        
        foo  =  kamstrup ( comport )
        heat_timestamp  =  datetime . Datum / Uhrzeit . strftime ( datetime . datetime . today (), "% Y-% m-% d% H:% M:% S" )
        
        
        für  i  im  Index :
            ii  =  int ( i )
            multical_var [ ii ]
            x , u  =  foo . readvar ( ii )
        
            # In SI-Einheiten umrechnen
            xsi  =  x  *  multical_var_si [ ii ]
            
            print ( "{}, {}, {}" . Format ( multical_var [ ii ], xsi , u ))
        
        
        # influxdb_update (xsi)
        # mqtt_update (Nutzlast, IP, Port, Benutzer, Passwort, Thema)
        

        />


        Sorry, aber ich weis nicht warum es den Code im Spoiler so komisch anzeigt? :anguished:

        (darum hier der Link)


        verlinkt, leider sagt mir dieses Script ziemlich wenig, und ich bin zu doof es für mich anzupassen. (ob das überhaupt geht?).

        Schön währe es, das Script auf dem Raspi Slave (R3+) zum laufen zu bringen (evtl. alle 15 min mit cronjob?)und die Daten dann in ioBroker zu schreiben (MQTT?)

        Oder stehe ich mit dieser Absicht wieder mal komplett auf dem Schlauch?
        Hatte ja gehofft das es viell. irgend wann mal mit dem Smartmeter- Adapter funktionieren könnte, aber da liege ich wohl auch falsch.

        Oder gibt es zwischenzeitlich von jemanden eine andere Lösung?
        Eine Wired- Lösung habe ich komplett verworfen, da ich in das System selber nicht eingreifen möchte.

        Schöne Grüße
        Christian

        capitaenzC Offline
        capitaenzC Offline
        capitaenz
        schrieb am zuletzt editiert von
        #3

        @csr Haben auch diesen Wärmezähler bekommen und ich habe folgendes gefunden:

        https://www.letscontrolit.com/forum/viewtopic.php?t=2828
        https://github.com/chipsi007/ESPEasyPluginPlayground/commit/7ae64fabbe05ebf79df5d3cffb9d8ba95a012072

        Das Plugin muss man dann noch in die EasyESP-Firmware bekommen, wozu ich allerdings keine besonders große Lust habe, da man wieder einen Rattenschwanz an Tools/Software installieren muss.

        Vielleicht hilft es dir ja weiter..?

        VG
        Leif

        ioBroker auf Synology DS920+ (SSD Raid / 20GB RAM) im VMM

        1 Antwort Letzte Antwort
        0
        • -cs-- -cs-

          Leider schlief das Thema ein, aber durch andere Projekte würde mich es schon reizen, dies hinzubekommen.

          So, dann möchte ich mal Updaten, evtl. hat sich ja im letzten Jahr was getan, hier meine Erkenntnisse:

          Mit dem Optokopf von Weidmann konnte ich über Windows 10 und dem Programm Metertool von Kamstrup auf den Zähler zugreifen und die Zählerdaten auslesen, leider keine Werte.
          Soweit ich jetzt weis braucht der Multical 403 nicht extra aufwecken oder regelmäßig abgefragt zu werden um nicht abzuschalten (der Multical 402 tat dies ja anscheinend nach ca. 30 min.)

          Des weiteren habe ich im Domoticz – Forum hier ein paar Sachen gefunden.
          (Meine Beiträge in diesem Forum wurden vom Moderator gelöscht, da ich sie angeblich nicht richtig übersetzt hätte)
          In diesem Thread ist am 22.Nov.2020 auch ein Script auf Github



          <
          #! / usr / bin / env python3

          --------------------------------------------- ---------------------------

          "DIE BIERWARENLIZENZ" (Revision 42):

          phk@FreeBSD.ORG hat diese Datei geschrieben. Solange Sie diesen Hinweis behalten

          kann mit diesem Zeug machen, was immer du willst. Wenn wir uns eines Tages treffen und Sie denken

          dieses Zeug ist es wert, du kannst mir dafür ein Bier kaufen. Poul-Henning Kamp

          --------------------------------------------- ---------------------------

          Geändert für Domotics und Einzelanfragen.

          Modifiziert von Ronald van der Meer, Frank Reijn und Paul Bonnemaijers für die

          Kamstrup Multical 402

          Modifiziert von Tim van Werkhoven 20201112 für den generischen Gebrauch (zB mqtt / influxdb).

          Auch überflüssige Zählerablesung aus dem Skript beschnitten, um die Batterie des Zählers zu schonen

          life (vorherige Version hat alle 30 Variablen gelesen und nicht verwendete Daten verworfen)

          Verwendung: file <ComPort>

          aus future import print_function

          Sie benötigen pySerial

          Seriennummer importieren
          Mathe importieren
          sys importieren
          Datum / Uhrzeit importieren
          Import - Anfragen
          Paho importieren . mqtt . Kunde als Paho

          urllib importieren

          importiere urllib.request

          Codecs importieren

          Variablen

          reader = codecs . getreader ( "utf-8" )

          Debug = 1

          multical_var = { # Dezimalzahl im Befehl für Kamstrup Multical
          0x003C : " Wärmeenergie (E1)" , # 60
          0x0050 : "Power" , # 80
          0x0056 : "Temp1" , # 86
          0x0057 : "Temp2" , # 87
          0x0059 : "Tempdiff" , # 89
          0x004A : "Flow" , # 74
          0x0044 : "Volume" , # 68
          0x008D : "MinFlow_M" , # 141
          0x008B : "MaxFlow_M" , # 139
          0x008C : "MinFlowDate_M" , # 140
          0x008A : "MaxFlowDate_M" , # 138
          0x0091 : "MinPower_M" , # 145
          0x008F : "MaxPower_M" , # 143
          0x0095 : "AvgTemp1_M" , # 149
          0x0096 : "AvgTemp2_M" , # 150
          0x0090 : "MinPowerDate_M" , # 144
          0x008E : "MaxPowerDate_M" , # 142
          0x007E : "MinFlow_Y" , # 126
          0x007C : "MaxFlow_Y" , # 124
          0x007D : "MinFlowDate_Y" , # 125
          0x007B : "MaxFlowDate_Y" , # 123
          0x0082 : "MinPower_Y" , # 130
          0x0080 : "MaxPower_Y" , # 128
          0x0092 : "AvgTemp1_Y" , # 146
          0x0093 : "AvgTemp2_Y" , # 147
          0x0081 : "MinPowerDate_Y" , # 129
          0x007F : "MaxPowerDate_Y" , # 127
          0x0061 : "Temp1xm3" , # 97
          0x006E : "Temp2xm3" , # 110
          0x0071 : "Infoevent" , # 113
          0x03EC : "HourCounter" , # 1004
          }}

          multical_var_si = { # Dezimalzahl im Befehl für Kamstrup Multical
          0x003C : 1E + 0 , # Quelldaten bereits in Joule - " Wärmeenergie (E1)", # 60
          0x0050 : 1E-3 , # Quelldaten in MilliWatt - "Power", # 80
          0x0056 : 1E-9 , # Quelldaten in nanoCelcius - "Temp1", # 86
          0x0057 : 1E-9 , # Quelldaten in nanoCelcius - "Temp2", # 87
          0x0059 : 1E-9 , # Quelldaten in nanoCelcius - "Tempdiff", # 89
          0x004A : 1E-12 / 3600 , # Quelldaten Nanoliter / Stunde - "Flow", # 74
          0x0044 : 1E + 0 , # Quelldaten TBD - "Volume", # 68
          0x008D : 1E + 0 , # Quelldaten TBD - "MinFlow_M", # 141
          0x008B : 1E + 0 , # Quelldaten TBD - "MaxFlow_M", # 139
          0x008C : 1E + 0 , # Quelldaten TBD - "MinFlowDate_M", # 140
          0x008A : 1E + 0 , # Quelldaten TBD - "MaxFlowDate_M", # 138
          0x0091 : 1E + 0 , # Quelldaten TBD - "MinPower_M", # 145
          0x008F : 1E + 0 , # Quelldaten TBD - "MaxPower_M", # 143
          0x0095 : 1E + 0 , # Quelldaten TBD - "AvgTemp1_M", # 149
          0x0096 : 1E + 0 , # Quelldaten TBD - "AvgTemp2_M", # 150
          0x0090 : 1E + 0 , # Quelldaten TBD - "MinPowerDate_M", # 144
          0x008E : 1E + 0 , # Quelldaten TBD - "MaxPowerDate_M", # 142
          0x007E : 1E + 0 , # Quelldaten TBD - "MinFlow_Y", # 126
          0x007C : 1E + 0 , # Quelldaten TBD - "MaxFlow_Y", # 124
          0x007D : 1E + 0 , # Quelldaten TBD - "MinFlowDate_Y", # 125
          0x007B : 1E + 0 , # Quelldaten TBD - "MaxFlowDate_Y", # 123
          0x0082 : 1E + 0 , # Quelldaten TBD - "MinPower_Y", # 130
          0x0080 : 1E + 0 , # Quelldaten TBD - "MaxPower_Y", # 128
          0x0092 : 1E + 0 , # Quelldaten TBD - "AvgTemp1_Y", # 146
          0x0093 : 1E + 0 , # Quelldaten TBD - "AvgTemp2_Y", # 147
          0x0081 : 1E + 0 , # Quelldaten TBD - "MinPowerDate_Y", # 129
          0x007F : 1E + 0 , # Quelldaten TBD - "MaxPowerDate_Y", # 127
          0x0061 : 1E + 0 , # Quelldaten TBD - "Temp1xm3", # 97
          0x006E : 1E + 0 , # Quelldaten TBD - "Temp2xm3", # 110
          0x0071 : 1E + 0 , # Quelldaten TBD - "Infoevent", # 113
          0x03EC : 1E + 0 , # Quelldaten TBD - "HourCounter", # 1004
          }}

          #################################################### #######################

          Einheiten, bereitgestellt von Erik Jensen

          Einheiten = {
          0 : '' , 1 : 'Wh' , 2 : 'kWh' , 3 : 'MWh' , 4 : 'GWh' , 5 : 'j' , 6 : 'kj' , 7 : 'Mj' ,
          8 : 'Gj' , 9 : 'Cal' , 10 : 'kCal' , 11 : 'Mcal' , 12 : 'Gcal' , 13 : 'varh' ,
          14 : 'kvarh' , 15 : 'Mvarh' , 16 : 'Gvarh' , 17 : 'VAh' , 18 : 'kVAh' ,
          19 : 'MVAh' , 20 : 'GVAh' , 21 : 'kW' , 22 : 'kW' , 23 : 'MW' , 24 : 'GW' ,
          25 : 'kvar' , 26 : 'kvar' , 27 : 'Mvar' , 28 : 'Gvar' , 29 : 'VA' , 30 : 'kVA' ,
          31 : 'MVA' , 32 : 'GVA' , 33 : 'V' , 34 : 'A' , 35 : 'kV' , 36 : 'kA' , 37 : 'C' ,
          38 : 'K' , 39 : 'l' , 40 : 'm3' , 41 : 'l / h' , 42 : 'm3 / h' , 43 : 'm3xC' ,
          44 : 'ton' , 45 : 'ton / h' , 46 : 'h' , 47 : 'hh: mm: ss' , 48 : 'yy: mm: dd' ,
          49 : 'yyyy: mm: dd' , 50 : 'mm: dd' , 51 : '' , 52 : 'Bar' , 53 : 'RTC' ,
          54 : 'ASCII' , 55 : 'm3 x 10' , 56 : 'ton x 10' , 57 : 'GJ x 10' ,
          58 : 'Minuten' , 59 : 'Bitfeld' , 60 : 's' , 61 : 'ms' , 62 : 'Tage' ,
          63 : 'RTC-Q' , 64 : 'Datetime'
          }}

          #################################################### #######################

          Kamstrup verwendet das "echte" CCITT CRC-16

          def crc_1021 ( Nachricht ):
          poly = 0x1021
          reg = 0x0000
          für Byte in Nachricht :
          Maske = 0x80
          while ( Maske > 0 ):
          reg << = 1
          wenn Byte & Maske :
          reg | = 1
          Maske >> = 1
          if reg & 0x10000 :
          reg & = 0xffff
          reg ^ = poly
          Rückgabe reg

          #################################################### #######################

          Bytewerte, die vor der Übertragung maskiert werden müssen

          entkommt = {
          0x06 : Wahr ,
          0x0d : Wahr ,
          0x1b : Wahr ,
          0x40 : Wahr ,
          0x80 : Richtig ,
          }}

          #################################################### #######################

          Und es geht los....

          Klasse Kamstrup ( Objekt ):

          def  __init__ ( self , serial_port ):
              Selbst . debug_fd  =  open ( "/ tmp / _kamstrup" , "a" )
              Selbst . debug_fd . Schreiben ( " \ n \ n Start \ n " )
              Selbst . debug_id  =  Keine
          
              Selbst . ser  =  serial . Seriennummer (
                  port  =  serial_port ,
                  Baudrate  =  1200 ,
                  Zeitüberschreitung  =  5,0 ,
                  Bytesize  =  seriell . EIGHTBITS ,
                  Parität  =  seriell . PARITY_NONE ,
                  Stopbits  =  seriell . STOPBITS_TWO )
          

          xonxoff = 0,

          rtscts = 0)

          timeout = 20

          def  debug ( self , dir , b ):
              für  i  in  b :
                  wenn  dir  ! =  Selbst . debug_id :
                      wenn  selbst . debug_id  ! =  Keine :
                          Selbst . debug_fd . schreiben ( " \ n " )
                      Selbst . debug_fd . schreibe ( dir  +  " \ t " )
                      Selbst . debug_id  =  dir
                  Selbst . debug_fd . schreibe ( "% 02x"  %  i )
              Selbst . debug_fd . Flush ()
          
          def  debug_msg ( self , msg ):
              wenn  selbst . debug_id  ! =  Keine :
                  Selbst . debug_fd . schreiben ( " \ n " )
              Selbst . debug_id  =  "Msg"
              Selbst . debug_fd . schreiben ( "Msg \ t "  +  msg )
              Selbst . debug_fd . Flush ()
          
          def  wr ( self , b ):
              b  =  Bytearray ( b )
              Selbst . Debug ( "Wr" , b );
              Selbst . ser . schreibe ( b )
          
          def  rd ( Selbst ):
              a  =  Selbst . ser . lesen ( 1 )
              wenn  len ( a ) ==  0 :
                  Selbst . debug_msg ( "Rx Timeout" )
                  Rückgabe  Keine
              b  =  Bytearray ( a ) [ 0 ]
              Selbst . Debug ( "Rd" , Bytearray (( b ,)));
              Rückkehr  b
          
          def  send ( self , pfx , msg ):
              b  =  Bytearray ( msg )
          
              b . anhängen ( 0 )
              b . anhängen ( 0 )
              c  =  crc_1021 ( b )
              b [ - 2 ] =  c  >>  8
              b [ - 1 ] =  c  &  0xff
          
              c  =  bytearray ()
              c . anhängen ( pfx )
              für  i  in  b :
                  wenn  ich  in  entkommt :
                      c . anhängen ( 0x1b )
                      c . anhängen ( i  ^  0xff )
                  sonst :
                      c . anhängen ( i )
              c . anhängen ( 0x0d )
              Selbst . wr ( c )
          
          def  recv ( Selbst ):
              b  =  bytearray ()
              während  wahr :
                  d  =  Selbst . rd ()
                  wenn  d  ==  Keine :
                      Rückgabe  Keine
                  wenn  d  ==  0x40 :
                      b  =  bytearray ()
                  b . anhängen ( d )
                  wenn  d  ==  0x0d :
                      brechen
              c  =  bytearray ()
              i  =  1 ;
              während  i  <  len ( b ) -  1 :
                  wenn  b [ i ] ==  0x1b :
                      v  =  b [ i  +  1 ] ^  0xff
                      wenn  v  nicht  in  entkommt :
                          Selbst . debug_msg (
                              "Fehlende Flucht% 02x"  %  v )
                      c . anhängen ( v )
                      i  + =  2
                  sonst :
                      c . anhängen ( b [ i ])
                      i  + =  1
              wenn  crc_1021 ( c ):
                  Selbst . debug_msg ( "CRC-Fehler" )
              return  c [: - 2 ]
          
          def  readvar ( self , nbr ):
              # Ich wäre nicht überrascht, wenn Sie mehr verlangen könnten als
              # eine Variable zu der Zeit, vorausgesetzt, die Länge ist
              # in der Antwort codiert. Habe es nicht versucht.
          
              Selbst . send ( 0x80 , ( 0x3f , 0x10 , 0x01 , nbr  >>  8 , nbr  &  0xff ))
          
              b  =  Selbst . recv ()
              if  b  ==  Keine :
                  return ( Keine , Keine )
              wenn  b [ 0 ] ! =  0x3f  oder  b [ 1 ] ! =  0x10 :
                  return ( Keine , Keine )
              
              wenn  b [ 2 ] ! =  nbr  >>  8  oder  b [ 3 ] ! =  nbr  &  0xff :
                 return ( Keine , Keine )
          
              wenn  b [ 4 ] in  Einheiten :
                  u  =  Einheiten [ b [ 4 ]]
              sonst :
                  u  =  Keine
          
              # Dekodiere die Mantisse
              x  =  0
              für  i  im  Bereich ( 0 , b [ 5 ]):
                  x << = 8
                  x | = b [ i  +  7 ]
          
              # Dekodiere den Exponenten
              i  =  b [ 6 ] &  0x3f
              wenn  b [ 6 ] &  0x40 :
                  i  =  - i
              i  =  math . pow ( 10 , i )
              wenn  b [ 6 ] &  0x80 :
                  i  =  - i
              x  * =  i
          
              wenn  falsch :
                  # Drucken debuggen
                  s  =  ""
                  für  i  in  b [: 4 ]:
                      s  + =  "% 02x"  %  i
                  s  + =  "|"
                  für  i  in  b [ 4 : 7 ]:
                      s  + =  "% 02x"  %  i
                  s  + =  "|"
                  für  i  in  b [ 7 :]:
                      s  + =  "% 02x"  %  i
          
                  print ( s , "=" , x , Einheiten [ b [ 4 ]])
          
              return ( x , u )
          

          def influxdb_update ( Wert , prot = 'http' , ip = '127.0.0.1' , port = '8086' , db = "smarthome" , querybase = "Energie, Menge = Wärme, Quelle = multical, Typ = Verbrauchswert =" ):
          "" "
          Drücken Sie das Update mit zweiter Genauigkeit auf influxdb
          "" "

          # Der Wert ist in GJ, wir konvertieren nach Joule, um SI in influxdb zu erhalten
          value_joule  =  value * 1000000000
          
          # So etwas wie req_url = "http: // localhost: 8086 / write? Db = smarthometest & präzise = s"
          req_url  =  "{}: // {}: {} / write? db = {} & präzise = s" . Format ( prot , ip , port , db )
          # So etwas wie post_data = "Energie, Typ = Wärme, Gerät = Landisgyr-Wert = 10"
          # Alternativ wie post_data = "energy landisgyr = 10"
          post_data  =  "{} {: d}" . Format ( Abfragebasis , int ( value_joule ))
          
          wenn  Debug  >  0 :
              print ( "Daten '{}' an influxdb senden" . format ( post_data ))
          
          
          versuchen Sie :
              httpresponse  =  Anfragen . post ( req_url , data = post_data , verify = False , timeout = 5 )
          außer  Ausnahme  als  inst :
              print ( "Zählerstand konnte nicht aktualisiert werden: {}" . format ( inst ))
              bestehen
          

          def mqtt_update ( Nutzlast , IP , Port , Benutzer , Passwort , Thema ):
          "" "
          In mqtt veröffentlichen
          http://www.steves-internet-guide.com/publishing-messages-mqtt-client/
          https://pypi.org/project/paho-mqtt/#publishing
          "" "
          # Broker = "192.168.1.184"
          # port = 1883

          client1  =  paho . Client ( client_id = "multical" )
          client1 . username_pw_set ( user , passwd )
          
          versuchen Sie :
              client1 . verbinden ( ip , int ( port ))
          außer :
              print ( 'Verbindung zum mqtt-Broker konnte nicht hergestellt werden' )
          
          versuchen Sie :
              ret  =  client1 . veröffentlichen ( Thema , Nutzlast )
          außer :
              print ( 'mqtt-Wert konnte nicht veröffentlicht werden' )
          

          if name == "main" :

           Importzeit
          
          versuchen Sie :
              comport  =  sys . argv [ 1 ]
          außer  IndexError :
              print ( "Gerät erforderlich. Beispiel: / dev / ttyUSB0" )
              sys . exit ()
          
          # Das vorherige Skript hatte mehrere Argumente und wurde für unterschiedliche Zwecke auskommentiert
          #
          #command = int (sys.argv [2], 0)
          
          versuchen Sie :
              index  =  str ( sys . argv [ 2 ])
          außer  IndexError :
              print ( "Multical Befehle erforderlich." )
              sys . exit ()
          
          index  =  index . split ( ',' )
          
          wenn  Debug  >  0 :
              print ( "Parameter angegeben:" )
              für  i  im  Index :
                  print ( "+"  +  i )
          
          foo  =  kamstrup ( comport )
          heat_timestamp  =  datetime . Datum / Uhrzeit . strftime ( datetime . datetime . today (), "% Y-% m-% d% H:% M:% S" )
          
          
          für  i  im  Index :
              ii  =  int ( i )
              multical_var [ ii ]
              x , u  =  foo . readvar ( ii )
          
              # In SI-Einheiten umrechnen
              xsi  =  x  *  multical_var_si [ ii ]
              
              print ( "{}, {}, {}" . Format ( multical_var [ ii ], xsi , u ))
          
          
          # influxdb_update (xsi)
          # mqtt_update (Nutzlast, IP, Port, Benutzer, Passwort, Thema)
          

          />


          Sorry, aber ich weis nicht warum es den Code im Spoiler so komisch anzeigt? :anguished:

          (darum hier der Link)


          verlinkt, leider sagt mir dieses Script ziemlich wenig, und ich bin zu doof es für mich anzupassen. (ob das überhaupt geht?).

          Schön währe es, das Script auf dem Raspi Slave (R3+) zum laufen zu bringen (evtl. alle 15 min mit cronjob?)und die Daten dann in ioBroker zu schreiben (MQTT?)

          Oder stehe ich mit dieser Absicht wieder mal komplett auf dem Schlauch?
          Hatte ja gehofft das es viell. irgend wann mal mit dem Smartmeter- Adapter funktionieren könnte, aber da liege ich wohl auch falsch.

          Oder gibt es zwischenzeitlich von jemanden eine andere Lösung?
          Eine Wired- Lösung habe ich komplett verworfen, da ich in das System selber nicht eingreifen möchte.

          Schöne Grüße
          Christian

          H Offline
          H Offline
          HelmutLinner
          schrieb am zuletzt editiert von
          #4

          @csr Hallo
          Ich habe eine Multical402 und verwende den Volkszähler TTL Lesekopf mit einem ESP8266 und dieser Software https://github.com/sebbebebbe/Multical402MQTT
          Um die Daten per MQTT direkt in Iobroker zu bekommen.
          Bei meinem 402 Schaltet es sich nach einer Zeit aus aber bei deiner sollte es ohne Probleme funktionieren.

          M 1 Antwort Letzte Antwort
          0
          • H HelmutLinner

            @csr Hallo
            Ich habe eine Multical402 und verwende den Volkszähler TTL Lesekopf mit einem ESP8266 und dieser Software https://github.com/sebbebebbe/Multical402MQTT
            Um die Daten per MQTT direkt in Iobroker zu bekommen.
            Bei meinem 402 Schaltet es sich nach einer Zeit aus aber bei deiner sollte es ohne Probleme funktionieren.

            M Offline
            M Offline
            maibua
            schrieb am zuletzt editiert von
            #5

            @helmutlinner said in Kamstrup Multical 403 mit Raspberry Pi auslesen:

            Volkszähler TTL Lesekopf

            Ich habe ebenfalls einen Multical 403 und möchte die Daten gerne auslesen. Habt ihr das mit dem Volkszähler TTL Lesekopf irgendwie hinbekommen?

            1 Antwort Letzte Antwort
            0
            Antworten
            • In einem neuen Thema antworten
            Anmelden zum Antworten
            • Älteste zuerst
            • Neuste zuerst
            • Meiste Stimmen


            Support us

            ioBroker
            Community Adapters
            Donate

            348

            Online

            32.5k

            Benutzer

            81.7k

            Themen

            1.3m

            Beiträge
            Community
            Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen | Einwilligungseinstellungen
            ioBroker Community 2014-2025
            logo
            • Anmelden

            • Du hast noch kein Konto? Registrieren

            • Anmelden oder registrieren, um zu suchen
            • Erster Beitrag
              Letzter Beitrag
            0
            • Home
            • Aktuell
            • Tags
            • Ungelesen 0
            • Kategorien
            • Unreplied
            • Beliebt
            • GitHub
            • Docu
            • Hilfe