using Edge.Core.IndustryStandardInterface.NetworkController;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using static DeviceInfoToAliIotHubViaGateway.App;
namespace DeviceInfoToAliIotHubViaGateway
{
///
/// helper for open and connect to a AliIotHub MqttServer.
///
internal class AliIotHubMqttClientInitializer
{
private IMqttClientNetworkController mqttClient;
//private static readonly AliIotHubMqttClientInitializer instance = new AliIotHubMqttClientInitializer();
public IMqttClientNetworkController MqttClient => this.mqttClient;
//private ILogger logger = null;
//public static AliIotHubMqttClientInitializer New(ILogger logger)
//{
// return new AliIotHubMqttClientInitializer(logger);
//}
internal AliIotHubMqttClientInitializer(IMqttClientNetworkController mqttClient)
{
this.mqttClient = mqttClient;
}
//public static AliIotHubMqttClientInitializer Default => instance;
///
/// 一型一密免预注册的设备动态注册方式,通过此次交互,可以获得设备的ProductKey、DeviceName、ClientID、DeviceToken,相当于在IOT上建立了此设备,再就可以像普通设备一样发起通讯了.
///
///
///
/// 表示客户端ID,建议使用设备的MAC地址或SN码
///
///
///
///
public async Task DynamicRegDeviceWithoutPreRegAsync(string mqttServerUrl, int port,
string mqttClientIdPrefix, string productKey, string productSecret, string dynamicDeviceName)
{
var rebootSucceed = await this.mqttClient.ResetAsync();
if (!rebootSucceed)
{
await Task.Delay(500);
return null;
}
await Task.Delay(2000);
//this.logger.LogInformation(" Querying Mqtt client status...");
var status = await this.mqttClient.QueryStatusAsync();
//this.logger.LogInformation(" Mqtt client Status is: " + status);
if (status != NetworkState.NetworkConnected)
return null;
bool succeed = false;
// looks like the sample in BC35g Mqtt protocol doc is not work via below command.
//succeed = await this.mqttClient.ConfigNetwork(AliIotHub_ProductKey,
// AliIotHub_DeviceName, AliIotHub_DeviceSecret);
//if (!succeed)
//{
// await Task.Delay(500);
// return false;
//}
succeed = await this.mqttClient.OpenAsync(mqttServerUrl, port);
if (!succeed)
{
await Task.Delay(500);
await this.mqttClient.CloseAsync();
return null;
}
Random r = new Random();
int random = 199;// r.Next(1, 1000000);
var toBeHashing = $"deviceName{dynamicDeviceName}productKey{productKey}random{random}";
var aliIotHubMqttPwd = Encoding.UTF8.GetBytes(toBeHashing).SignWithHMacSHA1(Encoding.UTF8.GetBytes(productSecret));
string aliIotHub_MqttComplexClientId = mqttClientIdPrefix + "|securemode=2,authType=regnwl,random=" + random + ",signmethod=hmacsha1|";
var aliIotHubMqttUserName = dynamicDeviceName + "&" + productKey;
var onMsgReceivedTCS = new TaskCompletionSource();
EventHandler evtHandler = (s, a) =>
{
if (a.Message.Topic == "/ext/regnwl")
onMsgReceivedTCS.SetResult(Encoding.UTF8.GetString(a.Message.Message));
};
this.mqttClient.OnMessageReceived += evtHandler;
succeed = await this.mqttClient.ConnectAsync(aliIotHub_MqttComplexClientId, aliIotHubMqttUserName, aliIotHubMqttPwd);
if (!succeed)
{
await Task.Delay(500);
await this.mqttClient.DisconnectAsync();
return null;
}
try
{
var ti = Task.WaitAny(new[] { Task.Delay(6000), onMsgReceivedTCS.Task });
if (ti == 0)
return null;
var dynamicRegistedGatewayDeviceInfo = JsonSerializer.Deserialize(onMsgReceivedTCS.Task.Result);
return dynamicRegistedGatewayDeviceInfo;
}
finally
{
this.mqttClient.OnMessageReceived -= evtHandler;
}
}
///
/// 用设备的ProductKey、DeviceName、ClientID、DeviceToken,像普通设备一样发起通讯.
///
/// 网关设备
///
public async Task DynamicDeviceConnAsync(string mqttServerUrl, int port, DynamicDeviceInfo dynamicDeviceInfo)
{
var rebootSucceed = await this.mqttClient.ResetAsync();
if (!rebootSucceed)
{
await Task.Delay(500);
return false;
}
await Task.Delay(2000);
//this.logger.LogInformation(" Querying Mqtt client status...");
var status = await this.mqttClient.QueryStatusAsync();
//this.logger.LogInformation(" Mqtt client Status is: " + status);
if (status != NetworkState.NetworkConnected)
return false;
bool succeed = false;
// looks like the sample in BC35g Mqtt protocol doc is not work via below command.
//succeed = await this.mqttClient.ConfigNetwork(AliIotHub_ProductKey,
// AliIotHub_DeviceName, AliIotHub_DeviceSecret);
//if (!succeed)
//{
// await Task.Delay(500);
// return false;
//}
succeed = await this.mqttClient.OpenAsync(mqttServerUrl, port);
if (!succeed)
{
await Task.Delay(500);
await this.mqttClient.CloseAsync();
return false;
}
var aliIotHubMqttPwd = dynamicDeviceInfo.deviceToken;
string aliIotHub_MqttComplexClientId = dynamicDeviceInfo.clientId + "|securemode=-2,authType=connwl|";
var aliIotHubMqttUserName = dynamicDeviceInfo.deviceName + "&" + dynamicDeviceInfo.productKey;
succeed = await this.mqttClient.ConnectAsync(aliIotHub_MqttComplexClientId, aliIotHubMqttUserName, aliIotHubMqttPwd);
if (!succeed)
{
await Task.Delay(500);
await this.mqttClient.DisconnectAsync();
return false;
}
return true;
}
}
}