Produkte
Service & Support
Branchen & Lösungen
Unternehmen
Version 1.0
·
Zuletzt bearbeitet am 2025-08-27

Zugriff auf BNI-Daten über Modbus TCP mit der Programmiersprache Python

1. Einführung

Der Zweck dieses technischen Anwendungshinweises ist es, die Schritte zu erklären, die notwendig sind, um auf die Balluff IO-Link-Master-Konfiguration und ihre Prozesseingangs- und -ausgangsdaten mit der Programmiersprache Python über das Modbus/TCP-Feldbusprotokoll zuzugreifen.

Ein Überblick über die verfügbaren Daten findet sich auf Seite 75 des IO-Link-Master-Konfigurationshandbuchs in Tabelle 6-2 - siehe unten.

A screenshot of a computer programAI-generated content may be incorrect.

2. Einrichtung

Dieses Kapitel beschreibt sowohl die Hardware- als auch die Software-Einrichtung.

2.1. Hardware

Dieser technische Anwendungshinweis bezieht sich auf die IO-Link-Master-Familie der Black- und Silver-Line von Balluff mit einer Firmware-Revision 1.2.0 oder höher, die Multi-Protokoll-Kommunikation einschließlich Modbus/TCP unterstützt.

In den in dieser technischen Applikationsschrift gezeigten Beispielen wurde folgende Hardware verwendet:

  1. IO-Link-Master
    1. BNI00L3 p/n BNI XG3-508-0B5-R067
      1. HW rev. 1.0.1
      2. FW rev. 1.2.0
    2. IO-Link Master IP-Adresse: 192.168.1.1
  2. An den IO-Link-Master angeschlossene IO-Link-Geräte
    1. Port 1 - Balluff Condition Monitoring Sensor
      1. BCM0003 p/n BCM R16E-004-CI02-01,5-S4
      2. Prozessdatenprofil - Schwingungsgeschwindigkeit - 1
    2. Anschluss 2 - Balluff Smart Light
      1. BNI0085 p/n BNI IOL-802-102-Z037
      2. 5-Segment-Smart-Light mit Buzzer

 

2.2. Software

Verwendete IDE (Integrierte Entwicklungsumgebung):

PyCharm 2025.2
Build #PY-252.23892.439, erstellt am 4. August 2025
Quellcode-Revision: e7a5644c801f1
Lizenziert für Testbenutzer
Abonnement ist bis zum 10. September 2025 aktiv.
Laufzeitversion: 21.0.7+6-b1038.58 amd64 (JCEF 122.1.9)
VM: OpenJDK 64-Bit Server VM von JetBrains s.r.o.
Toolkit: sun.awt.windows.WToolkit
Windows 10.0
GC: G1 Young Generation, G1 Concurrent GC, G1 Old Generation
Speicher: 2048M
Cores: 4
Registry:
ide.experimental.ui=true

Hinweis:
Es können auch andere IDEs verwendet werden.

3. Testen der Kommunikation mit einem IO-Link-Master und Lesen von Identifikationsdaten

In diesem Beispielcode werden die Modbus-Kommunikation mit dem IO-Link-Master unter Verwendung der "Client"-Funktion geöffnet, Identifikationsdaten im Holdingregister ab Adresse 10 und einer Länge von 4 Wörtern gelesen und in ASCII konvertiert.

 

Beispiel-Code:


import struct
from pyModbusTCP.client import ModbusClient

client = ModbusClient(host="192.168.1.1", port=502, auto_open=True)

regs = client.read_holding_registers(10, 4)
product_order_code = b''.join(struct.pack('<H', r) for r in regs).decode('ascii').strip('\x00')

print(client.host, client.port,client.unit_id, client.open())
print("Raw_register_data:", regs)
print("Product order code:", product_order_code)

Ergebnis:

92.168.1.1 502 1 True
Raw_register_data: [20034, 12361, 19504, 51]
Produkt-Bestellcode: BNI00L3

4. Lesen der Richtung des IO-Link-Ports

In diesem Kapitel wird die Richtung von IO-Link Port 1 gelesen.

Der Beispiel-Code kann modifiziert werden, um die Richtung anderer Ports zu lesen.

Weitere Informationen sind im IO-Link Konfigurationshandbuch zu finden:

 

Beispiel-Code:

from pyModbusTCP.client import ModbusClient

# Modbus-Client erstellen
client = ModbusClient(host="192.168.1.1", port=502, auto_open=True)

# 1 Register ab 3001 lesen
regs = client.read_holding_registers(9101, 1)

if regs: # prüfen, ob Lesen erfolgreich war
reg_val = regs[0] # den ersten (und einzigen) Registerwert ermitteln

# Low-Byte (Bits 0-7) extrahieren
byte0 = reg_val & 0xFF

# High-Byte (Bits 8-15) extrahieren
byte1 = (reg_val >> 8) & 0xFF

print(f "Register: 0x{reg_val:04X}")
print(f "Byte 0 (low) : 0x{byte0:02X} ({byte0})")
print(f "Byte 1 (high): 0x{byte1:02X} ({byte1})")
else:
print("❌ Failed to read register")

