using BPA.Message.IOT;
using BPA.Helper;
using BPASmartClient.IoT;
using BPASmartClient.IoT.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using uPLibrary.Networking.M2Mqtt;
using uPLibrary.Networking.M2Mqtt.Messages;
namespace BPASmartDatavDeviceClient.IoT
{
///
/// DataV客户端
///
public class DataVReport
{
#region 外部调用
///
/// 初始化IOT连接
///
public bool Initialize(string url, string _clientId, string _deviceId, ref string message)
{
if (string.IsNullOrEmpty(url)) return false;
deviceId = _deviceId;
if (!CreateLinks(url, _clientId, out deviceTable, _deviceId))
{
message += $"客户端{_clientId}设备{_deviceId}阿里云上没有该设备。";
return false;
}
IOT_Subscribe(BroadcastTopic);//订阅广播主题
IOT_Subscribe(FileUpLoadReplyTopic);
IOT_Subscribe(FileUpLoadSendReplyTopic);
IOT_Subscribe(CancelFileUpLoadSendTopic);
if (!DatavDeviceClient.IsConnected) message += $"客户端:【{_clientId}】,设备名称{deviceTable.devicename}阿里云连接失败.不能上报业务信息";
return DatavDeviceClient.IsConnected;
}
///
/// 初始化IOT连接
///
public bool InitializeNo(string _productkey, string _devicename, string _devicesecret, ref string message)
{
try
{
if (deviceTable == null) deviceTable = new DeviceTable();
deviceTable.devicename = _devicename;
SetValue(_productkey, _devicename, _devicesecret);
IPHostEntry host = Dns.GetHostEntry(Dns.GetHostName());
string _clientIp = host.AddressList.FirstOrDefault(
ip => ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork).ToString();
string t = Convert.ToString(DateTimeOffset.Now.ToUnixTimeMilliseconds());
string signmethod = "hmacmd5";
Dictionary dict = new Dictionary();
dict.Add("productKey", ProductKey);
dict.Add("deviceName", DeviceName);
dict.Add("clientId", _clientIp);
dict.Add("timestamp", t);
mqttUserName = DeviceName + "&" + ProductKey;
mqttPassword = IotSignUtils.sign(dict, DeviceSecret, signmethod);
mqttClientId = _clientIp + "|securemode=3,signmethod=" + signmethod + ",timestamp=" + t + "|";
targetServer = ProductKey + ".iot-as-mqtt." + RegionId + ".aliyuncs.com";
ConnectMqtt(targetServer, mqttClientId, mqttUserName, mqttPassword);
}
catch (Exception ex)
{
message += $"阿里云{_devicename}连接失败,{ex.Message}";
return false;
}
IOT_Subscribe(BroadcastTopic);//订阅广播主题
IOT_Subscribe(FileUpLoadReplyTopic);
IOT_Subscribe(FileUpLoadSendReplyTopic);
IOT_Subscribe(CancelFileUpLoadSendTopic);
if (!DatavDeviceClient.IsConnected) message += $"客户端:【】,设备名称{deviceTable.devicename}阿里云连接失败.不能上报业务信息";
return DatavDeviceClient.IsConnected;
}
///
/// 获取连接状态
///
public bool GetIsConnected()
{
try
{
if (DatavDeviceClient == null || !DatavDeviceClient.IsConnected)
return false;
else return true;
}
catch (Exception ex)
{
return false;
throw;
}
}
///
/// 断开连接
///
public void Disconnect()
{
if (DatavDeviceClient != null)
{
DatavDeviceClient.Disconnect();
}
}
///
/// 发布消息
///
///
///
public void IOT_Publish(string topic, string message)
{
var id = DatavDeviceClient.Publish(topic, Encoding.UTF8.GetBytes(message));
}
public void IOT_Publish(string topic, byte[] message)
{
var id = DatavDeviceClient.Publish(topic, message);
}
///
/// 订阅主题
///
///
public void IOT_Subscribe(string topic)
{
if (SubTopicList.Contains(topic))
{
SubTopicList.Add(topic);
}
DatavDeviceClient.Subscribe(new string[] { topic }, new byte[] { 0 });
}
public void Chkin_Up()
{
OSS_Helper ss = new OSS_Helper();
string objectName = "Project/aa.bak";
string downloadFilename = @"\\aa.bak";
//记录进度的文件路径
string checkpointDir = @"D:\checkin\";
//ss.Multipar_tUp(objectName, downloadFilename);
ss.chkin_Up(objectName, downloadFilename, checkpointDir);
}
#endregion
#region 私有函数
///
/// 设置变量
///
///
///
///
///
private void SetValue(string _ProductKey, string _DeviceName, string _DeviceSecret, string _RegionId = "cn-shanghai")
{
ProductKey = _ProductKey;
DeviceName = _DeviceName;
DeviceSecret = _DeviceSecret;
RegionId = _RegionId;
PubTopic = "/sys/" + ProductKey + "/" + DeviceName + "/thing/event/property/post";
SubTopic = "/sys/" + ProductKey + "/" + DeviceName + "/thing/event/property/set";
UserPubTopic = "/" + ProductKey + "/" + DeviceName + "/user/update";
UserSubTopic = "/" + ProductKey + "/" + DeviceName + "/user/get";
BroadcastTopic = "/broadcast/" + ProductKey + "/" + DeviceName + "_SetDevice";
AlarmSubTopic = "/" + ProductKey + "/" + DeviceName + "/user/AlarmMessage";
LogsSubTopic = "/" + ProductKey + "/" + DeviceName + "/user/ExceptionLogs";
HeartbeatSubTopic = "/" + ProductKey + "/" + DeviceName + "/user/HeartbeatAndState";
TargetStatusSubTopic = "/" + ProductKey + "/" + DeviceName + "/user/TargetStatus";
ScreenShowPubTopic = "/" + ProductKey + "/" + DeviceName + "/user/ScreenShow";
FileUpLoadTopic = $"/sys/{ProductKey}/{DeviceName}/thing/file/upload/mqtt/init";
FileUpLoadReplyTopic = $"/sys/{ProductKey}/{DeviceName}/thing/file/upload/mqtt/init_reply";
FileUpLoadSendTopic = $"/sys/{ProductKey}/{DeviceName}/thing/file/upload/mqtt/send";
FileUpLoadSendReplyTopic = $"/sys/{ProductKey}/{DeviceName}/thing/file/upload/mqtt/send_reply";
CancelFileUpLoadSendTopic = $"/sys/{ProductKey}/{DeviceName}/thing/file/upload/mqtt/cancel";
CancelFileUpLoadSendReplyTopic = $"/sys/{ProductKey}/{DeviceName}/thing/file/upload/mqtt/cancel_reply";
}
///
/// 创建连接
///
private bool CreateLinks(string url, string clientId, out DeviceTable device, string deviceId = "")
{
try
{
string json = string.Empty;
if (string.IsNullOrEmpty(deviceId))
//json = APIHelper.GetInstance.GetRequest($"{url}/api/Device/Query?clientId={clientId}", 1000);
json = APIHelper.GetInstance.GetRequest($"{url}/api/Device/Query?clientId={clientId}");
else
//json = APIHelper.GetInstance.GetRequest($"{url}/api/Device/Query?clientId={clientId}&deviceId={deviceId}");
json = APIHelper.GetInstance.GetRequest($"{url}/api/Device/Query?clientId={clientId}&deviceId={deviceId}");
JsonMsg> jsonMsg = Tools.JsonToObjectTools>>(json);
if (jsonMsg != null && jsonMsg.obj != null && jsonMsg.obj.data != null)
{
device = jsonMsg.obj.data.FirstOrDefault();
if (device == null) return false;
SetValue(device.productkey, device.devicename, device.devicesecret);
IPHostEntry host = Dns.GetHostEntry(Dns.GetHostName());
string _clientIp = host.AddressList.FirstOrDefault(
ip => ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork).ToString();
string t = Convert.ToString(DateTimeOffset.Now.ToUnixTimeMilliseconds());
string signmethod = "hmacmd5";
Dictionary dict = new Dictionary();
dict.Add("productKey", ProductKey);
dict.Add("deviceName", DeviceName);
dict.Add("clientId", _clientIp);
dict.Add("timestamp", t);
mqttUserName = DeviceName + "&" + ProductKey;
mqttPassword = IotSignUtils.sign(dict, DeviceSecret, signmethod);
mqttClientId = _clientIp + "|securemode=3,signmethod=" + signmethod + ",timestamp=" + t + "|";
targetServer = ProductKey + ".iot-as-mqtt." + RegionId + ".aliyuncs.com";
ConnectMqtt(targetServer, mqttClientId, mqttUserName, mqttPassword);
return true;
}
else
{
device = null;
return false;
}
}
catch (Exception ex)
{
device = null;
return false;
}
}
///
/// MQTT创建连接
///
///
///
///
///
private void ConnectMqtt(string targetServer, string mqttClientId, string mqttUserName, string mqttPassword)
{
DatavDeviceClient = new MqttClient(targetServer);
DatavDeviceClient.ProtocolVersion = MqttProtocolVersion.Version_3_1_1;
DatavDeviceClient.Connect(mqttClientId, mqttUserName, mqttPassword, false, 60);
DatavDeviceClient.MqttMsgPublishReceived += Client_MqttMsgPublishReceived;
DatavDeviceClient.ConnectionClosed += Client_ConnectionClosed;
}
///
/// MQTT 断开事件
///
///
///
private void Client_ConnectionClosed(object sender, EventArgs e)
{
// 尝试重连
_TryContinueConnect();
}
///
/// 订阅数据接收
///
///
///
private void Client_MqttMsgPublishReceived(object sender, MqttMsgPublishEventArgs e)
{
string topic = e.Topic;
string message = Encoding.UTF8.GetString(e.Message);
if (DataVMessageAction != null)
{
DataVMessageAction.Invoke(deviceId, topic, message);
}
}
///
/// 自动重连主体
///
private void _TryContinueConnect()
{
Thread retryThread = new Thread(new ThreadStart(delegate
{
while (DatavDeviceClient == null || !DatavDeviceClient.IsConnected)
{
if (DatavDeviceClient.IsConnected) break;
if (DatavDeviceClient == null)
{
DatavDeviceClient = new MqttClient(targetServer);
DatavDeviceClient.ProtocolVersion = MqttProtocolVersion.Version_3_1_1;
DatavDeviceClient.Connect(mqttClientId, mqttUserName, mqttPassword, false, 60);
DatavDeviceClient.MqttMsgPublishReceived += Client_MqttMsgPublishReceived;
DatavDeviceClient.ConnectionClosed += Client_ConnectionClosed;
if (DatavDeviceClient.IsConnected)
{
SubTopicList?.ForEach(par => { DatavDeviceClient.Subscribe(new string[] { par }, new byte[] { 0 }); });
}
Thread.Sleep(3000);
continue;
}
try
{
DatavDeviceClient.Connect(mqttClientId, mqttUserName, mqttPassword, false, 60);
if (DatavDeviceClient.IsConnected)
{
SubTopicList?.ForEach(par => { DatavDeviceClient.Subscribe(new string[] { par }, new byte[] { 0 }); });
UnConnectMqtt?.Invoke("重新连接阿里云MQTT成功!");
}
}
catch (Exception ce)
{
UnConnectMqtt?.Invoke("重新连接阿里云MQTT失败!");
}
// 如果还没连接不符合结束条件则睡2秒
if (!DatavDeviceClient.IsConnected)
{
Thread.Sleep(2000);
}
}
}));
retryThread.Start();
}
#endregion
#region 私有IOT连接变量
private static string ProductKey = "grgpECHSL7q";
private static string DeviceName = "hbldev";
private static string DeviceSecret = "4ec120de0c866199183b22e2e3135aeb";
private static string RegionId = "cn-shanghai";
private static string mqttUserName = string.Empty;
private static string mqttPassword = string.Empty;
private static string mqttClientId = string.Empty;
private static string targetServer = string.Empty;
private static string deviceId = string.Empty;
#endregion
#region 公有变量
///
/// 设备消息数据回调
///
public Action DataVMessageAction { get; set; }
///
/// 重连事件
///
public static Action UnConnectMqtt { get; set; }
///
/// 客户端
///
public static MqttClient DatavDeviceClient { get; set; }
///
/// 当前设备
///
public DeviceTable deviceTable = new DeviceTable();
#endregion
#region 发布或订阅主题或URL地址
///
/// 属性发布消息主题
///
public string PubTopic = "/" + ProductKey + "/" + DeviceName + "/user/update";
///
/// 属性接收消息主题
///
public static string SubTopic = "/" + ProductKey + "/" + DeviceName + "/user/get";
///
/// 自定义发布消息主题
///
public static string UserPubTopic = "/" + ProductKey + "/" + DeviceName + "/user/update";
///
/// 自定义接收消息主题
///
public static string UserSubTopic = "/" + ProductKey + "/" + DeviceName + "/user/get";
///
/// 告警订阅主题
///
public static string AlarmSubTopic = "/" + ProductKey + "/" + DeviceName + "/user/AlarmMessage";
///
/// 日志订阅主题
///
public static string LogsSubTopic = "/" + ProductKey + "/" + DeviceName + "/user/ExceptionLogs";
///
/// 上下线订阅主题
///
public static string HeartbeatSubTopic = "/" + ProductKey + "/" + DeviceName + "/user/HeartbeatAndState";
///
/// 属性状态主题
///
public static string TargetStatusSubTopic = "/" + ProductKey + "/" + DeviceName + "/user/TargetStatus";
///
/// 大屏展示发布主题
///
public static string ScreenShowPubTopic = "/" + ProductKey + "/" + DeviceName + "/user/ScreenShow";
///
/// 广播主题
///
public string BroadcastTopic = "/broadcast/" + "grgpECHSL7q" + "/" + DeviceName + "_SetDevice";
///
/// 文件上传请求Topic
///
public string FileUpLoadTopic = $"/sys/{ProductKey}/{DeviceName}/thing/file/upload/mqtt/init";
///
/// 文件上传请求响应Topic
///
public string FileUpLoadReplyTopic = $"/sys/{ProductKey}/{DeviceName}/thing/file/upload/mqtt/init_reply";
///
/// 文件发送Topic
///
public string FileUpLoadSendTopic = $"/sys/{ProductKey}/{DeviceName}/thing/file/upload/mqtt/send";
///
/// 文件发送响应Topic
///
public string FileUpLoadSendReplyTopic = $"/sys/{ProductKey}/{DeviceName}/thing/file/upload/mqtt/send_reply";
///
/// 取消文件发送Topic
///
public string CancelFileUpLoadSendTopic = $"/sys/{ProductKey}/{DeviceName}/thing/file/upload/mqtt/cancel";
///
/// 取消文件发送响应Topic
///
public string CancelFileUpLoadSendReplyTopic = $"/sys/{ProductKey}/{DeviceName}/thing/file/upload/mqtt/cancel_reply";
///
/// 订阅主题集合
///
public static List SubTopicList = new List();
#endregion
}
///
/// Iot 设备上报
///
public class IotSignUtils
{
public static string sign(Dictionary 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();
}
}
}