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

[BUG] MODBUS Server don't do anything, don't attach to port #1672

Open
palandri opened this issue Feb 6, 2025 · 7 comments · May be fixed by #1675
Open

[BUG] MODBUS Server don't do anything, don't attach to port #1672

palandri opened this issue Feb 6, 2025 · 7 comments · May be fixed by #1675
Assignees
Labels

Comments

@palandri
Copy link

palandri commented Feb 6, 2025

Hello everyone.

Describe the issue
When configuring the MODBUS connector as Server (TCP or Serial), literally nothing happens. tb-gateway don't attach to port, no log message, literally nothing.

If I enable sendDataToThingsBoard, it open/attach to designated port, but start polling, working as a Client, but do not listen on the interface, only sending requests. This behaviour happens both in TCP or Serial mode. In serial, I can see traffic on the bus (the requests being sent by the Server).

I don't think this behaviour is correct... in my understanding, a Modbus Server should listen and respond to requests, not initiate requests to another device (which is the role of the client).

Also, to corroborate with the information shown above, if I ran a Server/Slave simulator on the bus, it answer correctly to the requests, showing (in my understanding) that the connector is indeed working as a Client/Master.

OTOH, running a Client/Master simulator on the bus, it keeps timing out, or gives a checksum error (I suppose when the requests conflict between the Simulator and the Server/Slave Connector (which is bad behaving as a Client/Master).

Before enabling sendDataToThingsBoard
Image

After enabling sendDataToThingsBoard (no restart, only enabling)
Image

Slave simulator answering the requests of the "Server"
Image

Master simulator timing out/giving error
Image

Configuration (Attach your configuration file)

{
"thingsboard": {
"host": "redacted",
"port": redacted,
"remoteShell": false,
"remoteConfiguration": true,
"latencyDebugMode": false,
"statistics": {
"enable": true,
"statsSendPeriodInSeconds": 3600
},
"deviceFiltering": {
"enable": false,
"filterFile": "list.json"
},
"maxPayloadSizeBytes": 8196,
"minPackSendDelayMS": 50,
"minPackSizeToSend": 500,
"checkConnectorsConfigurationInSeconds": 60,
"handleDeviceRenaming": true,
"security": {
"type": "accessToken",
"accessToken": "redacted"
},
"qos": 1,
"reportStrategy": {
"type": "ON_RECEIVED"
},
"checkingDeviceActivity": {
"checkDeviceInactivity": false,
"inactivityTimeoutSeconds": 300,
"inactivityCheckPeriodSeconds": 10
},
"rateLimits": "DEFAULT_TELEMETRY_RATE_LIMIT",
"dpRateLimits": "DEFAULT_TELEMETRY_DP_RATE_LIMIT",
"messagesRateLimits": "DEFAULT_MESSAGES_RATE_LIMIT",
"deviceMessagesRateLimits": "DEFAULT_MESSAGES_RATE_LIMIT",
"deviceRateLimits": "DEFAULT_TELEMETRY_RATE_LIMIT",
"deviceDpRateLimits": "DEFAULT_TELEMETRY_DP_RATE_LIMIT",
"ts": 1738785615970
},
"storage": {
"type": "memory",
"read_records_count": 100,
"max_records_count": 100000,
"data_folder_path": "./data/",
"max_file_count": 10,
"max_read_records_count": 10,
"max_records_per_file": 10000,
"data_file_path": "./data/data.db",
"messages_ttl_check_in_hours": 1,
"messages_ttl_in_days": 7,
"ts": 1738785615970
},
"grpc": {
"enabled": false,
"serverPort": 9595,
"keepAliveTimeMs": 10001,
"keepAliveTimeoutMs": 5000,
"keepAlivePermitWithoutCalls": true,
"maxPingsWithoutData": 0,
"minTimeBetweenPingsMs": 10000,
"minPingIntervalWithoutDataMs": 5000
},
"connectors": [
{
"type": "modbus",
"name": "Slave Connector",
"configuration": "slaveConnector.json"
}
]
}

Connector name (If you need help with some connector/converter):
MODBUS Connector

{
"master": {
"slaves": []
},
"name": "Slave Connector",
"id": "c45419da-fb11-4889-bb77-77f8153a3f21",
"slave": {
"type": "serial",
"method": "rtu",
"unitId": 100,
"baudrate": 9600,
"deviceName": "redacted",
"deviceType": "default",
"pollPeriod": 0,
"sendDataToThingsBoard": false,
"byteOrder": "LITTLE",
"wordOrder": "LITTLE",
"identity": {
"vendorName": "redacted",
"productCode": "redacted",
"vendorUrl": "redacted",
"productName": "redacted",
"modelName": "redacted"
},
"values": {
"holding_registers": {
"attributes": [],
"timeseries": [
{
"tag": "teste",
"value": "0",
"type": "bytes",
"address": 2,
"objectsCount": 1
}
],
"attributeUpdates": [],
"rpc": []
},
"coils_initializer": {
"attributes": [],
"timeseries": [],
"attributeUpdates": [],
"rpc": []
},
"input_registers": {
"attributes": [],
"timeseries": [],
"attributeUpdates": [],
"rpc": []
},
"discrete_inputs": {
"attributes": [
{
"tag": "input",
"value": "12",
"type": "bytes",
"address": 2,
"objectsCount": 1
}
],
"timeseries": [],
"attributeUpdates": [],
"rpc": []
}
},
"port": "/dev/ttyS0"
},
"logLevel": "TRACE",
"enableRemoteLogging": false,
"configVersion": "3.6.3"
}

Versions (please complete the following information):

  • OS: RaspberryOS, tb-gateway running on Docker
  • Thingsboard IoT Gateway version: 3.7.0

--- the TL;DR is: Modbus Server don't act as a Server, but as a Client

Help please :)

