pythonmodbusplcpymodbustcp

Read & Write Float in Modbus Python


Sorry for my bad english. I try to write and read float in a plc register in python via Modbus using pyModbusTCP lib. This is my code that unfortunatly didn't go...

from pyModbusTCP.client import ModbusClient
from pyModbusTCP import utils

class FloatModbusClient(ModbusClient):
    def read_float(self, address, number=1):
        reg_l = self.read_holding_registers(address, number * 2)
        if reg_l:
            return [utils.decode_ieee(f) for f in utils.word_list_to_long(reg_l)]
        else:
            return None

    def write_float(self, address, floats_list):
        b32_l = [utils.encode_ieee(f) for f in floats_list]
        b16_l = utils.long_list_to_word(b32_l)
        return self.write_multiple_registers(address, b16_l)


c = FloatModbusClient(host=ip, port=porta, auto_open=True)
# write 10.0 at @0
c.write_float(registrow, [var]) 
print("write ok")

# read @0 to 9
float_l = c.read_float(registror)
print(float_l)
c.close()

Can someone help me?


Solution

  • This is little bit tricky because all Modbus registers are only 16-bit unsigned data (those who are intended for sending numbers):

    Object type      | Access     | Size    | Address Space
    Coil             | Read-write | 1 bit   | 00001 - 09999
    Discrete input   | Read-only  | 1 bit   | 10001 - 19999
    Input register   | Read-only  | 16 bits | 30001 - 39999
    Holding register | Read-write | 16 bits | 40001 - 49999
    

    This is code that will allow you as a Client send positive Float numbers from Python to Modbus server:

    from pyModbusTCP.client import ModbusClient
    
    def send_single_float(client, reg_addr, reg_value, setting, by):
        if setting == "multiply":
            client.write_single_register(reg_addr = reg_addr, reg_value = int(reg_value*by))
        elif setting == "divide":
            if reg_value == 0:
                client.write_single_register(reg_addr = reg_addr, reg_value = int(reg_value))
            else:
                client.write_single_register(reg_addr = reg_addr, reg_value = int(reg_value/by))
        else:
            raise TypeError("Only string with following values can be set for 'Setting' attribute: ('multiply', 'divide')")
    
    c = ModbusClient("localhost")
    c.open()
    
    my_float = 10.05
    
    while True:
        send_single_float(c, 0, my_float, "multiply", 100)
    

    You can use also this function to read Float numbers from Modbus:

    def read_single_float(client, reg_addr, setting, by):
        if setting == "multiply":
            return client.read_holding_registers(reg_addr = reg_addr, reg_nb = 1)[0] * by
        elif setting == "divide":
            data = client.read_holding_registers(reg_addr = reg_addr, reg_nb = 1)[0]
            if data == 0:
                return data
            else:
                return data / by
        else:
            raise TypeError("Only string with following values can be set for 'Setting' attribute: ('multiply', 'divide')")