Modbus: Kommunikation zwischen Server und Client

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
maksimilian
User
Beiträge: 86
Registriert: Freitag 2. November 2018, 20:59

Hallo Ihr,
ich arbeite mich zur Zeit in die Anwendung von Modbus mit Python ein, zunächst mit einfachen Tests. Ich erzeuge einen Modbus, in welchem mit einen Client Daten geschrieben werden sollen. Das gelingt bisher nicht.

Server-Code:

Code: Alles auswählen

#!/usr/bin/env python3
from pyModbusTCP.server import ModbusServer, DataBank
from time import sleep
from random import uniform

server = ModbusServer("127.0.0.1", 12345, no_block=True )
#server = ModbusServer("192.168.178.25",12345, no_block=True)
try:
   print("Start Server ...")
   server.start()
   print("Server ist online")
   state = [0]
   server.data_bank.set_input_registers(0,[int(uniform(0, 100))])
   state = server.data_bank.get_input_registers(0)
   print("Register 0: " + str(state[0]))
#  server.data_bank.set_input_register(0,[int(18)])
   while True:
#      print("2")
#      server.data_bank.set_input_registers(0,[int(uniform(0, 100))])
#      server.data_bank.set_input_registers(0, [int(uniform(0, 100))])
      if state != server.data_bank.get_input_registers(0):
#         print("3")
         state = server.data_bank.get_input_registers(0)
         print("Wert von Register 0 hat sich geändert zu " +str(state))
         sleep(0.5)
      continue
except:
   print("Shutdown Server ...")
   server.stop()
   print("Server ist offline")
Server-Aufruf:

Code: Alles auswählen

pi@raspitest:~ $ python3 modbusserver
Start Server ...
Server ist online
Register 0: 43
Wert von Register 0 hat sich geändert zu [0]
Client:

Code: Alles auswählen

pi@raspitest:~ $ python3
Python 3.7.3 (default, Oct 11 2023, 09:51:27)
[GCC 8.3.0] on linux
Type ...
>>> from pyModbusTCP.client import ModbusClient
>>> client = ModbusClient(host="127.0.0.1", port=12345)
>>> client.open()
True
>>> client.read_input_registers(0, 5)
[27, 0, 0, 0, 0]
>>> client.write_multiple_registers(0, [1,2,5])
True
>>> client.read_input_registers(0, 5)
[27, 0, 0, 0, 0]
>>>
Benutzeravatar
__blackjack__
User
Beiträge: 13250
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@maksimilian: Anmerkungen zum Quelltext:

`DataBank` wird importiert, aber nirgends verwendet.

Das nackte ``except:`` ohne konkrete Ausnahme sollte eigentlich ein ``finally:`` sein.

Die erste Zuweisung an `state` ist unnötig — der Wert der dort zugewiesen wird, wird nirgends verwendet.

Das ``server.data_bank.get_input_registers(0)`` in der Schleife zweimal ausgeführt wird, und ja bei beiden Aufrufen unterschiedliche Ergebnisse liefern könnte, ist ziemlich sicher ein Fehler.

``int(uniform(0, 100))`` ist etwas ungewöhnlich als Formulierung für ``randint(0, 100)``.

``+`` und `str()` um Zeichenketten und Werte zusammen zu stückeln ist eher BASIC als Python. In Python gibt es Zeichenkettenformatierung mittels `format()`-Methode oder f-Zeichenkettenliteralen, oder man nutzt einfach das `print()` die Argumente selber in Zeichenketten umwandelt.

``continue`` würde sowieso meiden, aber hier hat das noch nicht einmal einen Effekt auf den Programmablauf, denn die nächste Iteration starten an der Stelle mit oder ohne ``continue``.

Ungetestet:

Code: Alles auswählen

#!/usr/bin/env python3
from random import randint
from time import sleep

from pyModbusTCP.server import ModbusServer


def main():
    server = ModbusServer("127.0.0.1", 12345, no_block=True)
    try:
        print("Start Server ...")
        server.start()
        print("Server ist online")
        server.data_bank.set_input_registers(0, [randint(0, 100)])
        previous_state = state = server.data_bank.get_input_registers(0)
        print("Register 0:", state)
        while True:
            state = server.data_bank.get_input_registers(0)
            if state != previous_state:
                print("Wert von Register 0 hat sich geändert zu", state)
                previous_state = state
                sleep(0.5)

    finally:
        print("Shutdown Server ...")
        server.stop()
        print("Server ist offline")


if __name__ == "__main__":
    main()
Please call it what it is: copyright infringement, not piracy. Piracy takes place in international waters, and involves one or more of theft, murder, rape and kidnapping. Making an unauthorized copy of a piece of software is not piracy, it is an infringement of a government-granted monopoly.
Benutzeravatar
grubenfox
User
Beiträge: 447
Registriert: Freitag 2. Dezember 2022, 15:49

ungetester Vorschlag meinerseits: Probiere es mal mit dem Paket pymodbus anstelle vom Paket pyModbusTCP.

Bei dem ersten steht wenigstens was von "Production/Stable" als Entwicklungsstand
maksimilian
User
Beiträge: 86
Registriert: Freitag 2. November 2018, 20:59

@ _blackjack_
Ich habe es geahnt: Kritik an meinem Python-Code. Ich habe längere Zeit nicht mehr mit Python gearbeitet, und der Server-Code stammt aus einem Beispiel. Aber sei's drum. Danke für die Mühe, die Du Dir gemacht hast. Leider ändert auch Deine Server-Version nichts am Ergebnis. Gibt es evtl. eine Instanz, welche verhindert, dass der Client zwar den Modbus lesen, ihn aber nicht ändern darf ?

@grubenfox
Werde es auch mit pymodbus versuchen.
Kyrus86
User
Beiträge: 5
Registriert: Samstag 21. Oktober 2023, 13:04

Hallo maksimilian,

bei Modbus gibt es zwei Arten von Registern: Input Register und Holding Register.
Input Register sind read-only und können vom Client nicht geschreiben werden.
Holding Register sind Read-Write.

Dein Client schreibt also in ein Holding Register und liest aus dem Input Register, welche natürlich nicht den gleichen Wert haben.

Eine Abhilfe wäre die Methode "read_holding_registers" statt "read_input_registers" zu verwenden.

Eine andere Möglichkeit ist die Holding Register auf die Input Register zu spiegeln.
Hier der Code von meinem Testserver:

Code: Alles auswählen

from pyModbusTCP.server import ModbusServer, DataBank


class MyDataBank(DataBank):
    def on_holding_registers_change(self, address, from_value, to_value, srv_info):
        self.set_input_registers(address=address, word_list=[to_value])


def main():
    server = ModbusServer(host='0.0.0.0', data_bank=MyDataBank())
    server.start()


if __name__ == '__main__':
    main()
Wird vom Server eine Änderung des Holding Registers erkannt, wird der Wert auf das Input Register mit der gleichen Adresse geschrieben.
Antworten