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

  1. ioBroker Community Home
  2. Deutsch
  3. Skripten / Logik
  4. JavaScript
  5. [Skriptbeispiel] python Aufruf modbus-poll

NEWS

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

  • Monatsrückblick – September 2025
    BluefoxB
    Bluefox
    13
    1
    2.0k

  • Neues Video "KI im Smart Home" - ioBroker plus n8n
    BluefoxB
    Bluefox
    15
    1
    2.5k

[Skriptbeispiel] python Aufruf modbus-poll

Geplant Angeheftet Gesperrt Verschoben JavaScript
2 Beiträge 2 Kommentatoren 3.8k 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
      Antworten
      • In einem neuen Thema antworten
      Anmelden zum Antworten
      • Älteste zuerst
      • Neuste zuerst
      • Meiste Stimmen


      Support us

      ioBroker
      Community Adapters
      Donate

      413

      Online

      32.4k

      Benutzer

      81.4k

      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