跳到主要内容

MqttClient

提示

通过自定义脚本,可快速适配业务模型,比如各大云平台的Iot物模型

概述

MqttClient 是一个基于 MQTT 协议的客户端插件,通过 TCP 或 WebSocket 方式与 MQTT Broker 建立连接,实现数据的定时发布或变化触发发布。该插件采用异步架构设计,支持多种安全配置和发布模式,适用于各种物联网场景的数据传输需求。

核心功能

  • 协议支持:完整支持 MQTT v3.1.1 和 MQTT v5.0 协议规范
  • 连接方式:支持标准 TCP 连接和 WebSocket 连接,满足不同网络环境需求
  • 安全机制:支持 TLS/SSL 加密传输,支持 CA 证书验证和客户端证书认证
  • 发布策略:支持三种发布模式:定时发布、变化触发发布、变化和定时结合发布
  • 数据组织:支持按变量分组属性上传数据,提高数据传输效率
  • 远程控制:内置 RPC 支持,可通过 MQTT 消息实现远程变量写入和设备控制
  • 平台适配:通过自定义脚本支持各种云平台物模型(ThingsBoard、阿里云、华为云等)
  • 可靠性:内置断线重连机制,支持消息缓存和离线恢复
  • 可扩展性:提供丰富的脚本接口,支持自定义数据处理逻辑

技术架构

  • 异步通信:基于 .NET 异步编程模型,提供高性能的数据传输
  • 消息队列:内置内存队列和文件缓存,确保数据可靠性
  • 模块化设计:插件化架构,易于集成和扩展
  • 配置灵活:支持详细的连接参数和发布参数配置

适用场景

  • 物联网设备数据上报:传感器数据、设备状态等信息的实时上传
  • 工业自动化数据采集:工业设备运行数据、生产指标的采集和传输
  • 云平台集成:与 ThingsBoard、阿里云 IoT、华为云 IoT 等平台的无缝集成
  • 实时监控系统:需要实时数据更新的监控场景
  • 边缘计算:边缘设备数据处理和云端同步
  • 传感器网络:分布式传感器网络的数据汇总和传输
  • 远程控制:通过 MQTT 实现设备的远程参数配置和控制

插件属性配置项

基本配置

属性说明备注
IPServer IP-
端口连接端口1883
详细日志False=>日志输出上传数量,True=>日志输出上传内容False
TLS启用 SSL/TLSFalse
CA 文件CA File-
客户端证书Client Certificate File-
客户端 key 文件Client Key File-
Websocket是否 WebSocket 连接False
WebSocketUrlWebSocket Urlws://127.0.0.1:8083/mqtt
用户名账号-
密码密码-
连接 Id连接 Id-
连接超时时间连接超时时间(毫秒)-
允许 Rpc 写入是否允许写入变量-
Rpc 写入主题写入变量的主题如果检测适配固定的 topic 标识,会按默认规则返回,比如thingsboard平台为v1/gateway/rpc 。默认规则为:固定通配 RpcWrite/+ ,其中 RpcWrite 为该属性填入内容,+ 通配符是请求 GUID 值;返回结果主题会在主题后添加 Response , 也就是RpcWrite/+/Response
Rpc 请求数据主题该主题接受到任何消息都会发布全部信息到对应的变量/设备/报警主题中-
分组上传启用后,无论是定时还是变化模式,始终会上传变量分组属性为 key 分组的全部变量 。在变化模式时,每次变量变化都会触发一次组上传False
选择全部变量选择全部变量False
设备状态列表上传设备是否列表上传,false 时每个设备实体都会单独发布,注意性能需求,默认为 true-
变量列表上传变量是否列表上传,false 时每个变量实体都会单独发布,注意性能需求,默认为 true-
报警列表上传报警是否列表上传,false 时每个报警实体都会单独发布,注意性能需求,默认为 true-
设备 Topic设备实体的发布主题 ,使用${key}作为匹配项,key 必须是上传实体中的属性-
变量 Topic变量实体的发布主题 ,使用${key}作为匹配项,key 必须是上传实体中的属性-
报警 Topic报警实体的发布主题 ,使用${key}作为匹配项,key 必须是上传实体中的属性-
设备实体脚本脚本返回新的实体列表,动态类中需继承DynamicModelBase,传入列表为DeviceData,查看以下具体属性编辑页面中,可通过检查按钮验证脚本
变量实体脚本脚本返回新的实体列表,动态类中需继承DynamicModelBase,传入列表为VariableBasicData,查看以下具体属性编辑页面中,可通过检查按钮验证脚本
报警实体脚本脚本返回新的实体列表,动态类中需继承DynamicModelBase,传入列表为AlarmVariable,查看以下具体属性编辑页面中,可通过检查按钮验证脚本
选择全部变量是否选择全部变量,true 时不需要单个变量添加业务属性-
上传模式间隔/变化/变化和间隔同时生效-
定时上传间隔间隔执行时间-
严格入队模式启用后,每次定时上传时,保证一组数据在同一时间点可见-
启用缓存是否启用缓存-
缓存文件最大长度(mb)缓存文件最大长度-
上传每页条数每一次上传的列表最大数量-
内存队列最大数量内存队列的最大数量,超出或失败时转入文件缓存,根据数据量设定适当值-

