获取传感器消息通过mqtt通讯传给网页前端
标题虽然这么长,但是做法却十分简单 总共分为两个步骤 第一:获取传感器消息 第二:传给mqtt网络 第三:网页根据mqtt消息采取动作 总结:就是硬件上面操作,网页上实时查看硬件的操作动作 我们先来看第一个:获取传感器消息 首先看一下c#中对于串口通讯的操作(急于实现功能的各位可以跳过直接看下面的源码)
SerialPort类的常用属性
名 称 |
说 明 |
---|---|
BaseStream |
获取 SerialPort 对象的基础 Stream 对象 |
BaudRate |
获取或设置串行波特率 |
BreakState |
获取或设置中断信号状态 |
BytesToRead |
获取发送缓冲区中数据的字节数 |
BytesToWrite |
获取端口的载波检测行的状态 |
CDHolding |
获取“可以发送”行的状态 |
CtsHolding |
获取或设置每个字节的标准数据位长度 |
DiscardNull |
获取或设置一个值,该值指示 Null 字节在端口和接收缓冲区之间传输时是否被忽略 |
DsrHolding |
获取数据设置就绪 (DSR) 信号的状态 |
DtrEnable |
获取或设置一个值,该值在串行通信过程中启用数据终端就绪 (DTR) 信号 |
Encoding |
获取或设置传输前后文本转换的字节编码 |
Handshake |
获取或设置串行端口数据传输的握手协议 |
IsOpen |
获取一个值,该值指示 SerialPort 对象的打开或关闭状态 |
NewLine |
获取或设置用于解释 ReadLine( )和WriteLine( )方法调用结束的值 |
Parity |
获取或设置奇偶校验检查协议 |
ParityReplace |
获取或设置一个字节,该字节在发生奇偶校验错误时替换数据流中的无效字节 |
PortName |
获取或设置通信端口,包括但不限于所有可用的 COM 端口 |
ReadBufferSize |
获取或设置 SerialPort 输入缓冲区的大小 |
ReadTimeout |
获取或设置读取操作未完成时发生超时之前的毫秒数 |
ReceivedBytesThreshold |
获取或设置 DataReceived 事件发生前内部输入缓冲区中的字节数 |
RtsEnable |
获取或设置一个值,该值指示在串行通信中是否启用请求发送 (RTS) 信号 |
StopBits |
获取或设置每个字节的标准停止位数 |
WriteBufferSize |
获取或设置串行端口输出缓冲区的大小 |
WriteTimeout |
获取或设置写入操作未完成时发生超时之前的毫秒数 |
SerialPort类的常用方法
名 称 |
说 明 |
---|---|
Close |
关闭端口连接,将 IsOpen 属性设置为False,并释放内部 Stream 对象 |
Open |
从 SerialPort 输入缓冲区中读取 |
Read |
从 SerialPort 输入缓冲区中读取 |
ReadByte |
从 SerialPort 输入缓冲区中同步读取一个字节 |
ReadChar |
从 SerialPort 输入缓冲区中同步读取一个字符 |
ReadLine |
一直读取到输入缓冲区中的 NewLine 值 |
ReadTo |
一直读取到输入缓冲区中指定 value 的字符串 |
Write |
已重载。将数据写入串行端口输出缓冲区 |
WriteLine |
将指定的字符串和 NewLine 值写入输出缓冲区 |
首先要添加
using System.IO;
using System.IO.Ports;
1...在类的内部定义SerialPort com;
2...打开串口
com = new SerialPort();
com.BaudRate = 115200;
com.PortName = "COM1";
com.DataBits = 8;
com.Open();//打开串口
3...发送数据
Byte[] TxData ={1,2,3,4,5,6,7,8 };
com.Write(TxData, 0, 8);
4...接收数据 见下方源码
using System;
using System.IO.Ports;
using System.Linq;
using System.Management;
using System.Threading;
using System.Windows.Forms;
namespace CefSharp.MinimalExample.WinForms
{
public static class COMCtrl
{
public static string portName = "";
public static int baudRate = 115200;
public static Parity parity = Parity.None;
public static int dataBits = 8;
public static StopBits stopBits = StopBits.One;
public static string[] data;//用于存储6位数据
static SerialPort sp = null;//串口控制
public static string sensorNum = "";//传感器的序号
static CalcOnCrc16 OnCrc16;
public static string audioName;
public static void Init()
{
OnCrc16 = new CalcOnCrc16();
portName = GetPortName();
OpenPort();
}
#region 打开与关闭端口
//获取
static string GetPortName()
{
string i = GetComNum().ToString();
return "COM" + i;
}
//打开端口
public static void OpenPort()
{
sp = new SerialPort(portName, baudRate, parity, dataBits, stopBits);
try
{
sp.Open();
sp.ReadTimeout = 400;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
//关闭端口
public static void ClosePort()
{
try
{
sp.Close();
}
catch (Exception ex)
{
MessageBox.Show("端口关闭失败" + ex.Message);
}
}
#endregion
static string Lock_Str = "Lock";
#region 获取端口号
public static int GetComNum()
{
int comNum = -1;
string[] strArr = GetHarewareInfo(HardwareEnum.Win32_PnPEntity, "Name");
foreach (string s in strArr)
{
if (s.Length >= 23 && s.Contains("CH340"))
{
int start = s.IndexOf("(") + 3;
int end = s.IndexOf(")");
comNum = Convert.ToInt32(s.Substring(start + 1, end - start - 1));
}
}
return comNum;
}
private static string[] GetHarewareInfo(HardwareEnum hardType, string propKey)
{
System.Collections.Generic.List<string> strs = new System.Collections.Generic.List<string>();
try
{
using (ManagementObjectSearcher searcher = new ManagementObjectSearcher("select * from " + hardType))
{
var hardInfos = searcher.Get();
foreach (var hardInfo in hardInfos)
{
if (hardInfo.Properties[propKey].Value != null)
{
String str = hardInfo.Properties[propKey].Value.ToString();
strs.Add(str);
}
}
}
return strs.ToArray();
}
catch
{
return null;
}
finally
{
strs = null;
}
}
public enum HardwareEnum
{
// 硬件
Win32_Processor, // CPU 处理器
Win32_PhysicalMemory, // 物理内存条
Win32_Keyboard, // 键盘
Win32_PointingDevice, // 点输入设备,包括鼠标。
Win32_FloppyDrive, // 软盘驱动器
Win32_DiskDrive, // 硬盘驱动器
Win32_CDROMDrive, // 光盘驱动器
Win32_BaseBoard, // 主板
Win32_BIOS, // BIOS 芯片
Win32_ParallelPort, // 并口
Win32_SerialPort, // 串口
Win32_SerialPortConfiguration, // 串口配置
Win32_SoundDevice, // 多媒体设置,一般指声卡。
Win32_SystemSlot, // 主板插槽 (ISA & PCI & AGP)
Win32_USBController, // USB 控制器
Win32_NetworkAdapter, // 网络适配器
Win32_NetworkAdapterConfiguration, // 网络适配器设置
Win32_Printer, // 打印机
Win32_PrinterConfiguration, // 打印机设置
Win32_PrintJob, // 打印机任务
Win32_TCPIPPrinterPort, // 打印机端口
Win32_POTSModem, // MODEM
Win32_POTSModemToSerialPort, // MODEM 端口
Win32_DesktopMonitor, // 显示器
Win32_DisplayConfiguration, // 显卡
Win32_DisplayControllerConfiguration, // 显卡设置
Win32_VideoController, // 显卡细节。
Win32_VideoSettings, // 显卡支持的显示模式。
// 操作系统
Win32_TimeZone, // 时区
Win32_SystemDriver, // 驱动程序
Win32_DiskPartition, // 磁盘分区
Win32_LogicalDisk, // 逻辑磁盘
Win32_LogicalDiskToPartition, // 逻辑磁盘所在分区及始末位置。
Win32_LogicalMemoryConfiguration, // 逻辑内存配置
Win32_PageFile, // 系统页文件信息
Win32_PageFileSetting, // 页文件设置
Win32_BootConfiguration, // 系统启动配置
Win32_ComputerSystem, // 计算机信息简要
Win32_OperatingSystem, // 操作系统信息
Win32_StartupCommand, // 系统自动启动程序
Win32_Service, // 系统安装的服务
Win32_Group, // 系统管理组
Win32_GroupUser, // 系统组帐号
Win32_UserAccount, // 用户帐号
Win32_Process, // 系统进程
Win32_Thread, // 系统线程
Win32_Share, // 共享
Win32_NetworkClient, // 已安装的网络客户端
Win32_NetworkProtocol, // 已安装的网络协议
Win32_PnPEntity,//all device
}
#endregion
//发送数据
public static void WriteData(byte[] bys)
{
if (sp.IsOpen)
{
sp.Write(bys, 0, bys.Length);
//需要延迟执行接收程序
Thread.Sleep(50);
lock (Lock_Str)
{
DataReceiveFunction();
}
}
}
//获取传感器状态
public static void GetSensorState()
{
//发送获取传感器代码
WriteData(strToToHexByte("01 02 00 00 00 1E F8 02"));
}
//TO => 16进制
public static byte[] strToToHexByte(string hexString)
{
hexString = hexString.Replace(" ", "");
if ((hexString.Length % 2) != 0)
hexString += " ";
byte[] returnBytes = new byte[hexString.Length / 2];
for (int i = 0; i < returnBytes.Length; i++)
returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
return returnBytes;
}
//接收消息
#region constanc
static byte[] MSG;//接收到硬件返回的字符
static byte[] buffer = new byte[1024];//硬件返回数组的缓存空间
static int buffLength = 0;
static string Allbytes = "";
static string CheckCRC = "";
static string oldStr = "00000000000000000000000000000000"; //旧字符
static string newStr= "00000000000000000000000000000000"; //新字符
#endregion
public static void DataReceiveFunction()
{
if (sp != null && sp.IsOpen)
{
try
{
Array.Clear(buffer, 0, buffer.Length);
buffLength = sp.Read(buffer, 0, buffer.Length);
MSG = new byte[buffLength - 2];
Array.Copy(buffer, 0, MSG, 0, buffLength - 2);
//MCU返回的字符串转换为十六进制输出
for (int i = 0; i < buffLength; i++)
{
Allbytes += buffer[i].ToString("X2") + " ";
}
//MessageBox .Show (buffLength + "--------" + Allbytes);
//切割后2位的字符串,用来crc校验
string Checkbytes = "";
for (int i = 0; i < MSG.Length; i++)
{
Checkbytes += MSG[i].ToString("X2") + " ";
}
CheckCRC += buffer[buffLength - 1].ToString("X2");
CheckCRC += buffer[buffLength - 2].ToString("X2");
//BrowserForm.browserForm.RecMqttMsg.Text = CheckCRC ;
//MessageBox .Show("CRC16计算:" + OnCrc16.CRC16(MSG).ToString("X4"));
if (CheckCRC == (OnCrc16.CRC16(MSG).ToString("X4")))
{
CheckCRC = "";
byte[] reverse = new byte[4]; //硬件返回的传感器反序数组
Array.Copy(MSG, 3, reverse, 0, 4);
byte[] forward = new byte[4]; //传感器正向数组
for (int i = 0; i < 4; i++)
{
forward[i] = reverse[reverse.Count() - i - 1];
}
string sensorStr = "";
for (int i = 0; i < 4; i++)
{
sensorStr += Convert.ToString(forward[i], 2).PadLeft(8, '0');//一位16进制的数转换为8个单位
}
newStr = ReverseD(sensorStr);
//字符串有变化开始推送消息
if (newStr.CompareTo(oldStr) == 0)
{
}
else
{
oldStr = newStr;
//int i = oldStr.IndexOf("1");
//if (i != -1)
//{
BrowserForm.browserForm.RecMqttMsg.Text = oldStr;
//发送消息
MqttCtrl.client_sendMsg(oldStr);
//}
}
}
else
{
Console.WriteLine("检测未通过!");
}
Array.Clear(MSG, 0, MSG.Length);
}
catch (Exception ex)
{
Array.Clear(MSG, 0, MSG.Length);
MessageBox.Show(ex.Message);
//如果出错就再调用一次
//DataReceiveFunction();
//MessageBox.Show("串口出错!");
}
}
else
{
MessageBox.Show("串口意外关闭!");
}
}
public static string ReverseD(string text)
{
return new string(text.ToCharArray().Reverse().ToArray());
}
public static void RequestSensor(string Number)
{
try
{
int number = int.Parse(Number);
char state;
state = oldStr[number];
MqttCtrl.client_sendMsg("SZYL:"+Number + "-" + state.ToString());
}
catch (Exception)
{
throw;
}
}
}
}
里面还有一个crc检验
using System;
namespace CefSharp.MinimalExample.WinForms
{
public class CalcOnCrc16
{
public ushort CRC16(byte[] bytes)
{
ushort value;
ushort newLoad = 0xffff, In_value;
int count = 0;
for (int i = 0; i < bytes.Length; i++)
{
value = (ushort)bytes[i];
newLoad = (ushort)(Convert.ToInt32(value) ^ Convert.ToInt32(newLoad));
In_value = 0xA001;
while (count < 8)
{
if (Convert.ToInt32(newLoad) % 2 == 1)//判断最低位是否为1
{
newLoad -= 0x00001;
newLoad = (ushort)(Convert.ToInt32(newLoad) / 2);//右移一位
count++;//计数器加一
newLoad = (ushort)(Convert.ToInt32(newLoad) ^ Convert.ToInt32(In_value));//异或操作
}
else
{
newLoad = (ushort)(Convert.ToInt32(newLoad) / 2);//右移一位
count++;//计数器加一
}
}
count = 0;
}
return newLoad;
}
}
}
PS:这个单片机是我请求一次,它才发回消息,不是主动的发,所以我的程序里面还有计时器循环请求状态. 下面就是发送到mqtt消息平台,首先接收
教程是这里的,如果看不懂直接看我源码 https://help.aliyun.com/document_detail/59721.html?spm=a2c4g.11186623.6.590.666432b1pvEQrL
using System;
using System.Security.Cryptography;
using System.Text;
using System.Windows.Forms;
using uPLibrary.Networking.M2Mqtt;
using uPLibrary.Networking.M2Mqtt.Messages;
namespace CefSharp.MinimalExample.WinForms
{
public class MqttCtrl
{
// //实例 ID,购买后从控制台获取
//static String instanceId = " ";
// //此处填写购买得到的 MQTT 接入点域名
// static String brokerUrl = " ";
// //此处填写阿里云帐号 AccessKey
// static String accessKey = " ";
// //此处填写阿里云帐号 SecretKey
// static String secretKey = "";
// //此处填写在 MQ 控制台创建的 Topic,作为 MQTT 的一级 Topic
// static String parentTopic = " ";
// //此处填写客户端 ClientId,需要保证全局唯一,其中前缀部分即 GroupId 需要先在 MQ 控制台创建
// static String clientId = " " + DateTime.Now.Ticks.ToString();
// static MqttClient client = new MqttClient(brokerUrl);
//实例 ID,购买后从控制台获取
static String instanceId = " ";
//此处填写购买得到的 MQTT 接入点域名
static String brokerUrl = " ";
//此处填写阿里云帐号 AccessKey
static String accessKey = " ";
//此处填写阿里云帐号 SecretKey
static String secretKey = "";
//此处填写在 MQ 控制台创建的 Topic,作为 MQTT 的一级 Topic
static String parentTopic = "SJJK";
//此处填写客户端 ClientId,需要保证全局唯一,其中前缀部分即 GroupId 需要先在 MQ 控制台创建
static String clientId = " " + DateTime.Now.Ticks.ToString();
static MqttClient client = new MqttClient(brokerUrl);
public static void Init()
{
client.MqttMsgPublishReceived += client_recvMsg;
client.MqttMsgPublished += client_publishSuccess;
client.ConnectionClosed += client_connectLose;
//username和 Password 签名模式下的设置方法,参考文档 https://help.aliyun.com/document_detail/48271.html?spm=a2c4g.11186623.6.553.217831c3BSFry7
String userName = "Signature|" + accessKey + "|" + instanceId;
String passWord = HMACSHA1(secretKey, clientId);
client.Connect(clientId, userName, passWord, true, 60);
//订阅 Topic,支持多个 Topic,以及多级 Topic
//string[] subTopicArray = { parentTopic + "/SamJan", parentTopic + "/subDemo2/level3" };
string[] subTopicArray = { parentTopic + "/SamJan", parentTopic + "/SensorState" };
//string[] subTopicArray = { parentTopic + "/SensorState" };
byte[] qosLevels = { MqttMsgBase.QOS_LEVEL_AT_MOST_ONCE, MqttMsgBase.QOS_LEVEL_AT_MOST_ONCE };
//订阅
client.Subscribe(subTopicArray, qosLevels);
//client.Publish(parentTopic + "/SamJan", Encoding.UTF8.GetBytes("hello mqtt,尚哲智能"), MqttMsgBase.QOS_LEVEL_AT_LEAST_ONCE, false);
//发送 P2P 消息,二级 topic 必须是 p2p,三级 topic 是接收客户端的 clientId
//client.Publish(parentTopic + "/p2p/" + clientId, Encoding.UTF8.GetBytes("(P2P) hello mqtt"), MqttMsgBase.QOS_LEVEL_AT_LEAST_ONCE, false);
//System.Threading.Thread.Sleep(10000);
//client.Disconnect();
}
//
public static void client_sendMsg(string msg)
{
client.Publish(parentTopic + "/SamJan", Encoding.UTF8.GetBytes(msg), MqttMsgBase.QOS_LEVEL_AT_LEAST_ONCE, false);
}
static void client_sendMsgByP2P(string msg)
{
client.Publish(parentTopic + "/p2p/" + clientId, Encoding.UTF8.GetBytes(msg), MqttMsgBase.QOS_LEVEL_AT_LEAST_ONCE, false);
}
static void client_disConnect()
{
client.Disconnect();
}
static void client_recvMsg(object sender, MqttMsgPublishEventArgs e)
{
// access data bytes throug e.Message
//MessageBox.Show("Recv Msg : Topic is " + e.Topic + " ,Body is " + Encoding.UTF8.GetString(e.Message));
if (e.Topic == "SJJK/SensorState")
{
COMCtrl.RequestSensor(Encoding.UTF8.GetString(e.Message));
}
}
static void client_publishSuccess(object sender, MqttMsgPublishedEventArgs e)
{
// access data bytes throug e.Message
Console.WriteLine("Publish Msg Success");
}
static void client_connectLose(object sender, EventArgs e)
{
// access data bytes throug e.Message
Console.WriteLine("Connect Lost,Try Reconnect");
Init();
}
public static string HMACSHA1(string key, string dataToSign)
{
Byte[] secretBytes = UTF8Encoding.UTF8.GetBytes(key);
HMACSHA1 hmac = new HMACSHA1(secretBytes);
Byte[] dataBytes = UTF8Encoding.UTF8.GetBytes(dataToSign);
Byte[] calcHash = hmac.ComputeHash(dataBytes);
String calcHashString = Convert.ToBase64String(calcHash);
return calcHashString;
}
}
}
官方Demo: https://code.aliyun.com/aliware_mqtt/mqtt-demo/tree/master?spm=a2c4g.11186623.2.38.4181775ewvOQVo
与前端妹子沟通好,你们就可以愉快的吵架了.
- 点赞
- 收藏
- 关注作者
评论(0)