跳到主要内容

常见问题

一、通用问题

1. Modbus地址可以只写地址0吗,一定要写成类似400001?

按照PLC Modbus寄存器的格式,需要以区域号为起始字符,后续加上(寄存器地址+1)。这是因为Modbus协议规定了不同类型寄存器的地址范围:

  • 线圈寄存器:地址范围 00001-09999,格式为 0xxxx
  • 离散输入寄存器:地址范围 10001-19999,格式为 1xxxx
  • 输入寄存器:地址范围 30001-39999,格式为 3xxxx
  • 保持寄存器:地址范围 40001-49999,格式为 4xxxx

所以,保持寄存器地址0必须写成400001。

2. 数据如何设置小数位

网关提供灵活的脚本式配置转换,可以在变量的读取表达式中进行配置转换。以下是几种常见的小数位设置方法:

方法一:使用Math.Round函数

// 设置小数位为2
Math.Round(raw.ToDecimal(), 2)

// 设置小数位为1
Math.Round(raw.ToDecimal(), 1)

方法二:使用乘法和除法

// 将整数转换为小数(例如,原值乘以0.01)
raw.ToDecimal() * 0.01

// 将整数转换为小数(例如,原值除以100)
raw.ToDecimal() / 100

方法三:使用字符串格式化

// 格式化为2位小数
raw.ToDecimal().ToString("F2")

3. 源码打开razor文件时,不出现智能提示,有waring警告(波浪线)

这是Visual Studio的常见问题,可能由多种原因导致。可以尝试以下解决方案:

  1. 升级Visual Studio:确保使用最新版本的Visual Studio
  2. 清理项目文件
    • 删除工程目录下的.vs文件夹、bin文件夹和obj文件夹
    • 重新打开解决方案
  3. 重置Visual Studio设置
    • 打开Visual Studio命令提示符(以管理员身份运行)
    • 执行命令:devenv /ResetSettings
  4. 修复Visual Studio
    • 在控制面板中选择"修复Visual Studio"
    • 等待修复完成后重新启动
  5. 检查项目引用:确保所有项目引用都正确,没有缺失或错误的引用

4. 报警属性中的报警约束如何定义

报警约束和变量表达式类似,填入脚本,返回值为true时,报警生效。报警约束可以实现更复杂的报警逻辑,例如基于多个变量的组合条件。

示例1:基于单个变量的约束

// 当温度变量大于25度时,湿度报警才生效
GlobalData.GetVariable("环境监控", "温度").Value.ToDecimal() > 25

示例2:基于多个变量的约束

// 新建testInt1,testInt2两个变量

// 在testInt1的高高报警值为1,开启使能
// 在testInt1的高高报警约束中定义testInt2>10

// testInt1为8,testInt2为11时,产生testInt1报警
// testInt1为8,testInt2为10时,不会产生testInt1报警

// 复杂约束示例:当testInt2>10且testInt3<5时,报警生效
GlobalData.GetVariable("设备名称", "testInt2").Value.ToInt() > 10 &&
GlobalData.GetVariable("设备名称", "testInt3").Value.ToInt() < 5

5. 启动项目之后,驱动调试页面没有任何信息,设备选择插件时也不出现任何选择项

这通常是因为网关插件未正确编译或部署。解决方案:

  1. 编译解决方案

    • 在Visual Studio中打开解决方案
    • 选择"生成" > "生成解决方案"
    • 确保编译过程没有错误
  2. 检查插件目录

    • 确保插件DLL文件已成功拷贝到插件目录(Plugins)
    • 对于开发环境,插件会自动复制到输出目录
    • 对于部署环境,需要手动复制插件到Plugins目录
  3. 检查插件依赖

    • 确保插件所需的依赖项都已正确安装
    • 检查插件的目标框架是否与网关一致
  4. 查看日志

    • 查看网关日志文件,了解插件加载过程中的错误信息

6. Linux部署时发现无法启动,报错:The type initializer for 'Microsoft.Data.sqlite.Sqliteconnection' threw an exception.

