1
votes

I was assigned to perform the task without any documentation. I have a problem with reading data from MODBUS. This is the script that I was able to create:

from pymodbus.constants import Endian
from pymodbus.payload import BinaryPayloadDecoder
from pymodbus.payload import BinaryPayloadBuilder
from pymodbus.client.sync import ModbusTcpClient

client = ModbusTcpClient('X.X.X.X')
connection = client.connect()

request = client.read_holding_registers(12606,2)
result = request.registers
decoder = BinaryPayloadDecoder.fromRegisters(result, Endian.Big, wordorder=Endian.Little)
print "Counter1: %0.2f" % decoder.decode_32bit_float()

request = client.read_holding_registers(12482,2)
result = request.registers
decoder = BinaryPayloadDecoder.fromRegisters(result, Endian.Big, wordorder=Endian.Little)
print "Counter2: %0.2f" % decoder.decode_32bit_float()

client.close()

Everything looks fine, But the data on the counter is different from those in the script for example:

Value on the counter : 39558853.30 (value is decimal)
Value from the script: 58853.30
(value is decimal)

Read input registers (HEX): E54D 4765

And this is how the address documentation looks like"

P   12458       Q2  4\DW12458 = 1\ND20_Q2\P(F)
Q   12462       Q2  4\DW12462 = 1\ND20_Q2\Q(F)
S   12466       Q2  4\DW12466 = 1\ND20_Q2\S(F)
I   12470       Q2  4\DW12470 = 1\ND20_Q2\I(F)
U   12474       Q2  4\DW12474 = 1\ND20_Q2\U(F)
f   12478       Q2  4\DW12478 = 1\ND20_Q2\f(F)
EP_POB  12482       Q2  4\DW12482 = 1\ND20_Q2\EP_POB(F)
EP_ODD  12486       Q2  4\DW12486 = 1\ND20_Q2\EP_ODD(F)
EQ_IND  12490       Q2  4\DW12490 = 1\ND20_Q2\EQ_IND(F)
EQ_POJ  12494       Q2  4\DW12494 = 1\ND20_Q2\EQ_POJ(F)
THDVL1  12498       Q2  4\DW12498 = 1\ND20_Q2\THDVL1(F)
THDVL2  12502       Q2  4\DW12502 = 1\ND20_Q2\THDVL2(F)
THDVL3  12506       Q2  4\DW12506 = 1\ND20_Q2\THDVL3(F)
THDIL1  12510       Q2  4\DW12510 = 1\ND20_Q2\THDIL1(F)
THDIL2  12514       Q2  4\DW12514 = 1\ND20_Q2\THDIL2(F)
THDIL3  12518       Q2  4\DW12518 = 1\ND20_Q2\THDIL3(F)
UL1 12522       Q2  4\DW12522 = 1\ND20_Q2\UL1(F)
UL2 12526       Q2  4\DW12526 = 1\ND20_Q2\UL2(F)
UL3 12530       Q2  4\DW12530 = 1\ND20_Q2\UL3(F)
IL1 12534       Q2  4\DW12534 = 1\ND20_Q2\IL1(F)
IL2 12538       Q2  4\DW12538 = 1\ND20_Q2\IL2(F)
IL3 12542       Q2  4\DW12542 = 1\ND20_Q2\IL3(F)
PL1 12546       Q2  4\DW12546 = 1\ND20_Q2\PL1(F)
PL2 12550       Q2  4\DW12550 = 1\ND20_Q2\PL2(F)
PL3 12554       Q2  4\DW12554 = 1\ND20_Q2\PL3(F)
QL1 12558       Q2  4\DW12558 = 1\ND20_Q2\QL1(F)
QL2 12562       Q2  4\DW12562 = 1\ND20_Q2\QL2(F)
QL3 12566       Q2  4\DW12566 = 1\ND20_Q2\QL3(F)
S1  12570       Q2  4\DW12570 = 1\ND20_Q2\S1(F)
S2  12574       Q2  4\DW12574 = 1\ND20_Q2\S2(F)
S3  12578       Q2  4\DW12578 = 1\ND20_Q2\S3(F)
2
What are the raw register values (preferably in hex) that you are reading when the meter shows 1355723,9? Do you have documentation on the registers you are reading? BTW, does the "," in the number represent decimal point?Marker
"," is decimal Current value on the counter : 39558853.30 Current value from the script: 58853.30 Read input registers (HEX): E54D 4765 --- this is the only thing I have in the documentation, unfortunately I doubt that someone would understand it. Counter1 12482 Q2 Counter1: 4\DW12482 = 1\ND20_Q2\EP_POB(F)miesiu
@miesiu Can you more explain that what is 12606 and 12482 addresses and where are in the mentioned document?Benyamin Jafari
12482 is in 7 line | EP_POB 12482 Q2 4\DW12482 = 1\ND20_Q2\EP_POB(F)miesiu
12482 it seems to be a MODBUS address which stores data from the meter.miesiu

2 Answers

1
votes

I improved your code as the following:

from pymodbus.constants import Endian
from pymodbus.payload import BinaryPayloadDecoder
from pymodbus.client.sync import ModbusTcpClient

def validator(instance):
    if not instance.isError():
        '''.isError() implemented in pymodbus 1.4.0 and above.'''
        decoder = BinaryPayloadDecoder.fromRegisters(
            instance.registers,
            byteorder=Endian.Big, wordorder=Endian.Little
        )   
        return float('{0:.2f}'.format(decoder.decode_32bit_float()))

    else:
        # Error handling.
        print("There isn't the registers, Try again.")
        return None


client = ModbusTcpClient('X.X.X.X', port=502)  # Specify the port.
connection = client.connect()

if connection:
    request = client.read_holding_registers(12606, 2, unit=1)  # Specify the unit.
    data = validator(request)
    print(data)

    request = client.read_holding_registers(12482, 2, unit=1)  # Specify the unit.
    data = validator(request)
    print(data)

    client.close()

else:
    print('Connection lost, Try again')

[NOTE]:

Do you ensure about desired float32 decode?

  1. float AB CD == byteorder=Endian.Big, wordorder=Endian.Big
  2. float CD AB == byteorder=Endian.Big, wordorder=Endian.Little
  3. float BA DC == byteorder=Endian.Little, wordorder=Endian.Big
  4. float DC BA == byteorder=Endian.Little, wordorder=Endian.Little

Set the unit_ID:

  • In many cases unit is 1 as default ID.

[UPDATE]:

Maybe you need to reading and decoding as the double/float64 value at the 12482 register address, because I think when the desired register in the doc is 12482 and the next register is 12846, therefore we need to read 4regs (float64/double):

request = client.read_holding_registers(12482, 4, unit=1)

And

return float('{0:.2f}'.format(decoder.decode_64bit_float()))
0
votes

I'm pretty sure the value 39558853.30 is to large to store in a IEEE single precision float. There are 7.22 digits of precision, that number requires 9 digits. I did some experimentation with assigning the value to float and double values in C# confirms this.

That leads me believe:

1) Like Benyamin Jafari suggested, you need to read four registers. However, that number (as a double) in hex is 0x4182dcf62a666666 which doesn't seem to correspond any of the data that you are reading.

OR

2) It is also possible that it is returned as a UINT32 which must be scaled by (1/100) to give you what the counter is showing. 0xE54D4765 = 3847047013 => scaled by 1/100.0 = 38470470.13 which is close to what you are seeing on the counter. In my experience, this is a common practice in Modbus.

OR

3) They are using some other (non-standard) format to represent the data.

Can you give us the product name, model, etc?