C# 是一种现代通用的、面向对象的编程语言,由微软在 .NET 框架中开发并推出。它结合了 C++ 的强大功能和 Java 的易用性,使得开发者能够构建各种类型的应用程序,包括 Windows 客户端应用、Web 应用、数据库应用、移动应用和游戏等。
腾讯云物联网开发平台支持使用 C# 接入。本文介绍如何在 C# 项目中,使用 MQTTnet Client 库,实现与腾讯云物联网开发平台的连接、topic 订阅、上下行消息交互等功能。
说明:
1. 本示例基于 donet 6.0。
2. 第三方类库使用版本如下:
MQTTnet:v3.0.11
MQTTnet.Extensions.ManagedClient:v3.0.11
Newtonsoft.Json:v12.0.3
NLog:v5.2.3
操作场景
一款智能灯接入到物联网开发平台,通过物联网开发平台可以远程控制灯的亮度、颜色、开关,并实时获取智能灯上报到开发平台的数据。
准备工作
1. 申请 腾讯云物联网开发平台 服务。
2. 一台 Windows 电脑并且安装了 VS2017 及以上版本。
操作步骤
创建项目
1. 登录 物联网开发平台控制台,选择平台默认开通的公共实例或用户购买的企业实例。
2. 单击实例后,默认进入项目列表页面,单击新建项目。
项目名称:必填,输入“智能灯演示”或其他名称。
项目描述:按照实际需求填写项目描述。
3. 项目基本信息填写完成后,单击保存,即可完成新建项目。
4. 项目新建成功后,即可新建产品。
新建产品
1. 单击项目名称,进入产品列表页面,单击新建产品。
2. 在新建产品页面,填写产品基本信息。
产品名称:必填,输入“智能灯”或其他产品名称。
产品品类:选择标准品类 “智能生活” > “电工照明” > “灯”。
设备类型:选择“设备”。
认证方式:选择“密钥认证”。
通信方式:按需选择。
其他都为默认选项。
3. 产品信息填写完成后,单击保存,即可完成新建产品。
4. 产品新建成功后,您可在产品列表页查看到“智能灯”。
定义产品物模型
选择“灯”类型后,系统会自动生成标准功能。
创建设备
在设备调试页面中,单击新建设备,设备名为 dev001。
C# MQTT 客户端使用
通过以上步骤,您已经成功拿到腾讯云物联网开发平台的设备三元组信息,接下来可以根据这个示例来使用 C# 接入。
输入三元组信息
单击创建的设备名称,获取设备三元组信息。
// 云端生成的三元组信息static string PRODUCT_ID = "YOUR_PRODUCT_ID"; // 产品idstatic string DEVICE_NAME = "YOUR_DEVICE_NAME"; // 设备名称static string DEVICE_SECRET = "IOT_PSK"; // 设备密钥
生成 MQTT client 连接参数
通过刚才填入的三元组信息,生成 MQTT 的
clientId
、userName
、password
。// 生成MQTT连接参数byte[] decodeBytes = Convert.FromBase64String(DEVICE_SECRET);string clientId = PRODUCT_ID + DEVICE_NAME;string usrNmae = clientId + ";21010406;" + GetNextConnId() +";"+ 0x7fffffff.ToString();string password = ComputeHmacSha1(usrNmae, decodeBytes) + ";hmacsha1";
创建 MQTT client 并连接云平台
IManagedMqttClient mqttClient = new MqttFactory().CreateManagedMqttClient();var mqttOptions = new ManagedMqttClientOptionsBuilder().WithAutoReconnectDelay(TimeSpan.FromSeconds(10)).WithClientOptions(new MqttClientOptionsBuilder().WithClientId(clientId).WithCredentials(usrNmae, password).WithTcpServer(url, 1883) // 非tls模式.WithCleanSession().Build()).Build();
如果使用 TLS 加密接入,则按照如下方式配置:
IManagedMqttClient mqttClient = new MqttFactory().CreateManagedMqttClient();var mqttOptions = new ManagedMqttClientOptionsBuilder().WithAutoReconnectDelay(TimeSpan.FromSeconds(10)).WithClientOptions(new MqttClientOptionsBuilder().WithClientId(clientId).WithCredentials(usrNmae, password).WithTcpServer(url, 8883) // tls 接入.WithTls(new MqttClientOptionsBuilderTlsParameters {UseTls = true,IgnoreCertificateChainErrors = true,IgnoreCertificateRevocationErrors = true,AllowUntrustedCertificates = true,}).WithCleanSession().Build()).Build();
监听 MQTT 连接或断连或接收事件
// 监听连接事件mqttClient.UseConnectedHandler(e =>{log.Info("mqtt connect success with " + deviceId);return Task.CompletedTask;});// 监听断开事件mqttClient.UseDisconnectedHandler(e =>{log.Error("mqtt disconnect with " + deviceId);return Task.CompletedTask;});// 监听收到的消息mqttClient.UseApplicationMessageReceivedHandler(e =>{// 处理物模型数据string topic = e.ApplicationMessage.Topic;string payload = Encoding.UTF8.GetString(e.ApplicationMessage.Payload);log.Debug($"down message topic: {topic} paylaod : {payload}");if (topic.Contains("/property/")){// 属性处理}else if (topic.Contains("/event/")){// 事件处理}else if (topic.Contains("/action/")){// 行为处理}return Task.CompletedTask;});
连接云平台
// 连接到平台await mqttClient.StartAsync(mqttOptions);
订阅物模型 topic
// 订阅物模型topicvar topicFilters = new[]{new MqttTopicFilterBuilder().WithTopic("$thing/down/property/"+deviceId).Build(),new MqttTopicFilterBuilder().WithTopic("$thing/down/event/"+deviceId).Build(),new MqttTopicFilterBuilder().WithTopic("$thing/down/action/"+deviceId).Build()};await mqttClient.SubscribeAsync(topicFilters);
上报亮度示例
int brightness = 25;var payload_json = new JObject{["method"] = "report",["clientToken"] = DateTimeOffset.Now.ToUnixTimeSeconds().ToString(),["params"] = new JObject{["brightness"] = brightness}};string payload = JsonConvert.SerializeObject(payload_json).ToString();var message = new MqttApplicationMessageBuilder().WithTopic("$thing/up/property/" + deviceId).WithPayload(payload).WithQualityOfServiceLevel(0).WithRetainFlag(false).Build();await mqttClient.PublishAsync(message);
完整的示例代码如下:
using System;using System.Collections.Generic;using System.Text;using System.Security.Cryptography;using NLog;using MQTTnet;using MQTTnet.Client.Options;using MQTTnet.Extensions.ManagedClient;using Newtonsoft.Json;using Newtonsoft.Json.Linq;namespace IoT.Explorer.Test{class DatatemplateTest{private static Logger log = LogManager.GetCurrentClassLogger();// 云端生成的三元组信息static string PRODUCT_ID = "F2F43QKKA4";static string DEVICE_NAME = "5629fbfa12f4";static string DEVICE_SECRET = "a91V4htL41oILv80lgCeLA==";public static string GetNextConnId(){char[] connId = new char[6];Random random = new Random();for (int i = 0; i < 6 - 1; i++){int flag = random.Next(3);switch (flag){case 0:connId[i] = (char)(random.Next(26) + 'a');break;case 1:connId[i] = (char)(random.Next(26) + 'A');break;case 2:connId[i] = (char)(random.Next(10) + '0');break;}}connId[6 - 1] = '\\0';return new string(connId);}public static string ComputeHmacSha1(string inputString, byte[] keyBytes){byte[] inputBytes = Encoding.UTF8.GetBytes(inputString);using (HMACSHA1 hmac = new HMACSHA1(keyBytes)){byte[] hashBytes = hmac.ComputeHash(inputBytes);string hashString = BitConverter.ToString(hashBytes).Replace("-", "").ToLower();return hashString;}}static async Task Main(string[] args){// 生成MQTT连接参数byte[] decodeBytes = Convert.FromBase64String(DEVICE_SECRET);string clientId = PRODUCT_ID + DEVICE_NAME;string usrNmae = clientId + ";21010406;" + GetNextConnId() +";"+ 0x7fffffff.ToString();string password = ComputeHmacSha1(usrNmae, decodeBytes) + ";hmacsha1";string url = PRODUCT_ID + ".iotcloud.tencentdevices.com";string deviceId = PRODUCT_ID + "/" + DEVICE_NAME;try{IManagedMqttClient mqttClient = new MqttFactory().CreateManagedMqttClient();var mqttOptions = new ManagedMqttClientOptionsBuilder().WithAutoReconnectDelay(TimeSpan.FromSeconds(10)).WithClientOptions(new MqttClientOptionsBuilder().WithClientId(clientId).WithCredentials(usrNmae, password).WithTcpServer(url, 8883).WithTls(new MqttClientOptionsBuilderTlsParameters {UseTls = true,IgnoreCertificateChainErrors = true,IgnoreCertificateRevocationErrors = true,AllowUntrustedCertificates = true,}).WithCleanSession().Build()).Build();// 监听连接事件mqttClient.UseConnectedHandler(e =>{log.Info("mqtt connect success with " + deviceId);return Task.CompletedTask;});// 监听断开事件mqttClient.UseDisconnectedHandler(e =>{log.Error("mqtt disconnect with " + deviceId);return Task.CompletedTask;});// 监听收到的消息mqttClient.UseApplicationMessageReceivedHandler(e =>{// 处理物模型数据string topic = e.ApplicationMessage.Topic;string payload = Encoding.UTF8.GetString(e.ApplicationMessage.Payload);log.Debug($"down message topic: {topic} paylaod : {payload}");if (topic.Contains("/property/")){// 属性处理}else if (topic.Contains("/event/")){// 事件处理}else if (topic.Contains("/action/")){// 行为处理}return Task.CompletedTask;});// 连接到平台await mqttClient.StartAsync(mqttOptions);Thread.Sleep(2000);// 订阅物模型topicvar topicFilters = new[]{new MqttTopicFilterBuilder().WithTopic("$thing/down/property/"+deviceId).Build(),new MqttTopicFilterBuilder().WithTopic("$thing/down/event/"+deviceId).Build(),new MqttTopicFilterBuilder().WithTopic("$thing/down/action/"+deviceId).Build()};await mqttClient.SubscribeAsync(topicFilters);int brightness = 0;while (true) {// 周期上报亮度var payload_json = new JObject{["method"] = "report",["clientToken"] = DateTimeOffset.Now.ToUnixTimeSeconds().ToString(),["params"] = new JObject{["brightness"] = brightness}};string payload = JsonConvert.SerializeObject(payload_json).ToString();var message = new MqttApplicationMessageBuilder().WithTopic("$thing/up/property/" + deviceId).WithPayload(payload).WithQualityOfServiceLevel(0).WithRetainFlag(false).Build();await mqttClient.PublishAsync(message);log.Debug("publish message :" + payload);brightness++;if (!mqttClient.IsConnected){break;}Thread.Sleep(10000);}// disconnectawait mqttClient.StopAsync();}catch (Exception ex){var name = ex.GetType().FullName;log.Error("异常:"+ex.Message);}}}}
运行日志如下:
2023-08-09 12:04:20.0860 INFO IoT.Explorer.Test.DatatemplateTest - mqtt connect success with F2F43QKKA4/5629fbfa12f42023-08-09 12:04:21.7918 DEBUG IoT.Explorer.Test.DatatemplateTest - publish message :{"method":"report","clientToken":"1691553861","params":{"brightness":0}}2023-08-09 12:04:21.8791 DEBUG IoT.Explorer.Test.DatatemplateTest - down message topic: $thing/down/property/F2F43QKKA4/5629fbfa12f4 paylaod : {"method":"report_reply","clientToken":"1691553861","code":0,"status":"success"}2023-08-09 12:04:25.6359 DEBUG IoT.Explorer.Test.DatatemplateTest - down message topic: $thing/down/property/F2F43QKKA4/5629fbfa12f4 paylaod : {"method":"control","clientToken":"v2149648760ozOCb::af400362-c384-40dd-b39c-94d82950e1ad","params":{"power_switch":1}}2023-08-09 12:04:29.4171 DEBUG IoT.Explorer.Test.DatatemplateTest - down message topic: $thing/down/property/F2F43QKKA4/5629fbfa12f4 paylaod : {"method":"control","clientToken":"v2146761678bxCmt::295125a1-6b64-4cba-b2ca-036bbef43390","params":{"power_switch":0}}2023-08-09 12:04:31.7989 DEBUG IoT.Explorer.Test.DatatemplateTest - publish message :{"method":"report","clientToken":"1691553871","params":{"brightness":1}}2023-08-09 12:04:31.8919 DEBUG IoT.Explorer.Test.DatatemplateTest - down message topic: $thing/down/property/F2F43QKKA4/5629fbfa12f4 paylaod : {"method":"report_reply","clientToken":"1691553871","code":0,"status":"success"}