关于iot:使用MASA全家桶从零开始搭建IoT平台二设备注册

97次阅读

共计 6059 个字符,预计需要花费 16 分钟才能阅读完成。

前言

咱们不心愿任何设施都能够接入咱们的 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 增加设施,并同时存储到数据库中。
如果设施曾经注册过,那么间接从数据库取出设施注册信息返回。
代码编写绝对简略,不过多赘述。

//DeviceController
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);
        }
    }
}
//DeviceHandler
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;
        }
    }
}

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

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

总结

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

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

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

WeChat:MasaStackTechOps
QQ:7424099

正文完
 0