阿里云上通过MQTT协议,实现多设备的相互数据的稳定动态传输和使用(本地设备均采用c#窗体代码)第二篇-----本地设备开发

窗体界面的建立

  首先,我们需要在VS上进行窗体的建立,对两个设备进行窗体的建立。点击左侧的工具箱,找到textBox,label还有button,将他们放置在窗体上。然后修改右下角的Text以及字体的大小和字种(不改其实也没问题),两个程序,一个作为接收端,一个作为发出端,博主做的比较简陋,如下图所示:
在这里插入图片描述
在这里插入图片描述
  然后我们现在需要敲写一些代码上去,进行设备的激活和测试。在激活之前,我们还需要先写一个 IoT平台接入password签名的算法文件,关于签名规则以及想学敲写签名的,可以自行前往 https://www.yuque.com/cloud-dev/iot-tech/mebm5g 进行了解学习,本文篇幅有限,就不在这里过多赘述,直接展示适合阿里云物联网平台的代码了:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
namespace iotxsdkmqttnet {
    public class IotSignUtils {
        public static string sign(Dictionary<string, string> param, 
                            string deviceSecret, string signMethod) {
            string[] sortedKey = param.Keys.ToArray();
            Array.Sort(sortedKey);

            StringBuilder builder = new StringBuilder();
            foreach(var i in sortedKey){
                builder.Append(i).Append(param[i]);
            }

            byte[] key = Encoding.UTF8.GetBytes(deviceSecret);
            byte[] signContent = Encoding.UTF8.GetBytes(builder.ToString());
            //这里根据signMethod对代码进行了一些动态调整,于是写了一个HMACMD5
            var hmac = new HMACMD5(key);
            byte[] hashBytes = hmac.ComputeHash(signContent);

            StringBuilder signBuilder = new StringBuilder();
            foreach (byte b in hashBytes)
                signBuilder.AppendFormat("{0:x2}", b);

            return signBuilder.ToString();
        }
    }
}

  这里我展示的代码是我当时还未放入C#窗体前,在外部项目中单独尝试的,所以没有窗体中的那些类,但是我们在最后的成品程序中,是需要将这段作为一个类放入到C#窗体程序中去的。由于VS中的C#窗体应用里要求public partial class Form1 : Form需要作为本地程序namespace里的第一个类,所以在拷贝代码的时候还请注意不要把代码放到public partial class Form1 : Form的前面。

  然后我们需要再写一个设备的激活程序,代码如下,其中有一部分需要自己更改,我已经加了注释上去。

using System;
using System.Net;
using System.Collections.Generic;
using uPLibrary.Networking.M2Mqtt;//如果这里显示错误的话,请检查一下MQTT库是否已经安装好
using uPLibrary.Networking.M2Mqtt.Messages;//如果这里显示错误的话,请检查一下MQTT库是否已经安装好
using System.Text;
using System.Linq;

namespace iotMqttDemo {
    class MainClass {
        static string ProductKey = "";//这里输入你的产品的Productkey
        static string DeviceName = "";//这里输入你的设备的DeviceName
        static string DeviceSecret = "";//这里输入你的设备的DeviceSecret
        static string RegionId = "cn-shanghai";//这里是根据你的ReginId填写的,可以根据自己的进行修改

        static string PubTopic = "/" + ProductKey + "/" + DeviceName + "/update";//发布端的topic
        static string SubTopic = "/" + ProductKey + "/" + DeviceName + "/get";//订阅端的topic

        public static void Main(string[] args)
        {
            IPHostEntry host = Dns.GetHostEntry(Dns.GetHostName());//建立一个IPHostEntry host
            string clientId = host.AddressList.FirstOrDefault(//设置clientID
                ip => ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork).ToString();
            string t = Convert.ToString(DateTimeOffset.Now.ToUnixTimeMilliseconds());
            string signmethod = "hmacmd5";//采用hmacmd5

            Dictionary<string, string> dict = new Dictionary<string, string>();
            dict.Add("productKey", ProductKey);
            dict.Add("deviceName", DeviceName);
            dict.Add("clientId", clientId);
            dict.Add("timestamp", t);

            string mqttUserName = DeviceName + "&" + ProductKey;
            string mqttPassword = IotSignUtils.sign(dict, DeviceSecret, signmethod);
            string mqttClientId = clientId + "|securemode=3,signmethod="+signmethod+",timestamp=" + t + "|";
            
            string targetServer = ProductKey + ".iot-as-mqtt." + RegionId + ".aliyuncs.com";
            
            ConnectMqtt(targetServer, mqttClientId, mqttUserName, mqttPassword);//连接
        }

        static void ConnectMqtt(string targetServer, string mqttClientId, string mqttUserName, string mqttPassword){
            MqttClient client = new MqttClient(targetServer);
            client.ProtocolVersion = MqttProtocolVersion.Version_3_1_1;

            client.Connect(mqttClientId, mqttUserName, mqttPassword, false, 60);
            client.MqttMsgPublishReceived += Client_MqttMsgPublishReceived;//注册事件

            //发布消息
            String content = "1";//发送个数字1给阿里云,可以在日志记录里的上行数据中查看到这个1
            var id = client.Publish(PubTopic, Encoding.ASCII.GetBytes(content));
            //他函数的返回值为无符号的16位整数
            
            //订阅消息
            client.Subscribe(new string[] { SubTopic }, new byte[] { 0 });
            //这里的0的意思是采用Qos三种方法:0,1,2中的0号方法,也就是只运行一次的意思
        }

        static void Client_MqttMsgPublishReceived(object sender, MqttMsgPublishEventArgs e)
        {
            //对获得的message的处理
            string topic = e.Topic;
            string message = Encoding.ASCII.GetString(e.Message);
        }

    }
}

  需要注意的是这里也只是一个算法,而不是一个完整的程序,单独运行这段代码会出现错误,我们要做的是把之前的代码合并并且结合到C#的窗体应用里面去。两个程序的头文件中有相同的地方,合并的时候记得删除这一部分,或者直接使用我下面的实例代码中的头文件,在C#窗体应用中的框架如下:

using System;
using System.Net;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using uPLibrary.Networking.M2Mqtt;
using uPLibrary.Networking.M2Mqtt.Messages;
using System.Windows.Forms;
using System.Security.Cryptography;

namespace jieshou
{
public partial class Form1 : Form
    {
    ......
    }
public class IotSignUtils//IoT平台接入password签名算法
    {
    ......
    }
}

  在public class IotSignUtils中就只需要把之前的那段代码复制进来就行了,而对于设备端的具体操作,我们还需要对应C#的环境进行一定的加工和修改,不能直接复制进来使用。我这里的设备上线的时机是当我们在textBox输入完我们的值以后点击发送信息的时候,所以我们原先代码中的MainClass中的 public static void Main(string[] args) 里面的内容我们需要放在 private void button1_Click(object sender, EventArgs e) 这个事件中:

 private void button1_Click(object sender, EventArgs e)
        {
            label1.Text = "数据已经上传!";
            //开始连接阿里云
            IPHostEntry host = Dns.GetHostEntry(Dns.GetHostName());
            string clientId = host.AddressList.FirstOrDefault(
                ip => ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork).ToString();
            string t = Convert.ToString(DateTimeOffset.Now.ToUnixTimeMilliseconds());
            string signmethod = "hmacmd5";
            Dictionary<string, string> dict = new Dictionary<string, string>();
            dict.Add("productKey", ProductKey);
            dict.Add("deviceName", DeviceName);
            dict.Add("clientId", clientId);
            dict.Add("timestamp", t);
            string mqttUserName = DeviceName + "&" + ProductKey;
            string mqttPassword = IotSignUtils.sign(dict, DeviceSecret, signmethod);
            string mqttClientId = clientId + "|securemode=3,signmethod=" + signmethod + ",timestamp=" + t + "|";
            string targetServer = ProductKey + ".iot-as-mqtt." + RegionId + ".aliyuncs.com";
            ConnectMqtt(targetServer, mqttClientId, mqttUserName, mqttPassword);
        }

  然后 MainClass 与 public static void Main(string[] args) 之间的静态变量我们需要放在 public partial class Form1 : Form 与 public Form1() 之间,并且这里一定要特别注意的是,这里有一个与上面的不同的地方:因为我们等会需要和阿里云进行数据的交流,所以这里的Topic一定要修改,在 static string PubTopic 和 static string SubTopic 这两行中的 DeviceName 的后面一定要加上 /user ,不然等会就会出现9236错误,也就是权限的错误。 事例如下:

namespace jieshou
{
    public partial class Form1 : Form
    {
        //阿里云的数据
        static string ProductKey = "";//输入自己的ProductKey
        static string DeviceName = "";//输入自己的DeviceName
        static string DeviceSecret = "";//输入自己的DeviceSecret
        static string RegionId = "cn-shanghai";
        static string PubTopic = "/" + ProductKey + "/" + DeviceName + "/user/update";
        static string SubTopic = "/" + ProductKey + "/" + DeviceName + "/user/get";

        public Form1()
        {
        ......
        }
        ......
}

  但是光修改这么多还是远远不够的,因为就目前来说,我们还没有做将数据显示到C#窗体上的代码的修改,要想实现C#窗体显示的话,我们还需要修改 static void ConnectMqtt 函数以及 static void Client_MqttMsgPublishReceived 函数。

  我们先修改ConnectMqtt 函数:(函数类型改为 public void)

public void ConnectMqtt(string targetServer, string mqttClientId, string mqttUserName, string mqttPassword)
        {
            MqttClient client = new MqttClient(targetServer);
            client.ProtocolVersion = MqttProtocolVersion.Version_3_1_1;

            client.Connect(mqttClientId, mqttUserName, mqttPassword, false, 60);
            client.MqttMsgPublishReceived += Client_MqttMsgPublishReceived;
            
            //订阅消息
            client.Subscribe(new string[] { SubTopic }, new byte[] { 0 });
            
            //发布消息,发布的消息为我们在textBox1上的Text
            String content = textBox1.Text;
            //他上传的数据需要时byte[],所以我们先需要将string类转换成byte[]
            byte[] by1 = System.Text.Encoding.ASCII.GetBytes(content);
            var id = client.Publish(PubTopic, by1);
        }

  然后我们再修改Client_MqttMsgPublishReceived 函数:(函数类型改为 public void)

public void Client_MqttMsgPublishReceived(object sender, MqttMsgPublishEventArgs e)
        {
            //对获得的message的处理
            string topic = e.Topic;
            string message = Encoding.ASCII.GetString(e.Message);//从被订阅端获取消息
            int length = message.Length;//我们先得到这条message的长度,
            //因为是string所以调用他的length函数就可以了
            label3.Text = message.Substring(0,length);//label3原先是null,
            //后来就会变成message的内容,从头开始读,长度就是length
        }

  有的人可能会在label3.Text这里会报错,原因是在于初始化的问题,需要在 public Form1() 中添加一行代码,加入后错误就解决了:

public Form1()
        {
            InitializeComponent();
            System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;
            //加入这行代码
        }

  做到这一步的时候,我们在设备上的开发就已经完成了,现在我们可以运行一下这个代码,然后在textBox上输入数字以后点击button1,然后就开始传输数据了:

程序运行前:设备处于离线状态
在这里插入图片描述
程序运行后:设备处于在线状态在这里插入图片描述
数据的日志服务为:
在这里插入图片描述
由本地设备上传给阿里云的数据存放在上行消息分析中:
在这里插入图片描述
  但是我们会发现,下行消息分析里我们并没有数据,这是为什么呢?原因其实很简单,因为我们目前在云上的开发只是创建了产品和设备而已,数据的传递我们目前还没有在云上进行操作,所以目前下行数据分析是没有办法显示的,我们还需要在云上进行更深一步的开发。如何在云上进行二次开发将会在第三章中介绍。
  本章到此就结束了,谢谢大家。

  • 3
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值