Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Offset registers > 100 responding IllegalAddress in TCP server mode #1529

Closed
neosoyo opened this issue Apr 26, 2023 · 4 comments
Closed

Offset registers > 100 responding IllegalAddress in TCP server mode #1529

neosoyo opened this issue Apr 26, 2023 · 4 comments

Comments

@neosoyo
Copy link

neosoyo commented Apr 26, 2023

Versions

  • Python: 3.10.6
  • OS: Pop!_OS 22.04 LTS
  • Pymodbus: 3.2.2

Pymodbus Specific

  • Server: tcp - async

Description

Simulating devices with sparse DataBlock using offsets > 100 is reporting Illegal Address.

Code and Logs

Config of server:

sc501_datablock = ModbusSparseDataBlock({
            20000: [45, 241, 48],       #ACDC Output current, input voltage and output voltage
            20008: 38,                  #Ambient temperature ACDC
            20023: [0, 0, 0, 0, 0, 0],  #Alarms rectifier
            22001: 23,                  #Output current DCDC
            22003: 48,                  #Output Voltage DCDC
            30052: [4, 2, 1],           #Alarms counts
            48030: [0, 0],              #LVD alarm state
            48040: [0, 0],              #batt + fuse alarm
            48050: [0, 0],              #batt - fuse alarm
            48060: [0, 0],              #batt alarm
            48140: [0x4208,0xcccd],     #Ambient temperature alarm
            48146: [0x42ad, 0x0000],    #Humidity alarm 
            48170: [0,0,0,0,0,0],         #Alarms type and classication
            48190: [0,0],               #BMS alarm
            48200: [0,0],               #ACDC rectifier alarm
            48204: [0,0],               #Solar converter alarm
            48216: [0,0],                #DCDC rectifier alarm
        })
Battery_datablock = ModbusSparseDataBlock({
            1: 6720,
            2: 130,
            3: [4200,4200,4200,4200,4200,4200,4200,4200,4200,4200,4200,4200,4200,4200,4200,4200],
            19: [39,40,43,2100,170,69,80,2,0,0,0],
            30: [0x0D,0xFE],
            32: [0,0,32,32],
            37: [16,3920],
            62: [0,0,0,0,0,0,0,0,0,0,0],
            81: [0,0,0,0],
            91: [0,0,0,0,0,0,0,0,0,0,0],
            105: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24],
            117: [56, 30, 33, 52, 30, 34]
        })
context = {
        0x01: ModbusSlaveContext(
            hr=sc501_datablock,
        ),
        0x02: ModbusSlaveContext(
            hr=Battery_datablock,
        ),}

My code after requesting some holding registers, all offset < 100 works fine:

battery reg 105, 24 values, modbus error
Exception Response(131, 3, IllegalAddress)
SC501 reg 20000, 3 values, modbus error
Exception Response(131, 3, IllegalAddress)
SC501 reg 20008, 1 value, modbus error
Exception Response(131, 3, IllegalAddress)
SC501 reg 20023, 6 values, modbus error
Exception Response(131, 3, IllegalAddress)
SC501 reg 22001, 1 value, modbus error
Exception Response(131, 3, IllegalAddress)
SC501 reg 22003, 1 value, modbus error
Exception Response(131, 3, IllegalAddress)
SC501 reg 30052, 3 values, modbus error
Exception Response(131, 3, IllegalAddress)
SC501 reg 48170, 6 values, modbus error
Exception Response(131, 3, IllegalAddress)

Server response:

2023-04-26 17:43:51,271 INFO  logging:96 Server(TCP) listening.
2023-04-26 17:43:59,223 ERROR logging:114 Exception response Exception Response(131, 3, IllegalAddress)
2023-04-26 17:43:59,223 ERROR logging:114 Exception response Exception Response(131, 3, IllegalAddress)
2023-04-26 17:43:59,224 ERROR logging:114 Exception response Exception Response(131, 3, IllegalAddress)
2023-04-26 17:43:59,224 ERROR logging:114 Exception response Exception Response(131, 3, IllegalAddress)
2023-04-26 17:43:59,224 ERROR logging:114 Exception response Exception Response(131, 3, IllegalAddress)
2023-04-26 17:43:59,224 ERROR logging:114 Exception response Exception Response(131, 3, IllegalAddress)

Anyone have an idea how to deal with?

@janiversen
Copy link
Collaborator

Since you are not sharing parts of the relevant code, it is quite hard to tell.

However this could very well be caused by a wrong or missing slave_id in the client call, or in the server setup.

@janiversen
Copy link
Collaborator

You say that <100 works fine (no log supplied) so it cannot be the slave_id unless you use different calls.

@janiversen
Copy link
Collaborator

It seems to be a problem in your code, just added a test case that tests SparseDatablock with your setup.

@neosoyo
Copy link
Author

neosoyo commented Apr 27, 2023

Sorry guys, i just got confused with address and count values... i must read the holding register with -1 offset at address to read correctly...

server.py:

import asyncio
import logging
import os

