pythonでModbus/TCPによりデバイスのレジスタにアクセスするスクリプトに書込みスクリプトを追加しました。
Function Code 0x05 (Force Single Coil)のみ対応ですが、GitHubにも追加しています。
レジスタ書込みツール: modbus_writer.py
読取りツールmodbus_reader.pyと同じく、modbus用のライブラリは使用せずsocket通信でコマンド/レスポンスを送受信しています。
GitHub:
https://github.com/tyamazoe/modbus
使用方法
$python modbus_writer.py [ip address]
デバイスのIPを指定して実行すると、Unit ID, Function Code, アドレス等のパラメータの入力を対話式で要求されます。
パラメータは 16進の場合 0xを付けて指定します(例: 0x04)。10進数の場合はそのままです(例: 4)。
制限事項
現状はFunction Code は 0x05 (Force Single Coil)のみの対応です。従って1個のレジスタへの値のセットOn(0xff00)/Off(0x0000)を行います。
注意:
FC 0x05の場合書き込む値は
0xff00 または 0x0000 (On/Off)の2択です。0xff00/0x0000 以外をリクエストするとエラーが返ります。
プログラム
# -*- coding: utf-8 -*-
# Modbus/TCP writer
#
import socket
import struct
import time
import traceback
import codecs
import sys
TARGET_IP = '192.168.1.99'
try:
TARGET_IP = sys.argv[1]
except IndexError:
pass # use defaults
TARGET_PORT = 502
buffer_size = 0
def get_param(msg):
param = input(msg)
hex_dec = 16 if "0x" in param.lower() else 10
return int(param, hex_dec)
try:
print("\nEnter Modbus Params in [0xnn (Hex)] or [nn (Dec)]")
unitId = get_param(" Unit Identifier: ")
functionCode = get_param(" Function Code: ")
if functionCode == 0x05:
startRegister = get_param(" Start Register: ")
pack_data = 0xff00 if get_param(" On(1) or Off(0):") == 1 else 0x0000
numRegister = 2
else:
raise Exception("FC only support 0x05")
# Send request
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((TARGET_IP, TARGET_PORT))
req = struct.pack('>3H 2B 2H', 0, 0, 6, unitId, functionCode, startRegister, pack_data)
sock.send(req)
# Receive response
buffer_size = len(req)
res = sock.recv(buffer_size)
print("\nTX: {0}".format(codecs.encode(req, 'hex_codec')))
print("RX: {0}".format(codecs.encode(res, 'hex_codec')))
if res == req:
print("\nOK, write completed.")
else:
# error response
s = struct.Struct('>3H 3B')
data = s.unpack(res)
print("\nModbus Application Data Unit (ADU)")
print(" Transaction Identifier : %s" %data[0])
print(" Protocol Identifier : %s" %data[1])
print(" Length : %s" %data[2])
print(" Unit Identifier : %s" %data[3])
print(" Error Code : 0x{0:02x} : {0}".format(data[4]))
print(" Exception Code : 0x{0:02x} : {0}".format(data[5]))
sock.close()
except:
print(traceback.format_exc())
finally:
print("\nDone")
例:Off(0x0000) 正常応答
192.168.1.101のデバイスに対して
Unit ID: 1, Force Single Coil (FC 0x05)によりアドレス0x0101のSingle Coilに対して 0x0000 (Off)を指定した場合です。
$ python modbus_writer.py 192.168.1.101
Enter Modbus Params in [0xnn (Hex)] or [nn (Dec)]
Unit Identifier: 1
Function Code: 5
Start Register: 0x101
On(1) or Off(0):0
結果
0x0000のセットに成功したために同じModbus ADU (Application Data Unit):が返ってきています。
例えばデバイスの接点やリレーがOffになります。
TX: b'000000000006010501010000'
RX: b'000000000006010501010000'
OK, write completed.
Done
例:On(0xff00) 正常応答
192.168.1.101のデバイスに対して
Unit ID: 1, Force Single Coil (FC 0x05)によりアドレス0x0101のSingle Coilに対して 0xff00 (On)を指定した場合です。
$ python modbus_writer.py 192.168.1.101
Enter Modbus Params in [0xnn (Hex)] or [nn (Dec)]
Unit Identifier: 1
Function Code: 5
Start Register: 0x101
On(1) or Off(0):1
結果
0xff00のセットに成功したために同じModbus ADU (Application Data Unit):が返ってきています。
例えばデバイスの接点やリレーがOnになります。
TX: b'00000000000601050101ff00'
RX: b'00000000000601050101ff00'
OK, write completed.
Done
おわりに
Single Coilのみですが、これでModbus/TCPデバイスのレジスタも操作ができるようになりました。
“pythonでModbus機器と通信する(4) レジスタ書込み用ツール(Force Single Coil)” への1件の返信