变量业务属性

基本配置

属性说明备注
启用 RPC单独配置变量是否允许写入true
Enable是否启用true

RPC 远程控制

概述

MqttClient 支持通过 MQTT 协议实现远程过程调用(RPC),允许从 MQTT Broker 向设备发送控制命令,实现变量写入和设备操作。该功能支持标准 MQTT RPC 模式和各大云平台的 RPC 协议格式。

提示

如果检测到适配固定的 topic 标识,会按默认规则返回,比如thingsboard平台的 rpc 主题为v1/gateway/rpc

下面说明为 ThingsGateway 默认规则

1. RPC 请求格式

MqttRpc 的请求内容与 WebApi 一致,请求参数为Dictionary<string,Dictionary<string, string>>,示例:

{
"modbusDevice650922399363167":
{
"modbus41":"1",
"modbus42":"2"
}
}
  • 外层键:设备名称
  • 内层键:变量名称
  • 内层值:要写入的变量值

2. RPC 主题配置

请求主题

请求主题在配置属性中设置Rpc写入Topic,配置后实际格式为:

{Rpc写入Topic}/{请求ID}

其中:

  • Rpc写入Topic:在插件配置中设置的基础主题
  • 请求ID:自定义 GUID 或雪花 ID,用于标识请求

响应主题

响应主题自动生成,格式为:

{Rpc写入Topic}/{请求ID}/Response

3. RPC 响应格式

响应内容包含操作结果信息:


public int OperCode { get; set; } // 操作代码,0 表示成功
public bool IsSuccess => OperCode == null || OperCode == 0; // 是否成功
public string? ErrorMessage { get; set; } // 错误信息

4. RPC 安全配置

参数说明默认值建议值
允许 Rpc 写入全局启用/禁用 RPC 写入true生产环境建议启用
启用 RPC变量级别的 RPC 启用控制true根据变量重要性设置
Rpc 写入主题RPC 请求主题前缀RpcWrite使用有意义的主题名称

5. Rpc 脚本

脚本类定义

using MQTTnet;

using Newtonsoft.Json.Linq;

using System.Text;

using ThingsGateway.Foundation;
using ThingsGateway.NewLife.Extension;
using ThingsGateway.NewLife.Json.Extension;

namespace ThingsGateway.Plugin.Mqtt;