这是因为Linux系统缺少SQLite所需的依赖库。解决方案:

  1. 检查操作系统版本

  2. 安装SQLite依赖

    • 在Ubuntu/Debian系统上:
      sudo apt-get update
      sudo apt-get install libsqlite3-dev
    • 在CentOS/RHEL系统上:
      sudo yum install sqlite-devel
  3. 升级SQLite版本

  4. 使用.NET 6发布

    • 如果上述方法都无法解决,可以考虑使用.NET 6发布ThingsGateway项目

二、变量配置

7. 我想在当前设备中添加变量,该变量表示设备是否在线,不参与通讯

在变量地址中填写DeviceStatus,固定值为DeviceStatusEnum类型。可以通过读取表达式进行类型转换:

// 转换为布尔类型
(DeviceStatusEnum)raw == DeviceStatusEnum.OnLine

// 转换为字符串类型
((DeviceStatusEnum)raw).ToString()

// 转换为整数类型
((int)(DeviceStatusEnum)raw)

8. 我想在当前设备中添加变量,该变量作为计算点,不参与通讯

在变量地址中填写ScriptRead,在读取表达式中填写所需计算过程。计算点变量可以实现各种复杂的计算逻辑:

示例1:两个变量相加

// 不限制是否当前设备,只要变量名称存在,就可以正常运算
GlobalData.GetVariable("设备名称1", "变量名称1").Value.ToInt() +
GlobalData.GetVariable("设备名称2", "变量名称2").Value.ToInt()

示例2:计算平均值

// 计算多个变量的平均值
(GlobalData.GetVariable("设备名称", "变量1").Value.ToDecimal() +
GlobalData.GetVariable("设备名称", "变量2").Value.ToDecimal() +
GlobalData.GetVariable("设备名称", "变量3").Value.ToDecimal()) / 3

示例3:条件计算

// 根据条件返回不同的值
if (GlobalData.GetVariable("设备名称", "温度").Value.ToDecimal() > 30)
{
return "高温";
}
else if (GlobalData.GetVariable("设备名称", "温度").Value.ToDecimal() < 0)
{
return "低温";
}
else
{
return "正常";
}

9. 变量单独设置大小端解析顺序

在变量地址中添加DATA=参数,可以设置变量的大小端解析顺序:

  • DATA=ABCD:大端顺序(高位在前,低位在后)
  • DATA=DCBA:小端顺序(低位在前,高位在后)
  • DATA=BADC:混合端顺序1
  • DATA=CDAB:混合端顺序2

示例1:Modbus读取浮点数,保持寄存器0,大端顺序

400001;DATA=ABCD;

示例2:Modbus读取双字整数,保持寄存器2,小端顺序

400003;DATA=DCBA;

三、部署问题

10. Windows服务部署时无法启动

可能的原因及解决方案:

  1. 服务权限不足

    • 确保服务以管理员身份运行
    • 在服务属性中设置"登录"选项卡的账户为管理员账户
  2. 配置文件路径问题

    • 确保配置文件在正确的位置(与可执行文件同目录)
    • 检查配置文件的权限是否正确
  3. 端口被占用

    • 检查默认端口5000是否被其他程序占用
    • 使用命令netstat -ano | findstr :5000查看端口占用情况
    • 修改App.json配置文件中的端口号
  4. 依赖项缺失

    • 确保所有必要的依赖项都已安装
    • 检查.NET运行时是否正确安装
  5. 日志查看

    • 查看Windows事件日志,了解具体错误信息
    • 查看网关日志文件,了解启动过程中的错误

11. Docker部署时如何配置网络

Docker部署时,有多种网络配置方式:

方法一:使用主机网络

docker run --name thingsgateway --network host --restart=always -d thingsgateway:latest

优点:容器与主机共享网络,无需端口映射,适用于需要访问局域网设备的场景 缺点:可能会与主机网络产生冲突

方法二:使用端口映射

docker run --name thingsgateway -p 5000:5000 -p 5001:5001 --restart=always -d thingsgateway:latest

优点:网络隔离,安全性高 缺点:需要手动映射所有需要的端口

方法三:使用自定义网络

# 创建自定义网络
docker network create tg-network

# 运行容器
docker run --name thingsgateway --network tg-network -p 5000:5000 --restart=always -d thingsgateway:latest

优点:可以在多个容器之间创建隔离的网络环境 缺点:配置相对复杂