基于surging 的木舟平台如何通过HTTP网络组件接入设备

news/2024/11/5 14:55:30/文章来源:https://www.cnblogs.com/fanliang11/p/18527947

一、概述

      上篇文章介绍了木舟如何上传模块热部署,那么此篇文章将介绍如何利用HTTP网络组件接入设备,那么有些人会问木舟又是什么,是什么架构为基础,能做什么呢?

       木舟 (Kayak) 是什么?

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

     那么下面就为大家介绍如何从创建组件、协议、设备网关,设备到设备网关接入,再到设备数据上报,把整个流程通过此篇文章进行阐述。

二、网络组件

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

 开启成功后,可以看看swagger 是否可以访问

 又或者是访问一下中间服务,以上篇文章上传的Testapi 模块为例:

 三、自定义协议

  • 如何创建自定义协议模块

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

  public class Demo5ProtocolSupportProvider : ProtocolSupportProvider{public override IObservable<ProtocolSupport> Create(ProtocolContext context){
      var support = new ComplexProtocolSupport();
    support.Id = "demo5";
    support.Name = "演示协议5";
    support.Description = "演示协议5";support.AddDocument(MessageTransport.Http,
"Document/document-http.md");support.AddAuthenticator(MessageTransport.Http, new Demo5Authenticator()); support.AddRoutes(MessageTransport.Http, new List<BasicMessageCodec>() {BasicMessageCodec.DeviceOnline,BasicMessageCodec.ReportProperty,BasicMessageCodec.WriteProperty,BasicMessageCodec.ReadProperty,BasicMessageCodec.Event}.Select(p => HttpDescriptor.Instance(p.Pattern).GroupName(p.Route.GroupName()).HttpMethod(p.Route.HttpMethod()).Path(p.Pattern).ContentType(MediaType.ToString(MediaType.ApplicationJson)).Description(p.Route.Description()).Example(p.Route.Example())).ToList());support.AddMessageCodecSupport(MessageTransport.Http, () => Observable.Return(new HttpDeviceMessageCodec()));support.AddConfigMetadata(MessageTransport.Http, _httpConfig);return Observable.Return(support);}}

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

 

### 使用HTTP推送设备数据上报属性例子: POST /{productId}/{deviceId}/properties/report
Authorization:{产品或者设备中配置的Token}
Content-Type: application/json{"properties":{"temp":11.5}
}上报事件例子:POST /{productId}/{deviceId}/event/{eventId}
Authorization:{产品或者设备中配置的Token}
Content-Type: application/json{"data":{"createtime": ""}
}

 

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

 

       public class Demo5Authenticator : IAuthenticator{public IObservable<AuthenticationResult> Authenticate(IAuthenticationRequest request, IDeviceOperator deviceOperator){var result = Observable.Return<AuthenticationResult>(default);if (request is DefaultAuthRequest){var authRequest = request as DefaultAuthRequest;deviceOperator.GetConfig(authRequest.GetTransport()==MessageTransport.Http?"token": "key").Subscribe(  config =>{var password = config.Convert<string>();if (authRequest.Password.Equals(password)){result= result.Publish(AuthenticationResult.Success(authRequest.DeviceId));}else{result= result.Publish(AuthenticationResult.Failure(StatusCode.CUSTOM_ERROR, "验证失败,密码错误"));}});}elseresult = 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(async p => {var config=  await p.GetConfig(authRequest.GetTransport() == MessageTransport.Http ? "token" : "key");var password= config.Convert<string>();if(authRequest.Password.Equals(password)){result= result.Publish(AuthenticationResult.Success(authRequest.DeviceId));}else{result= result.Publish(AuthenticationResult.Failure(StatusCode.CUSTOM_ERROR, "验证失败,密码错误"));}});return result;}}

 

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

 

    public static BasicMessageCodec ReportProperty =>new BasicMessageCodec("/*/properties/report", typeof(ReadPropertyMessage), route => route.GroupName("属性上报").HttpMethod("Post").Description("上报物模型属性数据").Example("{\"properties\":{\"属性ID\":\"属性值\"}}"));

 