public abstract class DynamicMqttClientRpcBase
{
/// <summary>
///触发rpc脚本调用
/// </summary>
/// <param name="logMessage">日志对象</param>
/// <param name="args">InterceptingPublishEventArgs</param>
/// <param name="driverPropertys">插件属性</param>
/// <param name="mqttClient">mqttServer</param>
/// <param name="getRpcResult">传入clientId和rpc数据(设备,变量名称+值字典),返回rpc结果</param>
/// <param name="tryMqttClientAsync">尝试连接</param>
/// <param name="cancellationToken">cancellationToken</param>
/// <returns></returns>
public virtual async Task RPCInvokeAsync(TouchSocket.Core.ILog logMessage, MqttApplicationMessageReceivedEventArgs args, MqttClientProperty driverPropertys, MQTTnet.IMqttClient mqttClient, Func<string, Dictionary<string, Dictionary<string, JToken>>, ValueTask<Dictionary<string, Dictionary<string, IOperResult>>>> getRpcResult, Func<CancellationToken, ValueTask<OperResult>> tryMqttClientAsync, CancellationToken cancellationToken)
{


}
}

RPC 脚本 demo

using MQTTnet;

using Newtonsoft.Json.Linq;

using System.Text;

using ThingsGateway.Foundation;
using ThingsGateway.NewLife.Extension;
using ThingsGateway.NewLife.Json.Extension;

using ThingsGateway.Plugin.Mqtt;


public class DynamicMqttClientRpc:DynamicMqttClientRpcBase
{
/// <summary>
///触发rpc脚本调用
/// </summary>
/// <param name="logMessage">日志对象</param>
/// <param name="args">InterceptingPublishEventArgs</param>
/// <param name="driverPropertys">插件属性</param>
/// <param name="mqttClient">mqttServer</param>
/// <param name="getRpcResult">传入clientId和rpc数据(设备,变量名称+值字典),返回rpc结果</param>
/// <param name="tryMqttClientAsync">尝试连接</param>
/// <param name="cancellationToken">cancellationToken</param>
/// <returns></returns>
public override async Task RPCInvokeAsync(TouchSocket.Core.ILog logMessage, MqttApplicationMessageReceivedEventArgs args, MqttClientProperty driverPropertys, MQTTnet.IMqttClient mqttClient, Func<string, Dictionary<string, Dictionary<string, JToken>>, ValueTask<Dictionary<string, Dictionary<string, IOperResult>>>> getRpcResult, Func<CancellationToken, ValueTask<OperResult>> tryMqttClientAsync, CancellationToken cancellationToken)
{

if (driverPropertys.RpcWriteTopic.IsNullOrWhiteSpace()) return;
if(args.ApplicationMessage.Topic != driverPropertys.RpcWriteTopic) return;


var rpcDatas = Encoding.UTF8.GetString(args.ApplicationMessage.Payload).FromJsonNetString<Dictionary<string, Dictionary<string, JToken>>>();
if (rpcDatas == null)
return;

var mqttRpcResult = await getRpcResult(args.ClientId, rpcDatas).ConfigureAwait(false);
try
{
var isConnect = await tryMqttClientAsync(CancellationToken.None).ConfigureAwait(false);
if (isConnect.IsSuccess)
{

var variableMessage = new MqttApplicationMessageBuilder()
.WithTopic($"{args.ApplicationMessage.Topic}/Response")
.WithPayload(mqttRpcResult.ToSystemTextJsonString(driverPropertys.JsonFormattingIndented)).Build();
await mqttClient.PublishAsync(variableMessage, cancellationToken).ConfigureAwait(false);


}
}
catch
{
}
}
}

设备/变量/报警/事件数据脚本收集

1. 设备/变量/报警/事件数据脚本开发指南

1.1 脚本基类

public abstract class DynamicModelBase : IDynamicModel
{
public TouchSocket.Core.ILog Logger { get; set; }
public abstract IEnumerable<dynamic> GetList(IEnumerable<object> datas);
}

