Windows下载modbus模拟器
- 安装串口模拟工具Virtual Serial Port Kit http://www.opdown.com/soft/125086.html
- 安装Modbus从设备仿真器 ModbusSlave https://www.jb51.net/softs/597224.html#downintro2
- 安装Modbus主机仿真器 Modbus Poll https://mip.onlinedown.net/soft/978634.htm
Mac下载
- Appstore 搜索安装 ModRtuTcp
配置模拟器
port kit
Slave
A.Slave为Modbus从站地址,对应主画面中的ID值,默认为1。
B. Function 为寄存器功能码的选择,共四种,分别对应关系如下
C. Address 为寄存器起始地址。默认从1开始。
D. Length为寄存器连续个数。默认为10个。
Poll
配置Thingsboard gateway
源码安装(略)
见
配置修改 modbus.json
{
"master": {
"slaves": [
{
"host": "192.168.0.74",
"port": 502,
"type": "tcp",
"method": "socket",
"timeout": 35,
"byteOrder": "LITTLE",
"wordOrder": "LITTLE",
"retries": true,
"retryOnEmpty": true,
"retryOnInvalid": true,
"pollPeriod": 5000,
"unitId": 1,
"deviceName": "Temp Sensor",
"sendDataOnlyOnChange": false,
"connectAttemptTimeMs": 5000,
"connectAttemptCount": 5,
"waitAfterFailedAttemptsMs": 300000,
"attributes": [
{
"tag": "certificateNumber",
"type": "8int",
"functionCode": 4,
"objectsCount": 1,
"address": 0
},
{
"tag": "string_read",
"type": "string",
"functionCode": 3,
"objectsCount": 4,
"address": 1
},
{
"tag": "bits_read",
"type": "bits",
"functionCode": 3,
"objectsCount": 1,
"address": 5
},
{
"tag": "8int_read",
"type": "8int",
"functionCode": 3,
"objectsCount": 1,
"address": 6
},
{
"tag": "16int_read",
"type": "16int",
"functionCode": 3,
"objectsCount": 1,
"address": 7
},
{
"tag": "32int_read_divider",
"type": "32int",
"functionCode": 3,
"objectsCount": 2,
"address": 8,
"divider": 10
},
{
"tag": "8int_read_multiplier",
"type": "8int",
"functionCode": 3,
"objectsCount": 1,
"address": 10,
"multiplier": 10
},
{
"tag": "32int_read",
"type": "32int",
"functionCode": 3,
"objectsCount": 2,
"address": 11
},
{
"tag": "64int_read",
"type": "64int",
"functionCode": 3,
"objectsCount": 4,
"address": 13
}
],
"timeseries": [
{
"tag": "8uint_read",
"type": "8uint",
"functionCode": 3,
"objectsCount": 1,
"address": 17
},
{
"tag": "16uint_read",
"type": "16uint",
"functionCode": 3,
"objectsCount": 2,
"address": 18
},
{
"tag": "32uint_read",
"type": "32uint",
"functionCode": 3,
"objectsCount": 4,
"address": 20
},
{
"tag": "64uint_read",
"type": "64uint",
"functionCode": 3,
"objectsCount": 1,
"address": 24
},
{
"tag": "16float_read",
"type": "16float",
"functionCode": 3,
"objectsCount": 1,
"address": 25
},
{
"tag": "32float_read",
"type": "32float",
"functionCode": 3,
"objectsCount": 2,
"address": 26
},
{
"tag": "64float_read",
"type": "64float",
"functionCode": 3,
"objectsCount": 4,
"address": 28
},
{
"tag": "string_read",
"type": "string",
"functionCode": 3,
"objectsCount": 4,
"address": 36
}
],
"attributeUpdates": [
{
"tag": "shared_attribute_write",
"type": "32int",
"functionCode": 6,
"objectsCount": 2,
"address": 29
}
],
"rpc": [
{
"tag": "setValue",
"type": "bits",
"functionCode": 5,
"objectsCount": 1,
"address": 31
},
{
"tag": "getValue",
"type": "bits",
"functionCode": 1,
"objectsCount": 1,
"address": 31
},
{
"tag": "setCPUFanSpeed",
"type": "32int",
"functionCode": 16,
"objectsCount": 2,
"address": 33
},
{
"tag": "getCPULoad",
"type": "32int",
"functionCode": 3,
"objectsCount": 2,
"address": 35
}
]
}
]
},
"slave": {
"type": "tcp",
"host": "192.168.0.74",
"port": 502,
"method": "socket",
"deviceName": "Modbus Slave Example",
"deviceType": "default",
"pollPeriod": 5000,
"sendDataToThingsBoard": false,
"byteOrder": "LITTLE",
"wordOrder": "LITTLE",
"unitId": 0,
"values": {
"holding_registers": [
{
"attributes": [
{
"address": 1,
"type": "string",
"tag": "sm",
"objectsCount": 1,
"value": "ON"
}
],
"timeseries": [
{
"address": 2,
"type": "int",
"tag": "smm",
"objectsCount": 1,
"value": "12334"
}
],
"attributeUpdates": [
{
"tag": "shared_attribute_write",
"type": "32int",
"functionCode": 6,
"objectsCount": 2,
"address": 29,
"value": 1243
}
],
"rpc": [
{
"tag": "setValue",
"type": "bits",
"functionCode": 5,
"objectsCount": 1,
"address": 31,
"value": 22
}
]
}
],
"coils_initializer": [
{
"attributes": [
{
"address": 5,
"type": "string",
"tag": "sm",
"objectsCount": 1,
"value": "12"
}
],
"timeseries": [],
"attributeUpdates": [],
"rpc": []
}
]
}
}
}
修改thingsboard.json
"connectors": [
{
"name": "Modbus Connector",
"type": "modbus",
"configuration": "modbus.json"
}
]
启动成功
出现下面语句表示启动正常
"2023-09-26 18:00:29" - |INFO| - [tb_loader.py] - tb_loader - import_module - 68 - Import ModbusConnector from /thingsboard-gateway/thingsboard_gateway/connectors/modbus.
"2023-09-26 18:00:29" - |INFO| - [tb_gateway_service.py] - tb_gateway_service - __init__ - 298 - Gateway started.
启动失败
- cryptography版本过低问题
[tb_loader.py] - tb_loader - import_module - 75 - deprecated() got an unexpected keyword argument 'name'"
原因是因为cryptography 3.4版本与新版OpenSSL不兼容导致,需要升级,修改requirements.txt,cryptography==41.0.3
- pymodbus版本问题,修改为3.0.0版本 pymodbus==3.0.0
模拟器与gateway处理关键细节说明
pymodbus 连接测试
modbus的连接主要是用的 pymodbus 3.0.0,在初期连接不上时,可以用下面的代码进行简单测试
from pymodbus.client import ModbusTcpClient
from thingsboard_gateway.connectors.modbus.modbus_converter import ModbusConverter
client = ModbusTcpClient("192.168.0.74",502,timeout=1)
class CustomModbusConverter(ModbusConverter):
def __init__(self, config, logger):
self._log = logger
self.__config = config.get('converter')
@property
def config(self):
return self.__config
def main(cmdline=None):
"""Combine setup and run."""
request1 = client.read_coils(0, 10, slave=2)
result1 = request1.bits
client.write_coil(1,True,2)
# print(result.bits[0])
print(result1)
client.close()
if __name__ == "__main__":
main()
其中slave是标识ID,read_coils 是读取状态配置,要将Funcion修改为01
运行后可以出现布尔数组标识可以连上modbus了,否则继续排查下网关连接
网关字段类型说明
- 定义的类型需要与functionCode对应起来
- objectsCount表示该字段的长度范围
- 注意address地址长度的匹配
{
"tag": "certificateNumber",
"type": "8int",
"functionCode": 4,
"objectsCount": 1,
"address": 0
},
{
"tag": "string_read",
"type": "string",
"functionCode": 3,
"objectsCount": 4,
"address": 1
},
{
"tag": "bits_read",
"type": "bits",
"functionCode": 3,
"objectsCount": 1,
"address": 5
},
如何使用modbus传递字符串
如果要将字符串 “a” 模拟传递给 Modbus Slave 工具中定义的长度为 4 位的字段,将字符串 “a” 转换为字节数组,元素的值是 97,是字符 “a” 的 ASCII 码值,并将其存储在保持寄存器中:
字节数组:[0, 0, 0, 97]
如何在gateway中添加多个设备
https://github.com/thingsboard/thingsboard-gateway/issues/1118
启动成功页面上变化
最新遥测数据每10秒更新,这里要注意属性,将只变化才发送的选项关闭,否则不会更新,要么就去修改值后再观察
“sendDataOnlyOnChange”: false