4.添加消息编解码代码 support.AddMessageCodecSupport(MessageTransport.Http, () => Observable.Return(new HttpDeviceMessageCodec())), 可以自定义编解码,HttpDeviceMessageCodec代码如下:

 

  public class HttpDeviceMessageCodec : DeviceMessageCodec{private readonly MessageTransport _transport;public HttpDeviceMessageCodec() : this(MessageTransport.Http){}private static DefaultHttpResponseMessage Unauthorized(String msg){return new DefaultHttpResponseMessage().ContentType(MediaType.ApplicationJson).Body("{\"success\":false,\"code\":\"unauthorized\",\"message\":\"" + msg + "\"}").Status(HttpStatus.AuthorizationFailed);}private static DefaultHttpResponseMessage BadRequest(){return new DefaultHttpResponseMessage().ContentType(MediaType.ApplicationJson).Body("{\"success\":false,\"code\":\"bad_request\"}").Status(HttpStatus.RequestError);}public HttpDeviceMessageCodec(MessageTransport transport){_transport = transport;}public override IObservable<IDeviceMessage> Decode(MessageDecodeContext context){if (context.GetMessage() is HttpRequestMessage){return DecodeHttpRequestMessage(context);}return Observable.Return<IDeviceMessage>(default);}public override  IObservable<IEncodedMessage> Encode(MessageEncodeContext context){return Observable.Return<IEncodedMessage>(default);}private IObservable<IDeviceMessage> DecodeHttpRequestMessage(MessageDecodeContext context){var result = Observable.Return<IDeviceMessage>(default);var message = (HttpExchangeMessage)context.GetMessage();Header? header = message.Request.GetHeader("Authorization");if (header == null || header.Value == null || header.Value.Length == 0){message.Response(Unauthorized("Authorization header is required")).ToObservable().Subscribe(p => result = result.Publish(default));return result;}var httpToken = header.Value[0];var paths = message.Path.Split("/");if (paths.Length == 0){message.Response(BadRequest()).ToObservable().Subscribe(p => result = result.Publish(default));return result;}String deviceId = paths[1];context.GetDevice(deviceId).Subscribe(async deviceOperator =>{var config = deviceOperator==null?null: await deviceOperator.GetConfig("token");var token = config?.Convert<string>();if (token == null || !httpToken.Equals(token)){await message.Response(Unauthorized("Device not registered or authentication failed"));}else{var deviceMessage = await DecodeBody(message, deviceId);if (deviceMessage != null){await message.Success("{\"success\":true,\"code\":\"success\"}");result = result.Publish(deviceMessage);}else{await message.Response(BadRequest());}}});return result;}private async Task<IDeviceMessage> DecodeBody(HttpExchangeMessage message,string deviceId){byte[] body = new byte[message.Payload.ReadableBytes];message.Payload.ReadBytes(body);var deviceMessage = await TopicMessageCodec.Dodecode(message.Path, body);deviceMessage.DeviceId = deviceId;return deviceMessage;}}

 

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

        private readonly DefaultConfigMetadata _httpConfig = new DefaultConfigMetadata("Http认证配置", "token为http认证令牌").Add("token", "token", "http令牌", StringType.Instance);
  • 如何加载协议模块,协议模块包含了协议模块支持添加引用加载和上传热部署加载。                           

   引用加载模块

 上传热部署协议模块

 四、设备网关

创建设备网关

 五、产品管理

以下是添加产品。

 设备接入

 六、设备管理

添加设备

 HTTP认证配置

 创建告警阈值

 七、测试

 利用Postman 进行测试,以调用http://127.0.0.1:168/{productid}/{deviceid}/properties/report 为例,Authorization设置:123456

1.正常数据测试

 2. 如果是选用Get方式调用,会因为找不到ServiceRoute而返回错误。

 3. 把Authorization改成1111,会返回错误Device not registered or authentication failed,从而上报数据失败

 以上上传的数据可以在设备信息-》运行状态中查看

 告警信息可以在超临界数据中查看

  七、总结

 以上是基于HTTP网络组件设备接入,现有平台网络组件可以支持TCP,MQTT,UDP,CoAP,HTTP,Grpc,websocket,rtmp,httpflv,webservice,tcpclient, 而设备接入支持TCP,UDP,HTTP网络组件,后面会陆续添加支持所有网络组件接入,后面我也会陆续介绍其它网路组件设备接入 ,  然后定于11月20日发布1.0测试版平台。也请大家到时候关注捧场。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/827154.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

易基因: RNA-BS揭示动物不同发育阶段的mRNA m5C甲基化图谱和调控机制|Nat Commun