1.2 脚本开发步骤

  1. 继承基类:实现 DynamicModelBase 接口
  2. 处理数据:在 GetList 方法中处理输入数据
  3. 返回结果:返回格式化后的动态对象列表
  4. 测试验证:使用脚本编辑页面的检查按钮验证脚本

2. 适配 ThingsBoard 脚本

对应文档:ThingsBoard

2.1 设备属性脚本

using TouchSocket.Core;

public class ThingsBoardDeviceScript : DynamicModelBase
{
public IEnumerable<dynamic> GetList(IEnumerable<object> datas)
{
Dictionary<string, Dictionary<string, object>> dict = new();

foreach (var v in datas)
{
var data = (DeviceBasicData)v;
Dictionary<string, object> deviceData = new()
{
{ "description", data.Description },
{ "activeTime", data.ActiveTime },
{ "deviceStatus", data.DeviceStatus.ToString() },
{ "pluginName", data.PluginName },
{ "remark1", data.Remark1 },
{ "remark2", data.Remark2 },
{ "remark3", data.Remark3 },
{ "remark4", data.Remark4 },
{ "remark5", data.Remark5 }
};

// 移除空值,减少消息大小
deviceData = deviceData.Where(x => x.Value != null).ToDictionary(x => x.Key, x => x.Value);
dict.AddOrUpdate(data.Name, deviceData);
}

return new List<dynamic> { dict };
}
}

2.2 变量脚本

using ThingsGateway.Foundation;
using TouchSocket.Core;

public class ThingsBoardVariableScript : DynamicModelBase
{
public IEnumerable<dynamic> GetList(IEnumerable<object> datas)
{
var dict = new Dictionary<string, List<ThingsBoardValue>>();

// 按设备名称分组
var deviceGroups = datas
.Where(a => !string.IsNullOrEmpty(((VariableBasicData)a).DeviceName))
.GroupBy(a => ((VariableBasicData)a).DeviceName, a => ((VariableBasicData)a));

foreach (var deviceGroup in deviceGroups)
{
// 按采集时间分组
var timeGroups = deviceGroup.GroupBy(a => a.CollectTime);
List<ThingsBoardValue> telemetryData = new();

foreach (var timeGroup in timeGroups)
{
ThingsBoardValue value = new();
value.ts = timeGroup.Key.DateTimeToUnixTimestamp();

foreach (var variable in timeGroup)
{
value.values.AddOrUpdate(variable.Name, variable.Value);
}

telemetryData.Add(value);
}

dict.AddOrUpdate(deviceGroup.Key, telemetryData);
}

return new List<dynamic> { dict };
}
}

public class ThingsBoardValue
{
public long ts { get; set; } // 时间戳
public Dictionary<string, object> values { get; set; } = new(); // 变量值
}

2.3 ThingsBoard 配置

配置项说明
变量 Topicv1/gateway/telemetry遥测数据主题
设备 Topicv1/gateway/attributes设备属性主题
Rpc Topicv1/gateway/rpcRPC 命令主题
变量列表上传false单条消息包含所有设备数据
设备状态列表上传false单条消息包含所有设备属性

3. 适配阿里云物模型脚本

对应文档:阿里云设备属性上报

3.1 变量脚本