@imbeacon
Copy link
Member

imbeacon commented Feb 7, 2025

Hi @palandri,

Thank you for your interest in ThingsBoard IoT Gateway.
You are particularly right, the gateway in case of using it as a server - creates server and client to collect data from it. It works in most cases, except serial. We will try to find another way to collect data from the server and send it to ThingsBoard.

@imbeacon imbeacon added bug and removed help wanted labels Feb 7, 2025
@palandri
Copy link
Author

palandri commented Feb 7, 2025

Hi @imbeacon, thanks for the answer.

I'm studying the implementation of the MODBUS connector, and probably will write an extension to this specific use case. If there is interest, I can share it when it is done, no problem at all.

@imbeacon
Copy link
Member

imbeacon commented Feb 8, 2025

We appreciate any contribution and participation in project life and we will be glad to see your solution for this case.

@palandri
Copy link
Author

palandri commented Feb 9, 2025

I have been working on some proof-of-concept about this subject, and want to report/register my findings.

As @imbeacon said, the current implementation of the modbus server create both a server (to receive data from the bus) and a client (to read the data and send to uplink), essentially requesting data to yourself over the bus. This approach works on TCP/UDP, but not Serial, as you can't attach both a server and a client on the same serial resource.

The above paragraph explains why - at least on serial - the connector behaves as a client: The client is instantiated before the server, attaching to the serial port and not letting the server attach to it (my thoughts, exactly). But in modbus_connector.py, the server is instantiated AFTER the client (server starts in line 162 and client on the next line, inside the method __add_slave (when the Slave class is instantiated, here, so I'm confused 😅)

Anyway, as I need only a Server, I started to write an extension to simply listen on a specific unitId on the bus, and send the received data to Thingsboard. Starting from pymodbus examples (server_async.py specifically), I encountered my first problem: ModbusSerialServer from pymodbus don't attach to serial port (essentially, the example don't work).

I noticed that Thingsboard Gateway uses an old version of pymodbus (3.0.0), so I tried the same example on latest release (3.8.4), and it worked. Pymodbus release 3.0.0 is faulty, the easiest fix is change to 3.0.2 (latest of the 3.0.x release). This should not need any modification on the actual base code.

UPDATE

I managed to understand what is happening about the whole "server-before-client" shenanigans. Turns out the class ModbusSerialServer needs a start() before .serve_forever(), which is different than the other Modbus<type>Server. Also, as I stated before, pymodbus 3.0.0 don't work. I'll start a PR soon addressing both issues.

Anyway, the underlying problem still exists, which is: it is not possible to coexist a server and a client on the same hardware port. This is not a problem for me atm, but it is a major paradigm in current archetype of the modbus connector.

@imbeacon what do you think about splitting the connector in two variants, Server and Client? Or, we could keep the connector as is, and create another connector specific to modbus serial, which will be a Client OR a Server?

@imbeacon
Copy link
Member

Hi @palandri,

I appreciate your investigation, and you’re absolutely right about the library version—thanks for catching that.

Regarding the question about the working mode, I’m not entirely convinced that having a mode and related functionality is the right approach. It doesn’t seem like it would change the current behavior, except for the additional client being created to read data from the slave. However, this can be easily worked around by preventing slave creation when a serial server is used. That said, this approach wouldn’t allow us to retrieve data on ThingsBoard.

My focus has been on finding a way to extract data from the server in real time without introducing an additional client, as is currently the case. We are exploring the possibility of retrieving information directly from the running server, potentially by leveraging DataSparseBlocks or by using another method.

In my opinion, the best solution would be to eliminate the additional client for servers entirely and collect data for ThingsBoard directly from running servers. Another alternative is to implement this logic exclusively for the serial server.

As for your question, I believe you could keep this connector but introduce an additional entity, such as a “Starter” or “Initializer,” to handle server initialization and startup. Alternatively, you could use two separate methods to start different servers and manage data collection. Splitting the connector would unfortunately create UI configuration challenges and require extra work from the design and front-end teams, so we’d prefer to avoid that.

Ultimately, you can implement the solution in a way that works best for you, and we will integrate it with the existing connector once it’s ready.

@palandri
Copy link
Author

Hello @imbeacon, thanks for your input on the subject.

We are exploring the possibility of retrieving information directly from the running server, potentially by leveraging DataSparseBlocks or by using another method.

This is exactly my approach. I will share my implementation as soon as it is done.

Regarding the question about the working mode, I’m not entirely convinced that having a mode and related functionality is the right approach. It doesn’t seem like it would change the current behavior, except for the additional client being created to read data from the slave.

Indeed, you are right. But I was talking about working as a pure client or a pure master.

My understanding is that currently, the modbus connector works as a Client (master{} block) AND as a Server (slave{} block), where working as a Server, it spawns a "internal" client to read data from the server. I was not referring to the "internal" client, but rather, the coexistence of a master{} and slave{} blocks while the same serial port.

I don't think this is a problem, just a "quirk". A simple check to see if the connector is using the same serial port on both master{} and slave{] would suffice. This would allow to keep the current implementation of the connector, as it works, and this serial behaviour is an edge case.

@palandri palandri changed the title [HELP] MODBUS Server don't do anything, don't attach to port [BUG] MODBUS Server don't do anything, don't attach to port Feb 10, 2025
@palandri
Copy link
Author

Hello everyone.

I created a PR reflecting the overall discuting and understanding around this issue, if anyone is interested: PR 1675

@imbeacon thanks for your input about the subject, and at your discretion, if possible, check my PR. I'm looking forward some constructive criticism.

Thanks in advance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
3 participants