if byte1 == 0x00:
print("port 1 - Deactivated")
else:
# code if condition1 is False
client.close()

if byte1 == 0x01:
print("port 1 - IOL Manual")
else:
# code if condition1 is False
client.close()

if byte1 == 0x02:
print("port 1 - IOL Auto")
else:
# code if condition1 is False
client.close()

if byte1 == 0x03:
print("port 1 - Digital IN")
else:
# code if condition1 is False
client.close()

if byte1 == 0x04:
print("port 1 - Digital OUT")
else:
client.close()

Ergebnis:

Register: 0x0201
Byte 0 (niedrig) : 0x01 (1)
Byte 1 (high): 0x02 (2)
Anschluss 1 - IOL Auto

 

5. Einstellung der Richtung des IO-Link-Ports

In diesem Kapitel wird die Richtung von IO-Link Port 1 gesetzt (geschreiben) .

Der Beispiel-Code kann modifiziert werden, um die Richtung der anderen Ports einzustellen (zu schreiben).

Beispiel-Code:

from pyModbusTCP.client import ModbusClient

client = ModbusClient(host="192.168.1.1", port=502, auto_open=True)

# Schritt 1: Lesen des aktuellen Wertes von Register 9101 - IOL Port 1 Konfiguration
regs = client.read_holding_registers(9101, 1)

if regs:
current_val = regs[0]
print(f "Aktuelles Register 9101: {current_val} (0x{current_val:04X})")

# Schritt 2: Ersetze NUR das hohe Byte durch eine dezimale 2
low_byte = current_val & 0xFF # Behalte das niedrige Byte
high_byte = 2 # 0=deaktiviert, 1=IOL Manual, 2=IOL Autostart, 3=Digital Input, 4=Digital Output
new_val = (high_byte << 8) | low_byte # Kombinieren

print(f "Neuer zu schreibender Wert: {neues_wert} (0x{neues_wert:04X})")

# Schritt 3: Zurückschreiben mit Write Multiple Registers
success = client.write_multiple_registers(9101, [new_val])
print("✅ Write successful" if success else "❌ Write failed")

else:
print("❌ Failed to read register 9101")

Ergebnis:

Aktuelles Register 9101: 513 (0x0201)
Neuer zu schreibender Wert: 513 (0x0201)
✅ Schreiben erfolgreich

6. Lesen von IO-Link-Prozessdaten

In diesem Kapitel werden Prozessdaten von Port 1 des IO-Link-Masters gelesen. Dies kann auf andere IO-Link-Master-Ports angewendet werden, indem die Adresse des Startregisters angepasst wird.

Als Referenz:

Die Adresse des Startregisters von Port 1 ist 1100 und die Datenlänge beträgt 34 Worte oder 64 Bytes, die 32 Bytes der Eingangsprozessdaten und 32 Bytes der Ausgangsprozessdaten umfassen.

Im nachstehenden Beispiel-Code werden 32 Byte Eingangsprozessdaten von einem BCM0003 Balluff Condition Monitoring Sensor gelesen, die in 8 Slots zu je 4 Byte (2 Worte) unterteilt sind. Anschließend wird ein Byte-Swap durchgeführt, wandeln die Daten in einen REAL-Wert um und runden sie auf eine bestimmte Anzahl von Dezimalstellen.

 

Beispiel-Code:

import struct


from pyModbusTCP.client import ModbusClient
client = ModbusClient(host='192.168.1.1', port=502, unit_id=255, auto_open=True)
#**************************************************************************************
def read_float32(client, address, unit=255):
regs = client.read_holding_registers(address, 2)
if not regs:
return None
swapped = [regs[1], regs[0]]
raw_bytes = struct.pack('<HH', swapped[0], swapped[1])
return struct.unpack('>f', raw_bytes)[0]
#**************************************************************************************

v_rms_x = read_float32(client, 1100)
v_rms_y = read_float32(client, 1102)
v_rms_z = read_float32(client, 1104)
v_peak_x = read_float32(client, 1106)
v_peak_y = read_float32(client, 1108)
v_peak_z = read_float32(client, 1110)
bcm_temp = read_float32(client, 1112)

v_rms_x = round(v_rms_x, 4)
v_rms_y = round(v_rms_y, 4)
v_rms_z = round(v_rms_z, 4)
v_peak_x = round(v_peak_x, 4)
v_peak_y = round(v_peak_y, 4)
v_peak_z = round(v_peak_z, 4)
bcm_temp = round(bcm_temp, 2)

print("BCM vRMS X:", v_rms_x)
print("BCM vRMS Y:", v_rms_y)
print("BCM vRMS Z:", v_rms_z)
print("BCM vPeak X:", v_peak_x)
print("BCM vPeak Y:", v_peak_y)
print("BCM vPeak Z:", v_peak_z)
print("BCM Temp:", bcm_temp)

Ergebnis:
BCM vRMS X: 0.0398
BCM vRMS Y: 0.038
BCM vRMS Z: 0.0582
BCM vPeak X: 0.1225
BCM vPeak Y: 0.1395
BCM vPeak Z: 0.1735
BCM Temp: 39.87

