Hello,
I’ve checked this with our development team, and I’d like to share some insights. Currently, the Modbus MQTT Gateway service supports only two predefined data formats, and unfortunately, it isn’t natively adjustable through the WebUI in the way you described for customizing RX messages.
However, there’s a workaround solution developed by our programmer available by implementing a custom Lua service acting as a bridge between ThingsBoard and the device’s Modbus MQTT gateway. This Lua script essentially creates an additional MQTT client that listens for RPC requests from ThingsBoard, converts them into a format compatible with the Modbus MQTT Gateway, and forwards the response back to ThingsBoard.
Below you’ll find the full implementation steps for setting this up:
Installation & Setup
Install required Lua modules:
Download and upload the following .ipk packages to your device using SCP, FTP, or any preferred method:
luamqtt.ipk
luabitop_1.0.2-1_mipsel_24kc.ipk
(Note: luabitop modules needs to be compiled (unlike luamqtt is pure lua, thus it should work on any arch) I compiled for TRB2M, but any other arch can be compiled using SDK if you have other devices. Simply select luabitop lib in make menuconfig and take package from bin/ folder from SDK root.)
Install the packages:
Run:
opkg install /tmp/luabitop_1.0.2-1_<arch>.ipk
opkg install /tmp/luamqtt.ipk
Create and configure the Lua bridge script
touch /root/mqtt-modbus-gateway-adapter.lua
vim /root/mqtt-modbus-gateway-adapter.lua
Paste the following Lua code into the file (press i in vim to insert):
local HOSTNAME = "192.168.1.10"
local CLOUD_HOSTNAME = "eu.thingsboard.cloud"
local REQUEST_TOPIC = "v1/devices/me/rpc/request/+"
local REQUEST_TOPIC_CONVERTED = "request"
local RESPONSE_TOPIC = "response"
local RESPONSE_TOPIC_CONVERTED = "v1/devices/me/rpc/response/"
local TOKEN = "NyqmjbQdOGHsLPwHIn6V"
-- load mqtt and other modules
local mqtt = require("mqtt")
local json = require("luci.jsonc")
local util = require("vuci.util")
-- create mqtt client
-- this client will connect to Thingsboard cloud platform
local client = mqtt.client{
uri = CLOUD_HOSTNAME,
username = TOKEN,
clean = true,
}
-- Thingsboard cloud platform trial account accepts only one client connections
-- so I decided to create another client that will connect to local broker
-- where MQTT Modbus Gateway is connected
-- should be done with one broker only with different topics
local device = mqtt.client{
uri = HOSTNAME,
clean = true,
}
print("created MQTT client", client)
client:on{
connect = function(connack)
if connack.rc ~= 0 then
print("connection to broker failed:", connack:reason_string(), connack)
return
end
print("connected:", connack) -- successful connection
-- subscribe to test topic and publish message after it
assert(client:subscribe{ topic=REQUEST_TOPIC, qos=1, callback=function(suback)
print("subscribed:", suback)
end})
end,
message = function(msg)
assert(client:acknowledge(msg))
print("received:", msg)
request_id = string.sub(msg.topic,
string.len(RESPONSE_TOPIC_CONVERTED),
string.len(msg.topic))
print("request_id:", request_id)
local payload = json.parse(msg.payload)
util.dumptable(payload)
if payload.method == "setValue" then
local response_payload = payload.params
print("response_payload:", response_payload)
assert(device:publish{
topic = REQUEST_TOPIC_CONVERTED,
payload = response_payload,
qos = 1
})
end
end,
error = function(err)
print("MQTT device client error:", err)
end,
}
device:on{
connect = function(connack)
if connack.rc ~= 0 then
print("connection to broker failed:", connack:reason_string(), connack)
return
end
print("connected to device:", connack) -- successful connection
assert(device:subscribe{ topic=RESPONSE_TOPIC, qos=1, callback=function(suback)
print("subscribed:", suback)
end})
end,
message = function(msg)
assert(device:acknowledge(msg))
print("received from device:", msg)
response_topic = RESPONSE_TOPIC_CONVERTED .. request_id
print("response_topic:", response_topic)
assert(client:publish{
topic = response_topic,
payload = msg.payload,
qos = 1
})
end,
error = function(err)
print("MQTT device client error:", err)
end,
}
mqtt.run_ioloop(client, device)
Customize the MQTT broker addresses, topics, and authentication tokens as per your ThingsBoard and Teltonika device configuration.
Create an init service script:
Create a new init script:
touch /etc/init.d/mqtt-modbus-gateway-adapter
vim /etc/init.d/mqtt-modbus-gateway-adapter
chmod 755 /etc/init.d/mqtt-modbus-gateway-adapter
Paste the following content:
#!/bin/sh /etc/rc.common
USE_PROCD=1
START=99
STOP=01
start_service() {
procd_open_instance
procd_set_param command /usr/bin/lua /root/mqtt-modbus-gateway-adapter.lua
procd_set_param respawn ${respawn_threshold:-0} ${respawn_timeout:-6} ${respawn_retry:-0}
procd_close_instance
}
Enable and start the service:
service mqtt-modbus-gateway-adapter enable
service mqtt-modbus-gateway-adapter start
Now the MQTT Modbus gateway should be reachable from a cloud. Additionally, you can create a separate service to directly handle Modbus commands using Lua libraries like lua-libmodbus or via ubus Modbus methods, if needed.
I hope this solution will help you achieve the integration flow you were aiming for. Should you have any further questions or need assistance, feel free to reach out.
Best regards,