public class AliYunIotScript : DynamicModelBase
{
public IEnumerable<dynamic> GetList(IEnumerable<object> datas)
{
List<AliYunIot> aliYunIots = new();

// 按设备 ID 分组(使用 Remark1 存储设备 ID)
var deviceGroups = datas
.Where(a => !string.IsNullOrEmpty(((VariableBasicData)a).Remark1))
.GroupBy(a => ((VariableBasicData)a).Remark1, a => ((VariableBasicData)a));

foreach (var deviceGroup in deviceGroups)
{
var requestId = Yitter.IdGenerator.YitIdHelper.NextId();
var iotId = deviceGroup.Key; // Remark1 作为设备 ID
var productKey = deviceGroup.FirstOrDefault(a => !string.IsNullOrEmpty(a.Remark2))?.Remark2; // Remark2 作为产品 Key
var deviceName = deviceGroup.FirstOrDefault(a => !string.IsNullOrEmpty(a.Remark3))?.Remark3; // Remark3 作为设备名称

AliYunIot aliYunIot = new();
aliYunIot.iotId = iotId;
aliYunIot.requestId = requestId.ToString();
aliYunIot.deviceName = deviceName;
aliYunIot.productKey = productKey;

foreach (var variable in deviceGroup)
{
var property = new Property
{
value = variable.Value,
time = new DateTimeOffset(variable.CollectTime).ToUnixTimeSeconds()
};
aliYunIot.items.Add(variable.Name, property);
}

aliYunIots.Add(aliYunIot);
}

return aliYunIots;
}
}

public class AliYunIot
{
public string iotId { get; set; }
public string requestId { get; set; }
public string productKey { get; set; }
public string deviceName { get; set; }
public Dictionary<string, Property> items { get; set; } = new();
}

public class Property
{
public object value { get; set; }
public long time { get; set; }
}

3.2 阿里云配置

配置项说明
变量 Topic/${productKey}/${deviceName}/thing/event/property/post属性上报主题
变量列表上传true每条消息对应一个设备
启用缓存true确保数据可靠性

设备/变量/报警/事件数据脚本传入数据参数参考

参数固定为IEnumerable<object> datas,实际转化类型如下

2. 数据实体类

2.1 设备数据实体

/// <summary>
/// 设备业务变化数据
/// </summary>
public class DeviceBasicData : IPrimaryIdEntity
{
public long Id { get; set; } // 设备 ID
public string Name { get; set; } // 设备名称
public DateTime ActiveTime { get; set; } // 活跃时间
public DeviceStatusEnum DeviceStatus { get; set; } // 设备状态
public string LastErrorMessage { get; set; } // 最后错误信息
public string PluginName { get; set; } // 插件名称
public string? Description { get; set; } // 设备描述
public string Remark1 { get; set; } // 备注1
public string Remark2 { get; set; } // 备注2
public string Remark3 { get; set; } // 备注3
public string Remark4 { get; set; } // 备注4
public string Remark5 { get; set; } // 备注5
}

2.2 变量数据实体

/// <summary>
/// 变量业务变化数据
/// </summary>
public class VariableBasicData : IPrimaryIdEntity
{
public long Id { get; set; } // 变量 ID
public string Name { get; set; } // 变量名称
public string DeviceName { get; set; } // 设备名称
public object Value { get; set; } // 变量值
public object RawValue { get; set; } // 原始值
public object LastSetValue { get; set; } // 最后设置值
public DateTime ChangeTime { get; set; } // 变化时间
public DateTime CollectTime { get; set; } // 采集时间
public bool IsOnline { get; set; } // 是否在线
public DeviceBasicData DeviceRuntime { get; set; } // 关联设备
public string? LastErrorMessage { get; set; } // 最后错误信息
public string? RegisterAddress { get; set; } // 寄存器地址
public string? Unit { get; set; } // 单位
public string? Description { get; set; } // 变量描述
public ProtectTypeEnum ProtectType { get; set; } // 保护类型
public DataTypeEnum DataType { get; set; } // 数据类型
public string Remark1 { get; set; } // 备注1
public string Remark2 { get; set; } // 备注2
public string Remark3 { get; set; } // 备注3
public string Remark4 { get; set; } // 备注4
public string Remark5 { get; set; } // 备注5
}

2.3 报警数据实体