from helper import get_commandline
from pymodbus import __version__ as pymodbus_version
from pymodbus.datastore import (
    ModbusSequentialDataBlock,
    ModbusServerContext,
    ModbusSlaveContext,
    ModbusSparseDataBlock,
)
from pymodbus.device import ModbusDeviceIdentification
from pymodbus.server import (
    StartAsyncSerialServer,
    StartAsyncTcpServer,
)


_logger = logging.getLogger()


def setup_server(description=None, context=None, cmdline=None):
    """Run server setup."""
    args = get_commandline(server=True, description=description, cmdline=cmdline)
    print(args)
    if context:
        args.context = context
    if not args.context:
        _logger.info("### Create datastore")
        #simulating devices for unicoba POC
        sc501_datablock = ModbusSparseDataBlock({
            20000: [45, 241, 48],       #ACDC Output current, input voltage and output voltage
            20008: 38,                  #Ambient temperature ACDC
            20023: [0, 0, 0, 0, 0, 0],  #Alarms rectifier
            22001: 23,                  #Output current DCDC
            22003: 48,                  #Output Voltage DCDC
            30052: [4, 2, 1],           #Alarms counts
            48030: [0, 0],              #LVD alarm state
            48040: [0, 0],              #batt + fuse alarm
            48050: [0, 0],              #batt - fuse alarm
            48060: [0, 0],              #batt alarm
            48140: [0x4208,0xcccd],     #Ambient temperature alarm
            48146: [0x42ad, 0x0000],    #Humidity alarm 
            48170: [0,0,0,0,0,0],         #Alarms type and classication
            48190: [0,0],               #BMS alarm
            48200: [0,0],               #ACDC rectifier alarm
            48204: [0,0],               #Solar converter alarm
            48216: [0,0],                #DCDC rectifier alarm
        })
        Battery_datablock = ModbusSparseDataBlock({
            1: 6720,
            2: 130,
            3: [4200,4200,4200,4200,4200,4200,4200,4200,4200,4200,4200,4200,4200,4200,4200,4200],
            19: [39,40,43,2100,170,69,80,2,0,0,0],
            30: [0x0D,0xFE],
            32: [0,0,32,32],
            37: [16,3920],
            62: [0,0,0,0,0,0,0,0,0,0,0],
            81: [0,0,0,0],
            91: [0,0,0,0,0,0,0,0,0,0,0],
            105: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24],
            117: [56, 30, 33, 52, 30, 34]
        })
    context = {
        0x01: ModbusSlaveContext(
            hr=sc501_datablock,
        ),
        0x02: ModbusSlaveContext(
            hr=Battery_datablock,
        ),
    }
    single = False
    args.context = ModbusServerContext(slaves=context, single=single)
    args.identity = ModbusDeviceIdentification(
        info_name={
            "VendorName": "Pymodbus",
            "ProductCode": "PM",
            "VendorUrl": "https://github.com/pymodbus-dev/pymodbus/",
            "ProductName": "Pymodbus Server",
            "ModelName": "Pymodbus Server",
            "MajorMinorRevision": pymodbus_version,
        }
    )
    return args


async def run_async_server(args):
    """Run server."""
    txt = f"### start ASYNC server, listening on {args.port} - {args.comm}"
    _logger.info(txt)
    if args.comm == "tcp":
        address = ("", args.port) if args.port else None
        server = await StartAsyncTcpServer(
            context=args.context,  # Data storage
            identity=args.identity,  # server identify
            address=address,  # listen address
            framer=args.framer,  # The framer strategy to use
            allow_reuse_address=True,  # allow the reuse of an address
        )
    elif args.comm == "serial":
        server = await StartAsyncSerialServer(
            context=args.context,  # Data storage
            identity=args.identity,  # server identify
            port=args.port,  # serial port
            framer=args.framer,  # The framer strategy to use
            baudrate=args.baudrate,  # The baud rate to use for the serial device
        )
    return server

if __name__ == "__main__":
    run_args = setup_server(description="Run asynchronous server.")
    asyncio.run(run_async_server(run_args), debug=True)

test.py:

import time
from pymodbus.client import ModbusTcpClient
client = ModbusTcpClient("127.0.0.1",5020)

battery_address = 2

# addres, value count
registers=  [(0, 1),
            (1, 1),
            (2, 16),
            (18, 11),
            (29, 2),
            (31, 4),
            (33, 2),
            (61, 11),
            (80, 4),
            (90, 11),
            (104, 24),
            (117, 6)]

for register in registers:
    print('Reading holding register Offset {:d}, {:d} value(s)'.format(register[0], register[1]))
    for i in range(0, register[1]):
        time.sleep(0.1)
        request = client.read_holding_registers(register[0]+i,1,battery_address)
        if request.function_code < 0x80:
            print('register {:d} : {:d}'.format(register[0]+i,request.registers[0]))
        else:
            print('register {:d} error:'.format(register[0]+i))
            print(request)

thanks for the patience!

@neosoyo neosoyo closed this as completed Apr 27, 2023
@github-actions github-actions bot locked as resolved and limited conversation to collaborators May 8, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants