PyModbus
PyModbusDocs

Writing Registers

Write to Modbus registers and coils with PyModbus. Single writes, batch writes, data type conversion, and read-modify-write patterns.

Writing to Modbus Registers

PyModbus supports writing single registers, multiple registers, and coils. You can also convert floats and strings into register values using BinaryPayloadBuilder.

Write Single Register

from pymodbus.client import ModbusTcpClient

client = ModbusTcpClient('192.168.1.100')
client.connect()

# Write value 1234 to register 100
client.write_register(address=100, value=1234, slave=1)

client.close()

Track Modbus writes in production

TofuPilot records test results from your PyModbus scripts, tracks pass/fail rates, and generates compliance reports. Free to start.

Write Multiple Registers

from pymodbus.client import ModbusTcpClient

client = ModbusTcpClient('192.168.1.100')
client.connect()

values = [100, 200, 300, 400, 500]
client.write_registers(address=100, values=values, slave=1)

# Verify by reading back
result = client.read_holding_registers(100, 5, slave=1)
print(f"Written values: {result.registers}")

client.close()

Write Coils (Digital Outputs)

# Write single coil
client.write_coil(address=0, value=True, slave=1)

# Write multiple coils
coil_values = [True, False, True, True, False, False, True, False]
client.write_coils(address=0, values=coil_values, slave=1)

# Read back to verify
result = client.read_coils(0, 8, slave=1)
print(f"Coil states: {result.bits[:8]}")

Writing Data Types

32-bit Integer

from pymodbus.payload import BinaryPayloadBuilder
from pymodbus.constants import Endian

def write_int32(client, address, value):
    builder = BinaryPayloadBuilder(
        byteorder=Endian.BIG,
        wordorder=Endian.BIG
    )
    builder.add_32bit_int(value)
    client.write_registers(address, builder.to_registers())

write_int32(client, address=100, value=-123456)

Float

def write_float(client, address, value):
    builder = BinaryPayloadBuilder(
        byteorder=Endian.BIG,
        wordorder=Endian.BIG
    )
    builder.add_32bit_float(value)
    client.write_registers(address, builder.to_registers())

write_float(client, address=100, value=23.5)

String

def write_string(client, address, text, length=16):
    builder = BinaryPayloadBuilder(
        byteorder=Endian.BIG,
        wordorder=Endian.BIG
    )
    text = text[:length].ljust(length, '\x00')
    builder.add_string(text)
    client.write_registers(address, builder.to_registers())

write_string(client, address=100, text="PUMP_01", length=16)

Read-Modify-Write

Write a value and immediately read it back to confirm it stuck.

import time
from pymodbus.client import ModbusTcpClient

def write_and_verify(client, address, value, slave=1):
    write_result = client.write_register(address, value, slave)
    if write_result.isError():
        print(f"Write failed: {write_result}")
        return False

    read_result = client.read_holding_registers(address, 1, slave)
    if read_result.isError():
        print(f"Read verification failed: {read_result}")
        return False

    actual = read_result.registers[0]
    if actual == value:
        print(f"Wrote {value} to address {address}")
        return True
    else:
        print(f"Mismatch: expected {value}, got {actual}")
        return False

client = ModbusTcpClient('192.168.1.100')
client.connect()
write_and_verify(client, address=100, value=12345)
client.close()

Batch Writing

from pymodbus.client import ModbusTcpClient

def batch_write_configs(client, configs):
    for address, value in configs.items():
        result = client.write_register(address, value)
        if result.isError():
            print(f"Failed to write address {address}: {result}")
            return False
    return True

client = ModbusTcpClient('192.168.1.100')
client.connect()

configs = {
    1000: 235,    # Temperature setpoint: 23.5C
    1001: 750,    # Pressure setpoint: 75.0 bar
    1002: 1500,   # Flow setpoint: 1500 L/h
    1003: 60,     # Time setpoint: 60 seconds
}
batch_write_configs(client, configs)
client.close()

Write with Retry

import time
from pymodbus.exceptions import ModbusException

def safe_write(client, address, value, max_retries=3):
    for attempt in range(max_retries):
        try:
            result = client.write_register(address, value)
            if not result.isError():
                return True

            print(f"Attempt {attempt + 1} failed: {result}")

            if hasattr(result, 'exception_code'):
                if result.exception_code == 2:  # Illegal address
                    print(f"Address {address} does not exist")
                    return False
                elif result.exception_code == 3:  # Illegal value
                    print(f"Value {value} out of range")
                    return False

        except ModbusException as e:
            print(f"Modbus exception: {e}")

        if attempt < max_retries - 1:
            time.sleep(0.5)

    return False

Write Protection

Some devices require a password before writes are allowed.

import time

def unlock_and_write(client, password_register, password, address, value):
    client.write_register(password_register, password)
    time.sleep(0.1)  # Wait for unlock
    result = client.write_register(address, value)
    client.write_register(password_register, 0)  # Lock again
    return not result.isError()

unlock_and_write(client, 9999, 1234, 100, 500)

Always validate values before writing to production equipment. Wrong values can damage hardware or cause safety issues.

Common Issues

Value Out of Range

# Registers are 16-bit unsigned (0-65535)
# This wraps or fails
client.write_register(100, 70000)  # Too big

# Clamp to valid range
value = min(65535, max(0, your_value))
client.write_register(100, value)

Wrong Data Type

# Device expects scaled integer, not float
client.write_register(100, 23.5)  # Truncates to 23

# Scale first
scaled = int(23.5 * 10)  # 235
client.write_register(100, scaled)

Byte Order Issues

from pymodbus.payload import BinaryPayloadBuilder
from pymodbus.constants import Endian

# If device shows wrong values, try different byte order
builder = BinaryPayloadBuilder(
    byteorder=Endian.LITTLE,  # Try BIG if wrong
    wordorder=Endian.LITTLE   # Try BIG if wrong
)