/// <summary>
/// 报警变量
/// </summary>
public class AlarmVariable : PrimaryIdEntity, IDBHistoryAlarm
{
public string Name { get; set; } // 变量名称
public string? Description { get; set; } // 变量描述
public long CreateOrgId { get; set; } // 组织 ID
public long CreateUserId { get; set; } // 创建用户 ID
public long DeviceId { get; set; } // 设备 ID
public string DeviceName { get; set; } // 设备名称
public string RegisterAddress { get; set; } // 变量地址
public DataTypeEnum DataType { get; set; } // 数据类型
public string AlarmCode { get; set; } // 报警值
public string AlarmLimit { get; set; } // 报警限值
public string? AlarmText { get; set; } // 报警文本
public string RecoveryCode { get; set; } // 恢复值
public DateTime AlarmTime { get; set; } // 报警时间
public DateTime EventTime { get; set; } // 事件时间
public AlarmTypeEnum? AlarmType { get; set; } // 报警类型
public EventTypeEnum EventType { get; set; } // 事件类型
public string Remark1 { get; set; } // 备注1
public string Remark2 { get; set; } // 备注2
public string Remark3 { get; set; } // 备注3
public string Remark4 { get; set; } // 备注4
public string Remark5 { get; set; } // 备注5
}

常见问题与解决方案

Q1: 连接 MQTT 服务器失败怎么办?

A: 按照以下步骤排查:

  1. 网络连接检查

    • 确认 MQTT 服务器 IP 和端口配置正确
    • 使用 ping 命令测试网络连通性
    • 检查防火墙设置,确保端口已开放
    • 尝试使用 telnet 命令测试端口是否可访问
  2. 认证配置检查

    • 确认账号密码配置正确
    • 检查客户端 ID 是否唯一,避免冲突
    • 验证 MQTT 服务器是否启用了认证
  3. TLS 配置检查

    • 确认 TLS 选项配置正确
    • 检查 CA 证书文件是否有效
    • 验证客户端证书和密钥文件路径是否正确
    • 确认 MQTT 服务器 TLS 端口配置(通常为 8883)
  4. 服务器状态检查

    • 确认 MQTT 服务器是否正常运行
    • 检查 MQTT 服务器日志,查看是否有相关错误信息
    • 尝试使用 MQTT 客户端工具(如 MQTT.fx)测试连接

Q2: 发布数据失败怎么办?

A: 按照以下步骤排查:

  1. 连接状态检查

    • 确认 MQTT 连接是否正常
    • 检查 MQTT 客户端状态,是否处于已连接状态
    • 查看连接日志,确认是否有断线重连情况
  2. 主题配置检查

    • 检查主题格式是否正确
    • 确认 MQTT 服务器是否对主题有特殊要求
    • 验证主题是否包含非法字符
  3. 消息内容检查

    • 检查消息大小是否超过 MQTT 服务器限制(通常为 1MB)
    • 验证消息格式是否正确
    • 检查脚本是否正确处理数据
  4. 设备/变量配置检查

    • 确认设备和变量是否启用
    • 检查变量是否有采集数据
    • 验证分组上传配置是否正确

Q3: 如何适配不同的云平台?

A: 通过以下步骤适配不同的云平台:

  1. 平台文档研究

    • 查看目标云平台的 MQTT 协议文档
    • 了解平台要求的消息格式和主题结构
    • 熟悉平台的认证方式和安全要求
  2. 脚本开发

    • 根据平台要求编写对应的设备/变量脚本
    • 实现平台特定的数据格式转换
    • 处理平台的特殊字段和要求
  3. 配置调整

    • 配置正确的主题格式
    • 设置合适的 QoS 级别
    • 调整发布间隔和批量大小
  4. 测试验证

    • 使用测试设备验证数据上传是否成功
    • 检查云平台是否正确接收和处理数据
    • 验证 RPC 功能是否正常工作

Q4: 如何提高发布性能?

