You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyModbus:Modbus TCP异常处理及服务器变量读写权限配置咨询

PyModbus Server: Handling Out-of-Range Writes & Read-Only Registers

Hey there! Let's break down solutions for your two PyModbus server questions with practical, runnable code examples.

1. Generating Modbus TCP Exceptions for Out-of-Range Writes

To make your server throw a proper Modbus exception when a client sends an out-of-range value, you'll need to customize the server's data context to validate writes before they're applied. PyModbus lets you override default write methods to add your own range checks.

Here's how to implement it:

  • Create a custom slave context by inheriting from BaseModbusSlaveContext
  • Override the write method(s) matching your register type (e.g., write_registers for holding registers)
  • Add range validation logic, and throw a ModbusException with the correct error code if values are invalid

Example Code

from pymodbus.server import StartTcpServer
from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext
from pymodbus.datastore.context import BaseModbusSlaveContext
from pymodbus.exceptions import IllegalValueException

class ValidatedSlaveContext(BaseModbusSlaveContext):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # Define your allowed value ranges (tweak these to match your needs)
        self.valid_ranges = {
            "holding": (0, 100),  # Holding registers 0-99 accept 0-100
        }

    def write_registers(self, address, values, **kwargs):
        # Check if we're writing to the validated holding register range
        if 0 <= address <= 99:
            min_val, max_val = self.valid_ranges["holding"]
            for val in values:
                if not (min_val <= val <= max_val):
                    # Throw Illegal Value exception (Modbus code 0x03)
                    raise IllegalValueException(f"Value {val} is out of valid range [{min_val}, {max_val}]")
        # If validation passes, use the default write logic
        return super().write_registers(address, values, **kwargs)

# Set up the server context with 100 holding registers
slave_context = ValidatedSlaveContext(
    di=None, co=None, hr=[100], ir=None
)
server_context = ModbusServerContext(slaves=slave_context, single=True)

# Start the TCP server on port 502
StartTcpServer(context=server_context, address=("0.0.0.0", 502))

When a client writes a value outside 0-100 to holding registers 0-99, the server will respond with a Modbus Illegal Value Exception (code 0x03).

2. Setting Partial Variables as Read-Only

To make specific registers read-only while keeping others writable, you'll use a custom context to block writes to designated address ranges. The key is to check the target address in the write method and throw an exception if it's in a read-only zone.

Example Code

from pymodbus.server import StartTcpServer
from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext
from pymodbus.datastore.context import BaseModbusSlaveContext
from pymodbus.exceptions import IllegalFunctionException

class ReadOnlySlaveContext(BaseModbusSlaveContext):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # Define read-only address ranges (adjust these to your use case)
        self.read_only_zones = {
            "holding": (0, 9),  # Holding registers 0-9 are read-only
            "coils": (0, 4)     # Coils 0-4 are read-only
        }

    def write_registers(self, address, values, **kwargs):
        # Block writes to read-only holding registers
        if self.read_only_zones["holding"][0] <= address <= self.read_only_zones["holding"][1]:
            raise IllegalFunctionException("Write not allowed: holding registers 0-9 are read-only")
        return super().write_registers(address, values, **kwargs)

    def write_coils(self, address, values, **kwargs):
        # Block writes to read-only coils
        if self.read_only_zones["coils"][0] <= address <= self.read_only_zones["coils"][1]:
            raise IllegalFunctionException("Write not allowed: coils 0-4 are read-only")
        return super().write_coils(address, values, **kwargs)

# Set up server context with 20 holding registers and 10 coils
slave_context = ReadOnlySlaveContext(
    di=None, co=[10], hr=[20], ir=None
)
server_context = ModbusServerContext(slaves=slave_context, single=True)

# Start the TCP server
StartTcpServer(context=server_context, address=("0.0.0.0", 502))

In this setup:

  • Holding registers 0-9 are read-only (writes throw Illegal Function Exception 0x01)
  • Holding registers 10-19 are fully writable
  • Coils 0-4 are read-only, coils 5-9 are writable

You can easily adjust the read_only_zones dictionary to match your specific register types and address ranges.


内容的提问来源于stack exchange,提问作者MM87

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:52:55