线上测试木舟物联网平台之如何通过HTTP网络组件接入设备
一、概述
木舟 (Kayak) 是什么?
木舟(Kayak)是基于.NET6.0软件环境下的surging微服务引擎进行开发的, 平台包含了微服务和物联网平台。支持异步和响应式编程开发,功能包含了物模型,设备,产品,网络组件的统一管理和微服务平台下的注册中心,服务路由,模块,中间服务等管理。还有多协议适配(TCP,MQTT,UDP,CoAP,HTTP,Grpc,websocket,rtmp,httpflv,webservice,等),通过灵活多样的配置适配能够接入不同厂家不同协议等设备。并且通过设备告警,消息通知,数据可视化等功能。能够让你能快速建立起微服务物联网平台系统。
那么下面就为大家介绍如何从创建组件、协议、设备网关,设备到设备网关接入,再到设备数据上报,把整个流程通过此篇文章进行阐述。
木舟物联网平台:http://117.72.121.2:3100
surging 微服务引擎开源地址:https://github.com/fanliang11/surging(后面surging 会移动到microsurging进行维护)
二、木舟物联网平台管理平台界面
用户名:fanly 密码:123456

三、链路跟踪监控
地址:http://117.72.121.2:8080/ (这是社区版,仅支持v6.0 ,企业版本支持v8.0)


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

开启成功后,可以看看swagger 是否可以访问
地址:http://117.72.121.2:281/swagger/index.html

开启成功后,可以看看webservice是否可以访问
webservice:http://117.72.121.2:168/devicedata/devicedata/changedevicestage.asmx?servicekey=WebService

