前回の記事でpythonでModbus/TCPに対してリクエスト(コマンド)を送信しましたので、返ってきたレスポンスを受信してみます。
対象機器のレジスタマップを確認する
例えば、とあるIT機器の例ですが、Inletの入力電圧を読みたい場合、
ファンクションコードとレジスタの定義をその機器の取説や仕様書から読み取ります。
Holding Register MapにInletがマップされています。
Inlet1は Register 0x3000-0x303f です。
詳細な割り当てを参照すると最初の16レジスタは以下の様に割り当てられています。
各レジスタは2byte(=32bit)です。これも仕様書で確認しておきます。が、パラメータ毎にBit Mask型であったり、Word型であったり、Float型(4byte)の半分であったりします。
とにかくまとめてアドレス0x3000から16レジスタ分をreadしてみます。
Function Code 0x03 (Read Holding Registers)でUnit ID 0x01のユニットのレジスタ0x3000fから16レジスタをreadする
Modbus データ
リクエスト ‘000000000006010330000010’
レスポンス ‘00000000002301032009e30001000200640078000c0000000042cbe1473d5d2f1b0000000000000000’
区切ってみます。
TX:
Transaction, Protocol, length, Id, FC, Address, Num
0000 0000 0006 01 03 3000 0010
RX:
Transaction, Protocol, length, Id, FC, size, Registar data
0000 0000 0023 01 03 20 09e3 0001 0002 0064 0078 000c 0000 0000 42cb e147 3d5d 2f1b 0000 0000 0000 0000
16レジスタ分つまり0x20(=32)バイトのデータがレスポンスされました。
単純に2byteのHexで各レジスタ値を表示すると
REGISTER VALUES
0x3000 : 0x9e3
0x3001 : 0x1
0x3002 : 0x2
0x3003 : 0x64
0x3004 : 0x78
0x3005 : 0xc
0x3006 : 0x0
0x3007 : 0x0
0x3008 : 0x42cb
0x3009 : 0xe147
0x300a : 0x3d5d
0x300b : 0x2f1b
0x300c : 0x0
0x300d : 0x0
0x300e : 0x0
0x300f : 0x0
オフセット 0x03 Word Minimum voltage rating in V が 0x64 = 100[v] であることが解ります。
オフセット 0x00 Bit maskが 0x9e3 なので Bit0,1はOnです。RMS Voltage, RMS Currentすなわち電圧センサと電流センサがサポートされています。
現在の電圧は
オフセット 0x08-0x09 の4byteのfloatです。0x42cb e147 float型を10進に変換すると
0x42cbe147 = 101.9399…[v]
それらしい値をreadできました。
Hex Float -> 10進表示
$python
Python 3.6.4
>>> import struct, binascii
>>> s="42cbe147"
>>> print(struct.unpack('>f', binascii.unhexlify(s))[0])
101.93999481201172
気を付けること
このようにModbusの場合は各機器ごとにレジスタマップを確認して正しく受信データを切り出す必要があります。