Weiter zum Inhalt
  • Home
  • Aktuell
  • Tags
  • 0 Ungelesen 0
  • Kategorien
  • Unreplied
  • Beliebt
  • GitHub
  • Docu
  • Hilfe
Skins
  • Hell
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dunkel
  • 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. Skripten / Logik
  4. JavaScript
  5. [Skriptbeispiel] python Aufruf modbus-poll

NEWS

  • wichtiges UPDATE für controller 7.2.2 im stable
    HomoranH
    Homoran
    8
    1
    502

  • Neues YouTube-Video: Visualisierung im Devices-Adapter
    BluefoxB
    Bluefox
    15
    1
    2.7k

  • Neuer ioBroker-Blog online: Monatsrückblick März/April 2026
    BluefoxB
    Bluefox
    8
    1
    2.9k

[Skriptbeispiel] python Aufruf modbus-poll

Geplant Angeheftet Gesperrt Verschoben JavaScript
2 Beiträge 2 Kommentatoren 4.0k Aufrufe
  • Ä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.
  • S Offline
    S Offline
    starfish
    schrieb am zuletzt editiert von
    #1

    <size size="150">Beispiel für modbus/tcp</size>

    (erweiterte Variante für modbus/rtu im 2. Post)

    Aufgabenstellung: Auslesen von Verbrauchsdaten aus einem Energiemessgerät Siemens PAC3200 über modbus/tcp und Import in iobroker.

    möglich geworden ist dieses Projekt durch das durch bluefox gefixte javascript zur Ausführung von python-scripten.

    Voraussetzung: python (hier 2.7.9) mit pip oder easy_install zur Installation von pymodbus.

    Meine Wahl fiel auf pymodbus, da dies sehr viel besser als z.B. modbus-tk dokumentiert ist.

    pymodbus ist so vielseitig, dass sich nahezu jede Aufgabe im modbus-Bereich lösen lässt.

    https://github.com/bashwork/pymodbus

    https://code.google.com/p/pymodbus/

    Doku https://pythonhosted.org/pymodbus/

    dieses Skript in den javascript adapter einfügen

        createState('pythonResult', '');
        schedule("*/5 * * * *", function () {
             var python = require('child_process').spawn('python',
             // second argument is array of parameters, e.g.:
             ["/opt/python/kwh.py"]);
             var result = '';
             python.stdout.on('data', function(data){ result += data.toString(); });
             python.on('close', function(code){
               if (code !== 0) { 
                     log('Error: ' + code);
               } else {
                     log(result);
                     setState('pythonResult', result, true);
               }
             });
        });
    
    

    dadurch wird im 5 Min. Intervall das python Skript /opt/python/kwh.sh aufgerufen, welches via modbus/tcp den Inhalt des Registers 2801 im PAC3200 abruft und den Wert über stdout an das obige javascript zurückgibt.

    #!/usr/bin/env python
    from pymodbus.constants import Endian
    from pymodbus.payload import BinaryPayloadDecoder
    from pymodbus.client.sync import ModbusTcpClient as ModbusClient
    
    siemens = ModbusClient(host='192.168.0.68', port=502)
    
    result = siemens.read_holding_registers(2801, 2, unit=1)
    
    decoder = BinaryPayloadDecoder.fromRegisters(result.registers, endian=Endian.Big)
    a= decoder.decode_32bit_float() 
    
    # etwas Formatierung kilowattstunden
    
    print ("%.2f" % (a/1000)) #KWh
    siemens.close()
    
    

    als Abfallprodukt ergab sich folgende Lösung zum Import der Daten in Zabbix als trapper item mittels zabbix_sender. (naja, eigentlich war dies zuerst - den iobroker-import habe ich davon abgeleitet.)

    ! –---------------------------------------------------------------------
    ! #!/usr/bin/env python
    ! from pymodbus.constants import Endian
    ! from pymodbus.payload import BinaryPayloadDecoder
    ! from pymodbus.client.sync import ModbusTcpClient as ModbusClient
    ! siemens = ModbusClient(host='192.168.0.68', port=502)
    ! result = siemens.read_holding_registers(2801, 2, unit=1)
    ! decoder = BinaryPayloadDecoder.fromRegisters(result.registers, endian=Endian.Big)
    ! a= decoder.decode_32bit_float()
    ! # active energy Zaehler kilowattstunden
    ! # formatiert für Zabbix_sender host und key (item - key) müssen in Zabbix vorhanden sein
    ! # siehe zabbix doku trapper item
    ! print "host key " + ("%.2f" % (a/1000)) #KWh
    ! siemens.close()
    ! -------------------------------------------------------------------------
    ! shell script durch cron alle 5 min gestartet (bzw. nach Bedarf)
    ! #!/bin/sh
    ! python /root/kwh.py > /root/kwh.log
    ! zabbix_sender -z 127.0.0.1 -i /root/kwh.log >/dev/nul
    ! -------------------------------------------------------------------------

    sicher lässt sich dies oder jenes eleganter coden, für mich efüllts den Zweck vollauf.

    1 Antwort Letzte Antwort
    0
    • Y Offline
      Y Offline
      ykuendig
      schrieb am zuletzt editiert von
      #2

      Dank @starfish haben wir nun eine Möglichkeit modbus Daten zu pollen. Das ist uU ganz hilfreich (zumindest bis ein Modbus-Adapter fertig ist).

      Ich habe für meine Zwecke das Python-Script angepasst, da ich serielle Geräte am Bus habe. Zudem wollte ich mehrere Werte abfragen.

      Hier das Python-Script 'pymodhaus.py' (liegt bei mir in /home/pi/modbus-crawler):

      #!/usr/bin/env python
      import sys, time, json
      from pymodbus.constants import Endian
      from pymodbus.payload import BinaryPayloadDecoder
      from pymodbus.client.sync import ModbusSerialClient as ModbusClient
      from pymodbus.transaction import ModbusRtuFramer
      
      def decode32(decval):
      	decoder = BinaryPayloadDecoder.fromRegisters(decval.registers, endian=Endian.Big)
      	return decoder.decode_32bit_float()
      
      def decode64(decval):
      	decoder = BinaryPayloadDecoder.fromRegisters(decval.registers, endian=Endian.Big)
      	return decoder.decode_64bit_int()
      
      client = ModbusClient(method='rtu', port='/dev/ttyUSB0', stopbits=1, bytesize=8, timeout=0.05, baudrate=19200, parity='N')
      connection = client.connect()
      #print "Connection: ", connection * Only for debug
      
      try:
      	timestamp = str(time.time()).split('.')[0]
      	# iEM3155 Haus --> Adresse immer 1 kleiner als im Schneider Datenblatt; weiss der Geier warum
      	# HausL01 = decode32(client.read_holding_registers(3028-1, 2, unit=10))
      	# HausL02 = decode32(client.read_holding_registers(3030-1, 2, unit=10))
      	# HausL03 = decode32(client.read_holding_registers(3032-1, 2, unit=10))
      	HausLNM = decode32(client.read_holding_registers(3036-1, 2, unit=10))
      	HausP01 = decode32(client.read_holding_registers(3054-1, 2, unit=10)) * 1000
      	HausP02 = decode32(client.read_holding_registers(3056-1, 2, unit=10)) * 1000
      	HausP03 = decode32(client.read_holding_registers(3058-1, 2, unit=10)) * 1000
      	HausPower = decode32(client.read_holding_registers(3060-1, 2, unit=10)) * 1000
      	# HausPowerB = decode32(client.read_holding_registers(3068-1, 2, unit=10)) * 1000
      	# HausPowerS = decode32(client.read_holding_registers(3076-1, 2, unit=10)) * 1000
      	HausImport = decode64(client.read_holding_registers(3204-1, 4, unit=10)) / 1000
      	HausExport = decode64(client.read_holding_registers(3208-1, 4, unit=10)) / 1000
      except:
      	print 6
      else:
      	json_string = json.dumps({'ts': timestamp, 'HausLNM': round(HausLNM,2), 
      		'HausP01': round(HausP01,0), 'HausP02': round(HausP02,0), 'HausP03': round(HausP03,0), 
      		'HausPower': round(HausPower,0),'HausImport': HausImport, 'HausExport': HausExport})
      	print json_string
      
      client.close()
      

      Nun zum iobroker.javascript:

      // Create Datenpunkte für PV-Anlage
      createState('javascript.1.Solar.pi1Result', '');
      createState('javascript.1.Solar.modPoll', 1);
      // Create Datenpunkte für Schneider EnergyMeter 'Haus'
      createState('javascript.1.Solar.Schneider.HausLNM', 0);
      createState('javascript.1.Solar.Schneider.HausP01', 0);
      createState('javascript.1.Solar.Schneider.HausP02', 0);
      createState('javascript.1.Solar.Schneider.HausP03', 0);
      createState('javascript.1.Solar.Schneider.HausPower', 0);
      createState('javascript.1.Solar.Schneider.HausImport', 0);
      createState('javascript.1.Solar.Schneider.HausExport', 0);
      createState('javascript.1.Solar.Schneider.HausTimeStamp', 0);
      
      schedule({astro: "sunrise"}, function () {
          setState('javascript.1.Solar.modPoll', 1, true);
      });
      schedule({astro: "sunset"}, function () {
          setState('javascript.1.Solar.modPoll', 0, true);
      });
      
      //Schedule Script Run Haus
      schedule("*/1 * * * *", function (Haus) {
          var enabled = getState("javascript.1.Solar.modPoll"/*javascript.1.Solar.modPoll*/).val;
          if (enabled == 1) {
              var python = require('child_process').spawn('python', ["/home/pi/modbus-crawler/pymodhaus.py"]);
              // second argument is array of parameters, e.g.:
              var result = '';
              python.stdout.on('data', function(data){ result += data.toString(); });
              python.on('close', function(code1){
                  if (code1 !== 0) { 
                      log('Error: ' + code1, 'error');
                  } else {
                      if (result == 6) {
                          log('Error: Fehler im Modbus Python Script -Haus-', 'warn');
                      } else {
                          log('Modbus Python Script -Haus- erfolgreich gelaufen, Werte akzeptiert');
                          setState('javascript.1.Solar.pi1Result', result);
                          var solar1 = JSON.parse(result);
                          setState('javascript.1.Solar.Schneider.HausLNM', solar1.HausLNM, true);
                          setState('javascript.1.Solar.Schneider.HausP01', solar1.HausP01, true);
                          setState('javascript.1.Solar.Schneider.HausP02', solar1.HausP02, true);
                          setState('javascript.1.Solar.Schneider.HausP03', solar1.HausP03, true);
                          setState('javascript.1.Solar.Schneider.HausPower', solar1.HausPower, true);
                          setState('javascript.1.Solar.Schneider.HausImport', solar1.HausImport, true);
                          setState('javascript.1.Solar.Schneider.HausExport', solar1.HausExport, true);
                          setState('javascript.1.Solar.Schneider.HausTimeStamp', solar1.ts, true);
                      }
                  }
              });
          }
      });
      
      

      Etwas komplexer hat sich dann der Umstand erwiesen, dass ich das Script (mangels tcp) lokal am Solar-PI laufen lassen muss. Daher musste ein iobroker als remote-host auf den PI. Aber dass ist ein ganz anderes Thema.

      Version 0.1.0 2015-06-22 First release

      Gruss Yves

      1 Antwort Letzte Antwort
      0

      Hey! Du scheinst an dieser Unterhaltung interessiert zu sein, hast aber noch kein Konto.

      Hast du es satt, bei jedem Besuch durch die gleichen Beiträge zu scrollen? Wenn du dich für ein Konto anmeldest, kommst du immer genau dorthin zurück, wo du zuvor warst, und kannst dich über neue Antworten benachrichtigen lassen (entweder per E-Mail oder Push-Benachrichtigung). Du kannst auch Lesezeichen speichern und Beiträge positiv bewerten, um anderen Community-Mitgliedern deine Wertschätzung zu zeigen.

      Mit deinem Input könnte dieser Beitrag noch besser werden 💗

      Registrieren Anmelden
      Antworten
      • In einem neuen Thema antworten
      Anmelden zum Antworten
      • Älteste zuerst
      • Neuste zuerst
      • Meiste Stimmen


      Support us

      ioBroker
      Community Adapters
      Donate

      708

      Online

      33.0k

      Benutzer

      83.3k

      Themen

      1.3m

      Beiträge
      Community
      Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen | Einwilligungseinstellungen
      ioBroker Community 2014-2026
      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