前言
1、上位机软件通过串口或其他方式读取设备的唯一标识码UUID。
2、上位机调用IoT后台接口,发送UUID和ProductID。
3、后台接口判断设备是否注册过,如果没有注册过,就根据ProductID并按照一定规律生成DeviceName和Password通过接口返回给上位机软件。
4、上位机软件通过串口将接口返回的数据写入设备。.
一、设备注册流程
1、UUID(设备唯一ID,一般为设备主控板编号)
2、ProductID(设备所属产品ID,在IoT后台定义)
3、DeviceName(设备在IoT平台或MQTT的名称,该名称大多与产品相关)
4、Password(设备连接MQTT的密码)
二、MQTT注册
1.在EMQX中添加认证方式





2.创建Api Key


3.调用接口创建用户
http://localhost:18083/api-docs/index.html





三、测试设备连接



四、编写代码
如果设备已经注册过,那么直接从数据库取出设备注册信息返回。
代码编写相对简单,不过多赘述。
namespace MASA.IoT.WebApi.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class DeviceController : ControllerBase
{
private readonly IDeviceHandler _deviceHandler;
public DeviceController(IDeviceHandler deviceHandler)
{
_deviceHandler = deviceHandler;
}
[HttpPost]
public async Task<DeviceRegResponse> DeviceRegAsync(DeviceRegRequest request)
{
return await _deviceHandler.DeviceRegAsync(request);
}
}
}
using MASA.IoT.WebApi.Contract;
using MASA.IoT.WebApi.IHandler;
using MASA.IoT.WebApi.Models.Models;
using Microsoft.EntityFrameworkCore;
namespace MASA.IoT.WebApi.Handler
{
public class DeviceHandler : IDeviceHandler
{
private readonly MASAIoTContext _ioTDbContext;
private readonly IMqttHandler _mqttHandler;
public DeviceHandler(MASAIoTContext ioTDbContext, IMqttHandler mqttHandler)
{
_ioTDbContext = ioTDbContext;
_mqttHandler = mqttHandler;
}
/// <summary>
/// 注册设备
/// </summary>
/// <param name="request"></param>
/// <returns>
/// 设备注册信息
/// </returns>
public async Task<DeviceRegResponse> DeviceRegAsync(DeviceRegRequest request)
{
var productInfo =
await _ioTDbContext.IoTProductInfo.FirstOrDefaultAsync(o => o.ProductCode == request.ProductCode);
if (productInfo == null)
{
return new DeviceRegResponse
{
Succeed = false,
ErrMsg = "ProductCode not found"
};
}
var deviceRegInfo = await GetDeviceRegInfoAsync(request);
if (deviceRegInfo != null) //已经注册过
{
return deviceRegInfo;
}
else //没有注册过
{
var deviceName = await GenerateDeviceNameAsync(productInfo.SupplyNo, request.ProductCode, request.UUID);
var password = Guid.NewGuid().ToString("N");
var addDeviceResponse = await _mqttHandler.DeviceRegAsync(deviceName, password);
if (addDeviceResponse.user_id == deviceName) //注册成功
{
deviceRegInfo = new DeviceRegResponse
{
DeviceName = deviceName,
Password = password,
Succeed = true,
ErrMsg = string.Empty
};
await _ioTDbContext.IoTDeviceInfo.AddAsync(new IoTDeviceInfo
{
Id = Guid.NewGuid(),
DeviceName = deviceName,
Password = password,
ProductInfoId = productInfo.Id,
});
await _ioTDbContext.SaveChangesAsync();
return deviceRegInfo;
}
return new DeviceRegResponse
{
Succeed = false,
ErrMsg = addDeviceResponse.message
};
}
}
/// <summary>
/// 获取设备注册信息
/// </summary>
/// <param name="request"></param>
/// <returns>
/// 设备已经注册返回设备注册信息,没有注册过返回null
/// </returns>
private async Task<DeviceRegResponse?> GetDeviceRegInfoAsync(DeviceRegRequest request)
{
var deviceware = await _ioTDbContext.IoTDevicewares.FirstOrDefaultAsync(o => o.ProductCode == request.ProductCode && o.UUID == request.UUID);
if (deviceware == null)
{
return null;
}
else
{
var deviceInfo = await _ioTDbContext.IoTDeviceInfo.FirstAsync(o => o.DeviceName == deviceware.DeviceName);
return new DeviceRegResponse
{
DeviceName = deviceInfo.DeviceName,
Password = deviceInfo.Password,
Succeed = true,
ErrMsg = string.Empty
};
}
}
/// <summary>
/// 生成设备名称
/// </summary>
/// <param name="supplyNo"></param>
/// <param name="productCode"></param>
/// <param name="uuid"></param>
/// <returns>
/// 设备Mqtt名称
/// </returns>
private async Task<string> GenerateDeviceNameAsync(string supplyNo, string productCode, string uuid)
{
var lastDeviceware = await _ioTDbContext.IoTDevicewares.Where(o => o.ProductCode == productCode).OrderByDescending(o => o.CreationTime).FirstOrDefaultAsync();
var newDeviceware = new IoTDevicewares
{
Id = Guid.NewGuid(),
UUID = uuid,
ProductCode = productCode,
CreationTime = DateTime.Now
};
if (lastDeviceware != null && lastDeviceware.DeviceName.StartsWith(supplyNo + DateTime.Today.ToString("yyyyMMdd")))
{
newDeviceware.DeviceName = (long.Parse(lastDeviceware.DeviceName) + 1).ToString();
}
else
{
newDeviceware.DeviceName = supplyNo + DateTime.Today.ToString("yyyyMMdd") + "0001";
}
await _ioTDbContext.IoTDevicewares.AddAsync(newDeviceware);
await _ioTDbContext.SaveChangesAsync();
return newDeviceware.DeviceName;
}
}
}
using Flurl.Http;
using MASA.IoT.WebApi.Contract.Mqtt;
using MASA.IoT.WebApi.IHandler;
using Microsoft.Extensions.Options;
using System.Net;
namespace MASA.IoT.WebApi.Handler
{
public class MqttHandler : IMqttHandler
{
private readonly AppSettings _appSettings;
public MqttHandler(IOptions<AppSettings> settings)
{
_appSettings = settings.Value;
}
public async Task<AddDeviceResponse> DeviceRegAsync(string deviceName,string password)
{
var url = $"{_appSettings.MqttSetting.Url}/api/v5/authentication/password_based:built_in_database/users";
var response = await url.WithBasicAuth(_appSettings.MqttSetting.ApiKey, _appSettings.MqttSetting.SecretKey).AllowAnyHttpStatus().PostJsonAsync(new AddDeviceRequest
{
user_id = deviceName,
password = password,
}
);
if (response.StatusCode is (int)HttpStatusCode.Created or (int)HttpStatusCode.BadRequest or (int)HttpStatusCode.NotFound)
{
return await response.GetJsonAsync<AddDeviceResponse>();
}
else
{
throw new UserFriendlyException(await response.GetStringAsync());
}
}
}
}
总结
完整代码在这里:https://github.com/sunday866/MASA.IoT-Training-Demos