凯亚物联网平台如何通过MQTT网络组件接入设备

凯亚物联网平台如何通过MQTT网络组件接入设备

一、概述

    有人提议我用kestrel代替Dotnetty ,那是不可能的, 物联网平台MQTT,rtmp,rtsp,httpflv,tcp,udp,rpc 都是基于dotnetty实现,压测没有问题,每秒可以达到20w/s,当中因为SingleThreadEventExecutor的问题 导致每天内存会增加的问题,我会通过源码修复,修复完成我会开通MQTT,http,tcp,udp,coap端口提供给大家测试。

 

      凯亚 (Kayak) 是什么?

       凯亚(Kayak)是基于.NET6.0软件环境下的surging微服务引擎进行开发的, 平台包含了微服务和物联网平台。支持异步和响应式编程开发,功能包含了物模型,设备,产品,网络组件的统一管理和微服务平台下的注册中心,服务路由,模块,中间服务等管理。还有多协议适配(TCP,MQTT,UDP,CoAP,HTTP,Grpc,websocket,rtmp,httpflv,webservice,等),通过灵活多样的配置适配能够接入不同厂家不同协议等设备。并且通过设备告警,消息通知,数据可视化等功能。能够让你能快速建立起微服务物联网平台系统。

     凯亚物联网平台:http://117.72.121.2:3100(用户名:fanly 密码:123456)

    链路跟踪Skywalking V8:http://117.72.121.2:8080/

      surging 微服务引擎开源地址:https://github.com/fanliang11/surging(后面surging 会移动到microsurging进行维护)

二、网络组件

1.编辑创建MQTT协议的网络组件,可以选择共享配置和独立配置(独立配置是集群模式)

 

三、自定义协议

如何创建自定义协议模块

如果是网络编程开发,必然会涉及到协议报文的编码解码处理,那么对于平台也是做到了灵活处理,首先是协议模块创建,通过以下代码看出协议模块可以添加协议说明md文档, 身份鉴权处理,HTTP路由,消息编解码,元数据配置。下面一一介绍如何进行编写

  public class Demo5ProtocolSupportProvider : ProtocolSupportProvider

    {

             private readonly DefaultConfigMetadata _mqttConfig = new DefaultConfigMetadata(

        "Mqtt认证配置"

        , "secureId以及secureKey在创建设备产品或设备实例时进行配置.\r\n timestamp为当前时间戳(毫秒), 与服务器时间不能相差5分钟.\r\n md5为32位, 不区分大小写")

        .Add("secureId", "secureId", "用户唯一标识编号", StringType.Instance)

        .Add("secureKey", "secureKey", "密钥", StringType.Instance);

        public override IObservable<ProtocolSupport> Create(ProtocolContext context)

        {

      var support = new ComplexProtocolSupport();

              support.Id = "demo5";

              support.Name = "演示协议5";

              support.Description = "演示协议5";

               support.AddDocument(MessageTransport.Mqtt, "Document/document-mqtt.md");

           support.AddAuthenticator(MessageTransport.Mqtt, new DefaultAuthenticator());

 support.AddRoutes(MessageTransport.Mqtt, new List<TopicMessageCodec>() {

    TopicMessageCodec.DeviceOnline,

     TopicMessageCodec.ReportProperty,

     TopicMessageCodec.WriteProperty,

      TopicMessageCodec.ReadProperty,

        TopicMessageCodec.Event

 }.Select(p => MqttDescriptor.Instance(p.Pattern)

     .GroupName(p.Route.GroupName())

     .Path(p.Pattern)

     .ContentType(MediaType.ToString(MediaType.ApplicationJson))

     .Description(p.Route.Description())

     .Example(p.Route.Example())

).ToList());

           support.AddMessageCodecSupport(MessageTransport.Mqtt, () => Observable.Return(new ScriptDeviceMessageCodec(support.Script)));

        support.AddConfigMetadata(MessageTransport.Mqtt, _mqttConfig);

       return Observable.Return(support);

               

        }

     

     }                

1. 添加协议说明文档如代码: support.AddDocument(MessageTransport.Http, "Document/document-http.md");,文档仅支持markdown文件,如下所示

 

### 认证说明

CONNECT报文:

```text

clientId: 设备ID

username: secureId+"&"+timestamp

password: md5(secureId+"&"+timestamp+"&"+secureKey)

 ```