A: 采用以下优化策略:

  1. 网络优化

    • 使用 QoS 0 减少网络流量(适用于非关键数据)
    • 启用 TCP 持久连接
    • 合理设置心跳间隔,减少网络开销
  2. 发布策略优化

    • 根据数据重要性选择合适的发布模式
    • 合理设置发布间隔,避免过于频繁的发布
    • 合理配置上传分页条数,增加单次传输数据大小
  3. 脚本优化

    • 使用类型转换减少重复转换操作
    • 优化数据分组和处理逻辑
    • 减少字符串拼接和对象创建
  4. 缓存配置优化

    • 增加内存队列大小,提高并发处理能力
    • 启用文件缓存,确保数据可靠性
    • 调整上传批量大小,平衡吞吐量和延迟
  5. 硬件优化

    • 使用高性能网络设备
    • 确保服务器有足够的 CPU 和内存资源
    • 优化网络拓扑,减少网络跳数

Q5: 如何处理断线重连?

A: MqttClient 内置了完善的断线重连机制:

  1. 自动重连配置

    • MqttClient 会自动检测连接状态
    • 当连接断开时,会根据配置的重试策略进行重连
    • 默认的重连间隔会逐渐增加,避免对服务器造成压力
  2. 离线数据处理

    • 启用缓存功能,确保断线期间的数据不会丢失
    • 配置合适的缓存大小,平衡可靠性和存储开销
    • 启用离线恢复功能,在重连后自动上传缓存数据

Q6: 如何配置 TLS 连接?

A: 按照以下步骤配置 TLS 连接:

  1. 基础配置

    • 启用 TLS 选项
    • 配置 MQTT 服务器 TLS 端口(通常为 8883)
  2. 证书配置

    • 配置 CA 文件路径,用于验证服务器证书
    • 如需双向认证,配置客户端证书和密钥文件路径
    • 确保证书文件格式正确(通常为 PEM 格式)
  3. 高级配置

    • 可以配置 TLS 版本,建议使用 TLS 1.2 或更高版本
    • 可以设置证书验证模式,如严格验证或宽松验证
    • 对于自签名证书,需要特殊配置验证选项
  4. 测试验证

    • 使用 MQTT 客户端工具测试 TLS 连接
    • 检查连接日志,确认 TLS 握手是否成功
    • 验证数据传输是否加密

Q7: 如何使用 WebSocket 连接?

A: 按照以下步骤配置 WebSocket 连接:

  1. 基础配置

    • 启用 WebSocket 选项
    • 配置 WebSocket URL,格式通常为 ws://host:port/mqttwss://host:port/mqtt
  2. 网络环境检查

    • 确认网络环境是否支持 WebSocket 连接
    • 检查防火墙设置,确保 WebSocket 端口已开放
    • 验证 MQTT 服务器是否启用了 WebSocket 支持
  3. TLS 配置(可选)

    • 如果使用安全的 WebSocket 连接(wss),需要配置 TLS 选项
    • 按照 TLS 连接配置步骤设置证书
  4. 测试验证

    • 使用 WebSocket 测试工具验证连接
    • 检查 WebSocket 握手是否成功
    • 验证数据传输是否正常

Q8: 如何调试脚本?

A: 按照以下步骤调试脚本:

  1. 语法验证

    • 在脚本编辑页面点击检查按钮验证脚本语法
    • 检查是否有编译错误或语法错误
  2. 日志调试

    • 启用详细日志,查看脚本执行情况
    • 在脚本中添加日志输出,跟踪执行流程
    • 查看 MQTT 客户端日志,了解数据处理情况
  3. 数据验证

    • 使用简单的测试数据验证脚本输出
    • 检查脚本处理后的数据格式是否正确
    • 验证脚本是否按预期处理边界情况
  4. 服务器验证

    • 检查 MQTT 服务器接收到的数据格式
    • 验证数据是否符合云平台要求
    • 使用 MQTT 客户端工具订阅相关主题,查看发布的数据
  5. 性能调试

    • 测量脚本执行时间,优化性能瓶颈
    • 验证脚本在大数据量下的表现