前言

咱们不心愿任何设施都能够接入咱们的IoT平台,所以一个设施失常的接入流程是这样的,
1、上位机软件通过串口或其余形式读取设施的惟一标识码UUID
2、上位机调用IoT后盾接口,发送UUIDProductID
3、后盾接口判断设施是否注册过,如果没有注册过,就依据ProductID并依照肯定法则生成DeviceNamePassword通过接口返回给上位机软件。
4、上位机软件通过串口将接口返回的数据写入设施。

一、设施注册流程

这里次要波及四个概念
1、UUID(设施惟一ID,个别为设施主控板编号)
2、ProductID(设施所属产品ID,在IoT后盾定义)
3、DeviceName(设施在IoT平台或MQTT的名称,该名称大多与产品相干)
4、Password(设施连贯MQTT的明码)

二、MQTT注册

1.在EMQX中增加认证形式

抉择Built-in Database形式,内置数据库进行明码认证

账号类型抉择username,加密形式和加盐形式能够放弃默认。

点击创立后能够在认证菜单中看到新建的认证形式,状态为:已连贯。

咱们点击用户治理->增加 能够手动创立用户

这里的场景咱们是通过上位机调用IoT后端,IoT接口外部调用EMQX接口来实现主动创立用户的

2.创立Api Key

调用接口须要认证,这里咱们应用Api key的形式,咱们在零碎设置->API密钥中创立一个API密钥

Secret Key 只有创立的时候才会显示明文,咱们须要记录下API Key 和 Secret Key

3.调用接口创立用户

咱们在浏览器关上EMQX 的RestAPI swagger

http://localhost:18083/api-docs/index.html

咱们能够通过这个接口来创立用户,这里的Authenticator ID 就是咱们下面创立的内置数据库 Password Based的ID,

这个ID的获取通过上面的authentication办法获取

咱们在认证中间接应用API Key 和 Secret Key,接口返回Id:password_based:built_in_database

调用authentication的Post接口,在 id字段输出:password_based:built_in_database,Request body中输出设施的user_id和password即可胜利创立用户。

咱们在Deshboard的界面中也能够看到刚刚创立的用户

三、测试设施连贯

咱们应用MQTTX来模仿客户端设施通过mqtt协定连贯到EMQX,新建连贯,填写地址、端口、和刚刚通过Api创立用户名明码。

点击连贯、发现设施曾经能够失常连贯mqtt了。

在Dashboard中也能够看到以后连贯的客户端ID等信息。

四、编写代码

在MASA.IoT.WebApi我的项目种增加DeviceController控制器并增加DeviceRegAsync办法用于设施注册,设施如果没有注册过(UUID 数据库不存在),那么会依据ProductCode依照法则生成设施名称,名称以该产品供应商编号结尾,后跟工夫和序号。而后向EMQX增加设施,并同时存储到数据库中。
如果设施曾经注册过,那么间接从数据库取出设施注册信息返回。
代码编写绝对简略,不过多赘述。

//DeviceControllernamespace 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);        }    }}
//DeviceHandlerusing 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;        }    }}

这里生成设施名称用了一个简略的算法

// MqttHandlerusing 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());            }        }    }}

总结

以上就是本文要讲的内容,本文介绍了通过账号密码的形式通过接口在EMQX中创立用户,并连贯EMQX的过程,EMQX反对的赖账形式还有很多,例如JWT认证形式能够受权一次性明码认证,能够管制认证的有效期,咱们在前面的章节具体利用中会进行阐明。

残缺代码在这里:https://github.com/sunday866/MASA.IoT-Training-Demos

如果你对咱们的MASA感兴趣,无论是代码奉献、应用、提 Issue,欢送分割咱们

WeChat:MasaStackTechOps
QQ:7424099