说明: secureId以及secureKey在创建设备产品或设备实例时进行配置.

    timestamp为当前时间戳(毫秒), 与服务器时间不能相差5分钟.

        md5为32位, 不区分大小写.

 

2. 添加身份鉴权如代码: support.AddAuthenticator(MessageTransport.Http, new Demo5Authenticator()) ,自定义身份鉴权Demo5Authenticator 代码如下:

 

    public class DefaultAuthenticator : IAuthenticator

    {

        public IObservable<AuthenticationResult> Authenticate(IAuthenticationRequest request, IDeviceOperator deviceOperation)

        {

            var result = Observable.Return<AuthenticationResult>(default);

            if (request is DefaultAuthRequest)

            {

                var authRequest = request as DefaultAuthRequest;  

                var username = authRequest.UserName; 

                var password = authRequest.Password;

                String[] arr = username.Split("&");

                if (arr.Length <= 1)

                {

                    return Observable.Return(AuthenticationResult.Failure(StatusCode.CUSTOM_ERROR, "用户名格式错误"));

                }

                var requestSecureId = arr[0];

                long.TryParse(arr[1], out long time);

                if (Math.Abs(Utility.CurrentTimeMillis() - time) > TimeSpan.FromMinutes(10).TotalMilliseconds)

                {

                    return Observable.Return(AuthenticationResult.Failure(StatusCode.CUSTOM_ERROR, "时间不一致"));

                }

                var configs = deviceOperation.GetConfigs("secureId", "secureKey").Subscribe(p =>

                {

                    try

                    {

                        var secureId = p.GetValue("secureId").Convert<string>();

                        var secureKey = p.GetValue("secureKey").Convert<string>();

                        var encryptStr = $"{username}&{secureKey}".GetMd5Hash();

                        if (requestSecureId.Equals(secureId) && encryptStr.Equals(password))

                        {

                            result= result.Publish(AuthenticationResult.Success(deviceOperation.GetDeviceId()));

                        }

                        else

                        {

                            result= result.Publish(AuthenticationResult.Failure(StatusCode.CUSTOM_ERROR, "验证失败,密钥错误"));

                        }

                    }

                    catch (Exception ex)

                    {

                        result = result.Publish(AuthenticationResult.Failure(StatusCode.CUSTOM_ERROR, "请求参数格式错误"));

                    }

                });

            }

            else

            result = Observable.Return<AuthenticationResult>(AuthenticationResult.Failure(StatusCode.CUSTOM_ERROR, "不支持请求参数类型"));

            return result;

        }

        public IObservable<AuthenticationResult> Authenticate(IAuthenticationRequest request, IDeviceRegistry registry)

        {

            var result = Observable.Return<AuthenticationResult>(default);

            var authRequest = request as DefaultAuthRequest;

            registry

              .GetDevice(authRequest.DeviceId)

              .Subscribe( p =>Authenticate(request, p).Subscribe(authResult => result = result.Publish(authResult)));

            return result;

        }

    }

 

3. 添加Http路由代码support.AddRoutes,那么如何配置呢,代码如下:

 

    public static BasicMessageCodec ReportProperty =>

 new BasicMessageCodec("/*/properties/report", typeof(ReadPropertyMessage), route => route.GroupName("属性上报") 

                     .Description("上报物模型属性数据")

                     .Example("{\"properties\":{\"属性ID\":\"属性值\"}}"));

 

4.添加元数据配置代码 support.AddConfigMetadata(MessageTransport.Http, _httpConfig); _httpConfig代码如下

        private readonly DefaultConfigMetadata _mqttConfig = new DefaultConfigMetadata(

"Mqtt认证配置"

, "secureId以及secureKey在创建设备产品或设备实例时进行配置.\r\n timestamp为当前时间戳(毫秒), 与服务器时间不能相差5分钟.\r\n md5为32位, 不区分大小写")

.Add("secureId", "secureId", "用户唯一标识编号", StringType.Instance)

.Add("secureKey", "secureKey", "密钥", StringType.Instance);

如何加载协议模块,协议

模块包含了协议模块支持添加引用加载和上传热部署加载。                           

   引用加载模块

 

 上传热部署协议模块

 四、设备网关

创建设备网关

 五、产品管理

以下是添加产品。

  设备接入

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

牛马程序员2025

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值