大家好,这里是专注表观组学十余年,领跑多组学科研服务的易基因。 m5C是已知的RNA修饰之一,但其在mRNA中的发育动态、功能和进化仍然知之甚少。最初报道m5C在mRNA中普遍存在,但后来认识到许多最初被鉴定的位点可能假阳性。准确和系统地检测转录组范围mRNA m5C水平一直具有挑…

硬件设计布线原则

1. 高速电流不应流经低速器件 高速电路的地返回信号也会造成地平面的电压发生变 化。对于地平面或接地走线的感抗,V = Ldi/dt ;对于地平面或接地走线的阻抗,V = RI 。与数字电流一样,高 速电路的地平面或接地走线经过模拟器件时,地线上的电压变化会改变信 号链中信号和地之…

11.9

[实验任务一]:女娲造人 使用简单工厂模式模拟女娲(Nvwa)造人(Person),如果传入参数M,则返回一个Man对象,如果传入参数W,则返回一个Woman对象,如果传入参数R,则返回一个Robot对象。请用程序设计实现上述场景。 实验要求:画出对应的类图;提交源代码;package uml;// Per…

IT监控(进阶篇):运维监控系统手把手部署教学

前言: 注:系统需必须是centos7.4-7.9或redhat7.4-7.9且无其他业务的,不存在nginx、php、mysql、perseusZ_server、ansibles、postgresql等软件,否则一些脚本探测到已安装则会跳过配置文件的修改导致后续安装的系统功能异常。 top #查看系统配置最低要求CPU8核心以上,内存8…

RocketMQ实现优惠券秒杀

RocketMQ实现优惠券秒杀的简单思路秒杀架构图准备数据库 SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0;-- ---------------------------- -- Table structure for goods -- ---------------------------- DROP TABLE IF EXISTS `goods`; CREATE TABLE `goods` (`id` int(11…

2024.11.5 人工智能在小学教育教学中的应用

【知识小课堂1】概念与历史 人工智能(Artificial Intelligence),引文缩写为AI。它是研究、开发用于模拟延伸和扩展人的智能的理论、方法、技术及应用系统的一门新的技术科学。 (一)学科范畴 人工智能是一门边沿学科,属于自然科学、社会科学、技术科学三向交叉学科。 (二)涉及…

S7-1200对V90 PN进行位置控制的三种方法

S7-1200系列PLC通过PROFINET与V90 PN伺服驱动器搭配进行位置控制,实现的方法主要有以下三种: • 方法一、在PLC中组态位置轴工艺对象,V90使用标准报文3,通过MC_Power、MC_MoveAbsolute等PLC Open标准程序块进行控制, 这种控制方式属于中央控制方式(位置控制在PLC中计算,驱…

11.5 人工智能学习内容

人工智能(Artificial Intel ligence) 引文缩写为AI。它是研究、开发用于模拟、延伸和扩展人的智能的理论、方法、技术及应用系统的一门新的技术科学。 (一)学科范畴 人工智能是一门边沿学科,属于自然科学、社会科学、技术科学三向交叉学科。 (二)涉及学科与领域 哲学和认…

Nuxt.js 应用中的 nitro:build:public-assets 事件钩子详解

title: Nuxt.js 应用中的 nitro:build:public-assets 事件钩子详解 date: 2024/11/5 updated: 2024/11/5 author: cmdragon excerpt: nitro:build:public-assets 是 Nuxt 3 中的一个生命周期钩子,在复制公共资产之后调用。该钩子使开发者能够在构建 Nitro 服务器之前,对公…

FB284功能说明

FB284功能说明带增量编码器V90,使用参考挡块+编码器零脉冲方式回零时,参考挡块回零开关接到哪里,怎样配置 回零开关连接到一个PLC的数字量输入点,PLC内编程将其状态关联到FB284功能块ConfigEPos输入引脚的bit6。 (1)将V90参数P29240设置为1(选择参考挡块+零脉冲方式回零)…

《图解设计模式》 第九部分 避免浪费

第二十章 Flyweight 模式public class BigcharFactory{//这里对使用到的内容进行了缓存private HashMap pool = new HashMap();//有则直接取,无则创建并保存到缓存。public synchronized BigChar getBigChar(char charname){BigChar bc = (BigChar) pool.get("" + c…