7. Schreiben von IO-Link-Prozessdaten

In diesem Kapitel werden IO-Link-Prozessdaten geschrieben, um die Funktion einer 5-Segment-Smart-Light zu steuern, die an Port 2 des IO-Link-Masters angeschlossen ist.

Der Beispiel-Code kann auf andere IO-Link-Geräte angewendet werden.

Hinweis:
Register 1n17 (d.h. 1217 für Port 2) muss auf 1 gesetzt werden, um IO-Link-Prozessdaten zu validieren.

Beispiel-Code:

def reverse_bits(word):
"""
Kehrt die Reihenfolge der Bits in einem 16-Bit-Wort um.
Beispiel: 0b0000000000000001 -> 0b1000000000000000
"""
if not (0 <= word <= 0xFFFF):
raise ValueError("Word must be a 16-bit integer (0-65535)")

reversed_word = 0
for i in range(16):
if word & (1 << i):
reversed_word |= (1 << (15 - i))
return reversed_word
#*********************************************************************
def bits_to_word(bits):
"""
Konvertiert eine Liste von 16 Bits (0 oder 1) in eine 16-Bit Ganzzahl (Wort).
bits[0] ist das MSB, bits[15] ist das LSB.
"""
if len(bits) != 16:
raise ValueError("Genau 16 Bits sind erforderlich")
if any(bit not in (0, 1) for bit in bits):
raise ValueError("Bits müssen 0 oder 1 sein")

word = 0
for i, bit in enumerate(bits):
word |= (bit << (15 - i)) # Schiebe Bit in Position
return word
#*********************************************************************
SL_byte0_und_1 = [1, #Seg 1 Farbbit1
0, #Seg 1 Farbbit2
0, #Seg 1 Farbbit3
0, #Seg 1 blink
1, #Seg 2 Farbbit1
1, #Seg 2 Farbbit2
0, #Seg 2 Farbbit3
0, #Seg 2 blink
1, #Seg 3 Farbbit1
1, #Seg 3 Farbbit2
1, #Seg 3 Farbbit3
0, #Seg 3 blink
0, #Seg 4 Farbbit1
0, #Seg 4 Farbbit2
1, #Seg 4 Farbbit3
0, #Seg 4 blink
]
#*****************************************
SL_byte1_und_2 = [1, #Seg 5 color bit1
0, #Seg 5 color bit2
0, #Seg 5 color bit3
0, #Seg 1 blink
0, #Buzzer type bit 0
0, #Buzzer type bit 1
0, #nicht verwendet für SL
0, #Buzzer state
1, #Segment mode
0, #Level mode
0, #Runlight mode
0, #Flexible mode
0, #Nicht verwendet für SL
0, #Nicht sicher für SL
0, #Sync start
0, #Sync-Impuls
]
Register_1 = bits_to_word(SL_byte0_und_1)
Register_1_reversed = reverse_bits(Register_1)

Register_2 = bits_to_word(SL_byte1_und_2)
Register_2_reversed = reverse_bits(Register_2)

from pyModbusTCP.client import ModbusClient

# Modbus-Client erstellen
client = ModbusClient(host="192.168.1.1", port=502, auto_open=True)


# HINWEIS: 1n01 Port n IOL Prozessdateneingang gültig
# 1n01...1n16 16 Worte (32 Bytes) IOL Input Prozessdaten
# 1n17 Port n IOL Prozessdatenausgang gültig
# 1n18...1n33 16 Worte (32 Bytes) IOL Output Prozessdaten
IOL_Process_data_output_valid = 1 #0=ungültig und 1=gültig
# Schreiben von 16 (32 Bytes) Registern beginnend bei Adresse 1200 IOL Port 2
client.write_multiple_registers(1217, [IOL_Process_data_output_valid,Register_1_reversed,Register_2_reversed,5,1])

# Lesen von 16 (32 Byte) Registern ab Adresse 1200 IOL Port 2
registers = client.read_holding_registers(1217, 5)

# Werte prüfen und anzeigen
if registers:
for i, value in enumerate(registers):
print(f "Register {1217 + i}: {value:016b}")
else:
print("❌ Fehler beim Lesen von Registern")
#*********************************************************************************************************
Energy consumption labeling
Energy consumption labeling

EPREL - European Product Database for Energy Labeling

Haben Sie Fragen oder Anregungen? Wir sind für Sie da.

Sie haben mehrere Möglichkeiten mit uns in Kontakt zu treten. Wir freuen uns, Ihnen weiterhelfen zu können.

Kontaktieren Sie uns direkt per Telefon: +43 57887


Balluff GmbH

Sochorgasse 12-16
2512 Tribuswinkel

Kontakt via E-Mail:
[email protected]

Kostenloses Produktmuster

Um ein kostenloses Musterprodukt in den Warenkorb legen zu können, müssen wir alle normalen Produkte aus dem Warenkorb entfernen. Sind Sie sicher, dass Sie fortfahren möchten