五、自定义协议
- 如何创建自定义协议模块
如果是网络编程开发,必然会涉及到协议报文的编码解码处理,那么对于平台也是做到了灵活处理,首先是协议模块创建,通过以下代码看出协议模块可以添加协议说明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, "验证失败,密码错误"));
}
});
}
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(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://117.72.121.2:168/{productid}/{deviceid}/properties/report 为例,Authorization设置:123456
测试地址:http://117.72.121.2:168/product-http-23/DJI-Mavic-v231x12/properties/report
1.正常数据测试

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

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

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

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

四、结尾
如果感兴趣可以联系作者开通端口进行测试,后面陆续会把协议接入到木舟物联网平台,到时候可以支持多终端操作可视化管理。
线上测试木舟物联网平台之如何通过HTTP网络组件接入设备的更多相关文章
- rsync实现负载均衡集群文件同步,搭建线上测试部署环境
闲来无事,搭建一个负载均衡集群,至于负载均衡集群搭建过程,找时间写下.这次主要写集群之间的文件同步,以及线上测试环境的搭建. 笔者看过很多公司都没有线上测试环境,真是崩溃了,不造怎么确保线上线下环境一 ...
- 【线上测试之后的应用】基于MySQL+MHA+Haproxy构建高可用负载均衡数据库集群(详解)
这里我们先介绍一下MHA是什么,其次就是它的应用与测试,同时为了大家呈现了数据备份案例,最后总结了使用情况以及注意事项和解决办法 一.MHA 概述 MHA(Master High Availabili ...
- idea 分 环境 配置 线上 测试 本地
在resources 新建application.properties 分开在resources 新建的多个环境的文件 #测试环境 applicaion-test.properties #开发环境 a ...
- 测试开发【提测平台】分享12-掌握日期组件&列表状态格式化最终实现提测管理多条件搜索展示功能
微信搜索[大奇测试开],关注这个坚持分享测试开发干货的家伙. 本章内容思维导图如下,由于需要各种状态下的菜单操作,所以需要先实现提测信息的列表基础页面,然后再推进其他需求开发 基本知识点学习 Date ...
- 测试右移:线上质量监控 ELK 实战
目录 [测试右移]介绍 ELK Stack 介绍 ELK 监控体系搭建 ES & Kibana 搭建 Nginx 日志自动采集 Nginx Agent 安装 Nginx 服务器 数据分析 Lo ...
- 国外物联网平台(8):Telit
国外物联网平台(8) ——Telit 马智 定位 We Bring IoT to Life Telit提供世界上最全面的高性能物联网模块.连接服务和软件. 产品体系 模块 Telit提供丰富专业的物联 ...
- 线上日志集中化可视化管理:ELK
本文来自网易云社区 作者:王贝 为什么推荐ELK: 当线上服务器出了问题,我们要做的最重要的事情是什么?当需要实时监控跟踪服务器的健康情况,我们又要拿什么去分析?大家一定会说,去看日志,去分析日志.是 ...
- 微软官方网站线上兼容测试平台-Browser screenshots
前端开发时最不想做的就是在不同浏览器.平台和分辨率测试网页显示效果,通常这会浮现许多问题,尤其浏览器版本就可能让显示成效完全不同,也只好尽力维持让每一种设备都能正常浏览网页.修改到完全没有问题必须投入 ...
- Auty 2017——WebMonitor接口线上检测平台
[本文出自天外归云的博客园] Auty 2017——WebMonitor接口检测平台 前篇 接口本地检测平台 本篇 接上篇,在本地检测平台的基础上,去掉本地服务,改功能为线上使用.好处是项目可以多人访 ...
- wechat开发笔记之1.线上环境搭建与测试
Wechat开发笔记 线上环境搭建: 申请一个wechat公众平台. 手机个人微信可以用webwechat来测试. Website:https://web.weixin.qq.com/ 手机客户端扫一 ...
随机推荐
- 解决docker 容器设置中文语言包出现的问题_docker
https://www.anquanclub.cn/5821.html 这篇文章主要介绍了解决docker 容器设置中文语言包出现的问题,具有很好的参考价值,希望对大家有所帮助.一起跟随小编过来看看吧 ...
- MAC brew install 跳过 update
相信很多用 MAC 小伙伴的小伙伴都对 HomeBrew 很熟悉. 但是! 都遇到过这样的问题, 每次安装新东西, 它都要先去 update 一下, 那个耗时啊-. 怎么才能不 update, 直接安 ...
- Python包管理不再头疼:uv工具快速上手
Python 包管理生态中存在多种工具,如 pip.pip-tools.poetry.conda 等,各自具备一定功能. 而今天介绍的uv 是 Astral 公司推出的一款基于 Rust 编写的 Py ...
- JpaRepository动态代理执行原理
本文基于spring-boot-starter-data-jpa:2.7.17分析 SpringBoot 里集成Jpa自动配置是如何处理的 通过分析SpringBoot 自动配置核心源码可以找到Jpa ...
- 深入剖析数据删除操作:DELETE 语句的使用与管理实践
title: 深入剖析数据删除操作:DELETE 语句的使用与管理实践 date: 2025/1/8 updated: 2025/1/8 author: cmdragon excerpt: 数据删除( ...
- Solution Set -「LGR-126」洛咕咕的 NOIP 模拟赛
机房在三楼, 不在五楼. 三楼确实有阶梯教室. 三楼向外望是一楼大厅屋顶所以看上去不高. 十一点前必须离开科技楼是因为爱因斯坦要锁大门. 我不会被自己写的东西清空 san 值. ...
- CF div2 994 (A~E)
VP赛时三题,自我感觉发挥不错,唯一不满意的地方在于D题完全没有思路. A 答案最多为2,因为最坏情况即为先将整个区间合并为一个数,若这个数不是0,则再将这个数变为0. 所以3种情况分类讨论即可: 全 ...
- bat脚本判断windows服务,判断windows进程
bat脚本判断windows服务是否存在,方式一: sc query|findstr /i "ZhuDongFangYu" &&echo "存在" ...
- 在 Windows 10 上实现免密码 SSH 登录
前言 在日常开发中,SSH(Secure Shell)作为一种安全的远程登录协议,广泛用于 Linux 和 Windows 系统之间的连接.为了提高效率,我们可以通过配置免密码登录,省去每次连接时输入 ...
- Python · Jax | 在 python 3.8 上安装 jax,运行 offline RL 的 IQL
致谢师兄的 jax 环境,完全按照师兄的 conda_env.yml 配置的 (如何导出其他环境的 conda_env.yml:Conda | 如何(在新服务器上)复制一份旧服务器的 conda 环境 ...