pythonraspberry-pi3modbuspymodbus3

Pymodbus in RaspberryPi 3


I am trying to get data from a modbus device through pymodbus in raspberrypi 3

from pymodbus.client.sync import ModbusSerialClient as ModbusClient

client = ModbusClient(method = 'rtu', port = '/dev/ttyUSB0', baudrate = 115200)
client.connect()

result = client.read_input_registers(0x3100,6,unit=1)
solarVoltage = float(result.registers[0] / 100.0)
solarCurrent = float(result.registers[1] / 100.0)
batteryVoltage = float(result.registers[4] / 100.0)
chargeCurrent = float(result.registers[5] / 100.0)

# Do something with the data

client.close()

The code above is working fine. But i want to get the bits from the information given below

enter image description here

e.g i am trying something like this

result = client.read_input_registers(0x3200,unit=1)

but when i call result.registers the output it shows is 0 but i want to get the Values of D0 to D15. How can i do that? thanks


Solution

  • The description in the documentation tells you how to interpret each bit of your values.
    pymodbus's read_input_registers() returns a units16 (unsigned int 2 bytes) for each register (see official documentation), this means that it can be a value between 0 and 65535.

    result = client.read_input_registers(0x3200, 2, unit=1)
    value1 = result.registers[0] # 33059
    value2 = result.registers[1] # 9359
    

    This values can be transformed in binary values:

    print format(value1, '016b') # 1000000100100011
    print format(value2, '016b') # 0010010010001111
    

    each one of these bit can be indexed from 0 to 15 (from right to left), and then we can split them as described in the documentation:

    value1 D3-D0: 0011
    Value1 D7-D4: 0010
    Value1 D8: 1
    Value1 D15: 1

    For each subset of bit, the documentation provides us a number in hex value, and each number in hex value can be converted in binary:

    D3-D0:
    00H (bin: 0000) Normal
    01H (bin: 0001) Overvolt
    02H (bin: 0010) Undervolt
    03H (bin: 0011) Low Volt Disconnect
    04H (bin: 0100) OverTemp
    and same for other sets...

    If the set contains only one bit, we consider True(1)/False(0) behaviour.

    Comparing this values with our sets, we understand that 33059 means: Low Volt Disconnect, Low Temp, Battery internal resistance abnormal, Wrong identification for rated voltage (a disaster!) or in your case, 0 means Normal, Normal, Normal, Correct identification for rated voltage.

    If we apply the same to value2(9359), we will understand that:

    1 D0----|---Standby
    1 D1----|---Fault
    1 D2----|---|---Equalization
    1 D3----|---|
    0 D4----|---ok
    0 D5----|---//
    0 D6----|---//
    1 D7----|---The load is short
    0 D8----|---ok
    0 D9----|---ok
    1 D10---|---Input is over current
    0 D11---|---ok
    0 D12---|---ok
    1 D13---|---Charging MOSFET is short
    0 D14---|---|---Normal
    0 D15---|---|
    

    Obviously you don't want to do all this by hand: even if there are many ways to program this work, i suggest you to use a bitmask:

    # Define each mask as a tuple with all the bit at 1 and distance from the right:
    D3_D0_mask = (0b1111, 0)
    D7_D4_mask = (0b1111, 4)
    D8_mask = (0b1, 8)
    D15_mask = (0b1, 15)
    # compare each mask to the value, after shifting to the right position:
    print D3_D0_mask[0]&(value1>>D3_D0_mask[1]) == 4 # False, Fault
    print D3_D0_mask[0]&(value1>>D3_D0_mask[1]) == 3 # True, Low Volt Disconnect
    print D3_D0_mask[0]&(value1>>D3_D0_mask[1]) == 2 # False, Under Volt
    print D3_D0_mask[0]&(value1>>D3_D0_mask[1]) == 1 # False, Overvolt
    print D3_D0_mask[0]&(value1>>D3_D0_mask[1]) == 0 # False, Normal
    
    print D7_D4_mask[0]&(value1>>D7_D4_mask[1]) == 2 # True, Low Temp
    print D7_D4_mask[0]&(value1>>D7_D4_mask[1]) == 1 # False, Over Temp
    print D7_D4_mask[0]&(value1>>D7_D4_mask[1]) == 0 # False, Normal
    
    print D8_mask[0]&(value1>>D8_mask[1]) == 1 # True, Battery internal resistance abnormal
    
    print D15_mask[0]&(value1>>D15_mask[1]) == 1 # True, Wrong identification for rated voltage
    

    The optimisation on this code should be evident.
    As you see, anyway, we are getting the output that we expected.