概述
名词说明
南北向:
给物联中心提供数据的平台或者终端称为南向
、物联中心给外部数据的称为北向
上下行:
上行为南向到平台的数据,多为南向系统推送或设备主动上报的数据
、下行为平台到南向的数据,平台请求南向系统或下发消息到终端设备
编解码器:
通过标准骨架,完成编码、解码等协议的开发,实现子系统集成、终端设备接入的协议包
编解码器-编码:
一是物联中心下发指令到子系统或终端的指令编码过程,
、二是物联中心按第三方接口协议调用,获取数据并进行解析为标准数据格式的过程
编解码器-解码:
物联中心对第三方平台(或终端设备)主动推送数据进行解析为标准数据格式的过程
标准数据格式:
物联中心可以直接解析的数据格式
,类型分为设备数据
、告警数据
、功能操作
协议组件:
数据传输协议,目前仅支持HTTP、MQTT两种
解码上下文 DecoderCodecContext
包含上行原始数据Payload、需解析数据格式类型ReplyMessage、协议基础信息CodecMetadata、协议配置参数JSONObject
编码上下文 EncoderCodecContext
包含功能操作信息FuncReplyMessage、设备信息(可能为null)DeviceMetadata、协议基础信息CodecMetadata、协议配置参数JSONObject
服务环境
演示环境
地址:https://pai.flyrise.cn/iot-cns
账号:admin
密码:admin123本地环境(dev)
idea工具、jdk1.8+、node.js
协议组件
MQTT
支持上下行
,数据收发由系统控制
topic订阅规则
通过消息模板配置
topic发布规则
通过消息模板配置
HTTP
支持上下行
,其中下行由编解码器控制(即开发者控制)
注意:`clientId=xx&secureKey=xxx为北向授权认证账号信息`
设备信息上报(上行)
接口地址:
/open/api/northbound/push/device/{topic}/*?clientId=xx&secureKey=xxx
参数:JSON告警事件上报(上行)
接口地址:
/open/api/northbound/push/event/{topic}/*?clientId=xx&secureKey=xxx
参数:JSON功能调用(下行)
接口地址:
/open/api/northbound/func/*?clientId=xx&secureKey=xxx
参数:{ deviceId:"设备ID", func:"功能标识", req:{ // 请求参数 } }
南向接入
MQTT服务申请
这里使用emq官方服务器演示,如果有其他环境可用的MQTT服务器则也可使用其他
https://cloud.emqx.com/console/
- 登录emq官网,点免费试用,微信登录,选第一个套餐部署。
这三个参数和CA证书都有用
创建一个账号,账号root,密码root
点击在线调试
地址是连接地址,端口用WebSocket端口,用户密码就是刚刚创的用户密码
飞企标准协议方式
- 南向平台添加内置的
飞企标准协议
,并进行激活
- 北向授权账号
- 数据推送
飞企边缘网关方式
- 部署
pai-node-red
编排引擎
- 南向平台添加内置的
飞企边缘网关
- 配置
飞企边缘网关
参数,并进行激活
- 北向授权账号
登录Node-Red地址新建一个测试流文件
流文件编排,得到一个用于订阅MQTT主题的订阅客户端,和一个用于发布MQTT主题消息的发布客户端。
发布使用定时器加固定参数的形式模拟定时采集设备信息过程。
部署,如果两个MQTT节点都是绿色(连接状态)则成功
点击定时器发送一条信息
可以看到订阅了同一主题的Node-Red和emq官方客户端都打印了一条接收到信息的记录,至此可视为Node-Red与MQTT服务器连接正常
jar编解码器方式
默认功能方法
主要针对南向子系统需要物联中心主动去调用接口获取数据的,这类子系统需要实现物联中心定义的默认功能方法,部分功能方法有默认的参数定义
/**
* 默认功能方法
* @author zhangq
* @date 2023-3-13
*/
public enum SubsystemFunc {
GET_DEVICE_LIST("getDeviceList", "获取设备列表"),
GET_DEVICE_INFO("getDeviceInfo", "获取设备信息"),
GET_EVENT_LIST("getEventList", "获取告警记录"),
PLATFORM_URL("platformUrl", "平台地址"),
VIDEO_STREAM_URL("videoStreamUrl", "视频流地址"),
INIT("init", "初始化"),
;
}
- GET_DEVICE_LIST 获取设备列表
默认参数:
{
deviceType:"设备类型(参考字典附件),为空则获取所有类型",
}
- GET_DEVICE_INFO 获取设备信息
默认参数:
{
type:"类型:0查询全部|1查询具体",
deviceIds:["设备标识集,为空则获取所有设备的信息"]
}
- GET_EVENT_LIST 获取告警记录
默认参数:
{
eventType:"告警类型(参考字典附件),为空则获取所有类型",
}
- PLATFORM_URL 平台地址
默认参数:无
- VIDEO_STREAM_URL 视频流地址
默认参数:
{
deviceId:"设备标识,为空则获取所有设备的信息",
type:"类型:0实时视频流|1回放视频流",
beginTime:"开始时间,实时类型时此参数为空",
endTime:"结束时间-实时类型时此参数为空",
}
- INIT 初始化
默认参数:无
步骤一:编解码器工程创建
方式一:使用pai工具创建物联中心脚手架,创建指令:pai create service -n pai-ibms-prot-demo –ibmsprot
方式二:创建java maven工程,pom.xml配置如下
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.flyrise.pai</groupId>
<artifactId>pai-ibms-news-zyxf</artifactId>
<name>pai-ibms-news-zyxf</name>
<description>pai-ibms-news-zyxf for pai</description>
<version>1.0</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.build.locales>zh_CN</project.build.locales>
<java.version>1.8</java.version>
<project.build.jdk>${java.version}</project.build.jdk>
<iot-ibms-protocol.version>1.1-SNAPSHOT</iot-ibms-protocol.version>
</properties>
<dependencies>
<!-- 编解码对接协议包 -->
<dependency>
<groupId>cn.flyrise.pai</groupId>
<artifactId>pai-iot-ibms-protocol</artifactId>
<version>${iot-ibms-protocol.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>${project.build.jdk}</source>
<target>${project.build.jdk}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>
步骤二:编解码器工程结构
XxxProtocolCodec编解码协议
XxxProtocolRegister注册文件
步骤三:编解码协议实现
- 1.实现
ProtocolCodec
接口
public class XxxHttpProtocolCodec implements ProtocolCodec {
}
- 2.定义协议类型
@Override
public String getTransport() {
return DefaultTransport.HTTP.getCode();
}
- 3.实现解码方法(上行)
/**
* 解码
* 上行数据直接转化为标准数据结构
* @param decoderCodecContext
* @return
*/
@Override
public ReplyMessage decoder(DecoderCodecContext decoderCodecContext) {
// 上下文中获取需解析数据格式类型
ReplyMessage replyMessage = decoderCodecContext.getReplyMessage();
// 上下文中的原始数据转为HttpPayload格式
HttpPayload httpPayload = (HttpPayload)decoderCodecContext.getPayload();
// 上行文中获取协议配置参数信息
JSONObject param = decoderCodecContext.getCodecMetadataParam();
// 根据上下文中需解析的数据格式类型进行解析
if(replyMessage instanceof DeviceReplyMessage){
// 如果是标准设备数据格式则直接转换
DeviceMetadata deviceMetadata = JSONUtil.toBean(JSONUtil.parseObj(httpPayload.getPayload()), DeviceMetadata.class);
// 设备ID是否需要增加前缀进行区分
deviceMetadata.setId(ProtocolUtil.setPrefix(param,deviceMetadata.getId()));
// 返回解码结果
return ((DeviceReplyMessage) replyMessage).addDeviceMetadata(deviceMetadata);
}else if(replyMessage instanceof EventReplyMessage){
// 如果是标准告警数据格式则直接转换
EventMetadata eventMetadata = JSONUtil.toBean(JSONUtil.parseObj(httpPayload.getPayload()), EventMetadata.class);
// 告警ID是否需要增加前缀进行区分
eventMetadata.setId(ProtocolUtil.setPrefix(param,eventMetadata.getId()));
// 设备ID是否需要增加前缀进行区分
eventMetadata.setDeviceId(ProtocolUtil.setPrefix(param,eventMetadata.getDeviceId()));
// 返回解码结果
return ((EventReplyMessage) replyMessage).addEventMetadata(eventMetadata);
}else if(replyMessage instanceof FuncReplyMessage){
// 如果是标准功能操作数据格式则直接转换
FuncReplyMessage funcReplyMessage = JSONUtil.toBean(JSONUtil.parseObj(httpPayload.getPayload()), FuncReplyMessage.class);
// 设备ID是否需要增加前缀进行区分
funcReplyMessage.setDeviceId(ProtocolUtil.setPrefix(param,funcReplyMessage.getDeviceId()));
// 返回解码结果
return funcReplyMessage;
}else {
// 其他来源,不处理直接返回
}
return replyMessage;
}
- 4.实现编码方法(下行)
/**
* 编码
* 标准数据结构直接转化未下行指令
* @param encoderCodecContext
* @param encoderCallback
* @return
*/
@Override
public Issue encode(EncoderCodecContext encoderCodecContext, EncoderCallback encoderCallback) {
// 上下文中获取功能操作信息
FuncReplyMessage funcReplyMessage = encoderCodecContext.getFuncReplyMessage();
// 上行文中获取协议配置参数信息
JSONObject param = encoderCodecContext.getCodecMetadataParam();
// 实现HTTP协议模式下的默认功能
if(SubsystemFunc.GET_DEVICE_LIST.match(funcReplyMessage.getFunc())){
// 根据第三方接口文档,以及上下文中的协议配置参数,实现第三方接口调用,完成设备列表获取请求,并进行解析 待续....
// 获取设备列表并返回设备列表,使用回调函数进行推送 encoderCallback.reply(new DeviceReplyMessage())
encoderCallback.reply(encoderCodecContext,new DeviceReplyMessage());
funcReplyMessage.setRes("返回设备列表");
// 功能状态
funcReplyMessage.setState(FuncStatusType.TO_BE_RETURNED.getCode());
}else if (SubsystemFunc.GET_DEVICE_INFO.match(funcReplyMessage.getFunc())){
// 根据第三方接口文档,以及上下文中的协议配置参数,实现第三方接口调用,完成设备信息获取请求,并进行解析 待续....
// 获取设备信息并返回设备列表,使用回调函数进行推送 encoderCallback.reply(new DeviceReplyMessage())
funcReplyMessage.setRes("返回设备信息");
// 功能状态
funcReplyMessage.setState(FuncStatusType.TO_BE_RETURNED.getCode());
}else if (SubsystemFunc.GET_EVENT_LIST.match(funcReplyMessage.getFunc())){
// 根据第三方接口文档,以及上下文中的协议配置参数,实现第三方接口调用,完成告警列表获取请求,并进行解析 待续....
// 获取告警列表并返回告警列表,使用回调函数进行推送 encoderCallback.reply(new EventReplyMessage())
funcReplyMessage.setRes("返回获取告警列表");
// 功能状态
funcReplyMessage.setState(FuncStatusType.TO_BE_RETURNED.getCode());
}else if (SubsystemFunc.PLATFORM_URL.match(funcReplyMessage.getFunc())){
// 根据第三方接口文档,以及上下文中的协议配置参数,实现第三方接口调用,完成第三方平台单点登录地址获取,并进行解析 待续....
// 获取单点登录地址
funcReplyMessage.setRes("返回第三方平台跳转地址");
// 功能状态
funcReplyMessage.setState(FuncStatusType.TO_BE_RETURNED.getCode());
}else if (SubsystemFunc.VIDEO_STREAM_URL.match(funcReplyMessage.getFunc())){
// 根据第三方接口文档,以及上下文中的协议配置参数,实现第三方接口调用,完成HLS视频流地址获取请求,并进行解析 待续....
// 获取视频流地址支持HLS协议
funcReplyMessage.setRes("返回HLS视频流地址");
// 功能状态
funcReplyMessage.setState(FuncStatusType.TO_BE_RETURNED.getCode());
}else{
// 其他扩展功能操作在此进行延续...
funcReplyMessage.setRes("返回扩展功能操作结果");
// 功能状态
funcReplyMessage.setState(FuncStatusType.TO_BE_RETURNED.getCode());
}
return new HttpIssue(funcReplyMessage);
}
步骤四:注册文件实现
- 1.实现
ProtocolRegister
接口
public class XxxProtocolRegister implements ProtocolRegister {
}
- 2.定义编解码协议配置
/**
* HTTP 配置信息
*/
private static final CodecMetadata httpConfig = new CodecMetadata(DefaultTransport.HTTP.getCode(),"HTTP配置", "Xxx系统接入协议 v1.0.3")
// 协议所需参数配置
.addProperty("username","账号","认证账号")
.addProperty("password","密码","认证密码")
.addProperty("serverUrl","服务地址","服务地址")
// 协议数据唯一表示前缀配置
.addProperty(SubsystemConstants.CODE_PREFIX, SubsystemConstants.CODE_PREFIX, "唯一标识前缀",false)
// 协议编码下行功能操作说明
.addFuncProperty(SubsystemFunc.GET_DEVICE_LIST.getCode(),SubsystemFunc.GET_DEVICE_LIST.getDesc(),"获取设备列表","无参数");
/**
* MQTT 配置信息
*/
private static final CodecMetadata mqttConfig = new CodecMetadata(DefaultTransport.MQTT.getCode(),"mqtt配置", "Xxx系统接入协议 v1.0.3")
.addProperty("username","账号","认证账号")
.addProperty("password","密码","认证密码")
.addProperty("serverUrl","服务地址","服务地址")
.addProperty(SubsystemConstants.CODE_PREFIX, SubsystemConstants.CODE_PREFIX, "唯一标识前缀",false);
- 3.编解码协议注册
@Override
public ProtocolContainer register() {
ProtocolContainer protocolRegister = new ProtocolContainer("XxxProtocolRegister","Xxx平台适配协议","大华平台支持HTTP和MQTT");
// HTTP 注册
{
protocolRegister.addCodecMetadata(httpConfig)
.addProtocolCodec(new XxxHttpProtocolCodec());
}
// MQTT 注册
{
protocolRegister.addCodecMetadata(httpConfig)
.addProtocolCodec(new XxxMqttProtocolCodec());
}
return protocolRegister;
}
步骤五:打包jar
打包,maven先点clean,然后点package
然后工程目录下的target文件下会有一个jar包
步骤六:南向平台注册
- 登录南向平台创建页面,上传jar包
注册文件地址就是register的项目目录下地址,jar包是刚打包的jar包
- 点击启用,配置,写入平台地址
这里如果在写register类的http配置时未留平台地址而选择将地址写在代码中,则不需要配置适配器参数。
创建后北向授权会自动创建一条记录
- 点击启用,然后点击认证刷新获取secureKey
然后就可以使用了。一般设备列表获取会在定时任务内自动获取,这里调用南向功能平台接口进行测试。
定时任务
配置子系统数据采集任务
点位编排
- 1.图标管理
- 2.面板管理
- 3.点位编排
- 4.物联地图
工单服务
- 流程定义(目前仅支持”告警流程”一种流程分类)
- 业务表单
业务表单数据格式
{
alarmId:'告警标识',
eventType:'告警类型',
eventName:'告警名称',
eventTime:'告警时间',
deviceNo:'设备编号',
deviceName:'设备名称',
description:'告警详情',
xxx:'其他,根据告警信息设置',
}
告警信息数据格式
/**
* 设备名
*/
@ApiModelProperty(value = "设备名" )
@Size(max = 50)
@InvalidCode(value = "5001", message = "{invalid.code.5001}", desc = "设备名")
private String deviceName;
/**
* 设备编号
*/
@ApiModelProperty(value = "设备编号" )
@Size(max = 50)
@InvalidCode(value = "5002", message = "{invalid.code.5002}", desc = "设备编号")
private String deviceNo;
/**
* 设备类型
*/
@ApiModelProperty(value = "设备类型" )
@Size(max = 50)
@InvalidCode(value = "5003", message = "{invalid.code.5003}", desc = "设备类型")
private String deviceType;
/**
* 位置
*/
@ApiModelProperty(value = "位置" )
@Size(max = 50)
@InvalidCode(value = "5004", message = "{invalid.code.5004}", desc = "位置")
private String location;
/**
* 位置
*/
@ApiModelProperty(value = "位置id" )
@Size(max = 50)
@InvalidCode(value = "5015", message = "{invalid.code.5015}", desc = "位置")
private String locationId;
/**
* 上报时间
*/
@ApiModelProperty(value = "上报时间" )
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date reportingTime;
/**
* 处理完成时间
*/
@ApiModelProperty(value = "处理完成时间" )
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date completionTime;
/**
* 说明
*/
@ApiModelProperty(value = "说明" )
@Size(max = 65535)
@InvalidCode(value = "5008", message = "{invalid.code.5008}", desc = "说明")
private String description;
/**
* 租户ID
*/
@ApiModelProperty(value = "租户ID" )
@Size(max = 32)
@InvalidCode(value = "5009", message = "{invalid.code.5009}", desc = "租户ID")
private String tenantId;
/**
* 园区ID
*/
@ApiModelProperty(value = "园区ID" )
@Size(max = 32)
@InvalidCode(value = "5010", message = "{invalid.code.5010}", desc = "园区ID")
private String parkId;
/**
* 状态
*/
@ApiModelProperty(value = "状态" )
@Digits(integer = 10, fraction = 0)
@InvalidCode(value = "5012", message = "{invalid.code.5012}", desc = "状态")
private Integer status;
/**
* 创建人
*/
@ApiModelProperty(value = "创建人" )
@Size(max = 64)
@InvalidCode(value = "5013", message = "{invalid.code.5013}", desc = "创建人")
private String createBy;
/**
* 创建时间
*/
@ApiModelProperty(value = "创建时间" )
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
/**
* 修改人
*/
@ApiModelProperty(value = "修改人" )
@Size(max = 64)
@InvalidCode(value = "5014", message = "{invalid.code.5014}", desc = "修改人")
private String updateBy;
/**
* 修改时间
*/
@ApiModelProperty(value = "修改时间" )
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
private String origin;
private String ibmsId;
消息服务
短信发送
- 申请短信平台,并在系统进行配置
- 配置短信模板(仅支持’设备告警’、’工单派发’两种短信类型)
数据转发(仅支持MQTT)
- 申请或部署MQTT服务,并在系统进行配置
- 配置消息模板,数据转发只需要配置’MQTT发布’模板类型
二开应用
应用中心
根据实际业务需求,定制化开发应用模块
指标数据
根据IOC实际业务所需,定制化开发指标接口
源码开发
数据字典附录
标准数据格式
设备数据格式
{ id:"设备ID", name:"设备名称", state:"设备状态(参照数据字典)", classify:"设备类型(参照数据字典)", collectTime:"时间", location:"位置详情", lon:"经度", lat:"维度", alt:"高度", properties:{ // 附加属性 xxx:'xx值' } }
告警数据格式
{ id:"事件ID", name:"事件名称", deviceId:"设备ID", state:"事件状态(参照数据字典)", type:"事件类型(参照数据字典)", details:"事件详情", createTime:"时间", location:"位置详情", properties:{ // 附加属性 xxx:'xx值' } }
功能操作格式
{ deviceId:"设备ID", func:"功能标识(默认的功能操作参照数据字典)", req:{ // 请求参数 xxx:'xx值' } }
设备状态
/**
* 设备状态
* @author zhangq
* @date 2023-3-13
*/
public enum DeviceStatusType {
ONLINE(0, "正常"),
OFFLINE(1, "离线"),
HITCH(2, "故障"),
DISCARD(3, "废弃"),
NOT_ENABLED(-1, "未启用"),
;
}
设备类型
/**
* 标准设备类型
* @author zhangq
* @date 2023-3-13
*/
public enum DeviceType {
// 安防
DEVICE_CAMERA("CAMERA", "摄像头"),
DEVICE_ENCODER("DEVICE_ENCODER", "编码设备"),
DEVICE_SERVICE("DEVICE_SERVICE", "服务设备"),
DEVICE_ENTRANCE_GUARD("ENTRANCE_GUARD", "门禁"),
DEVICE_BARRIER_GATE("BARRIER_GATE", "道闸"),
// 能耗
DEVICE_ELECTRICITY("ELECTRICITY_METER", "电表"),
DEVICE_THREE_ELECTRICITY("THREE_ELECTRICITY", "三相电表"),
DEVICE_WATER("WATER_METER", "水表"),
DEVICE_GAS("GAS_METER", "燃气表"),
// 动环
DEVICE_WATER_IMMERSION("WATER_IMMERSION", "水浸报警器"),
DEVICE_WATER_GAGE("WATER_GAGE", "水压传感器"),
// 消防
DEVICE_SMOKE("SMOKE_SENSOR", "烟感器"),
DEVICE_FIRE_ENGINE("FIRE_ENGINE", "消防主机"),
DEVICE_ALARM_ENGINE("ALARM_ENGINE", "告警主机"),
// 传感器
DEVICE_TEMP("TEMP_SENSOR", "温度传感器"),
DEVICE_HUMIDITY("HUMIDITY_SENSOR", "湿度传感器"),
DEVICE_TEMP_HUMIDITY("TEMP_HUMIDITY_SENSOR", "温湿度传感器"),
DEVICE_LTH_SENSOR("LTH_SENSOR", "光照温湿度传感器"),
// 边缘计算、网关
DEVICE_GATEWAY("INTEL_GATEWAY", "智能网关"),
// 终端设备
DEVICE_ELECTRIC_RELAY("ELECTRIC_RELAY", "继电器"),
DEVICE_SWITCH("SWITCH", "控制面板"),
// BA
DEVICE_AIR_CONDITION("AIR_CONDITION", "空调"),
DEVICE_LIFT("DEVICE_LIFT", "电梯"),
DEVICE_LAMP("DEVICE_LAMP", "灯"),
DEVICE_WINDOW_OPENER("WINDOW_OPENER", "开窗器"),
// 信息发布
DEVICE_LED_SCREEN("LED_SCREEN", "LED屏"),
// 环境检测
DEVICE_WEATHER_STATION("WEATHER_STATION", "气象站监控仪"),
DEVICE_UNKNOWN("Z_DEVICE_UNKNOWN", "未知设备"),
;
}
告警类型
/**
* 告警事件类型
* @author zhangq
* @date 2023-3-13
*/
public enum EventType {
NORMAL("NORMAL", "正常"),
DEVICE_ALARM("DEVICE_ALARM", "设备告警"),
SERVICE_ALARM("SERVICE_ALARM", "服务告警"),
EXCEED_THRESHOLD("EXCEED_THRESHOLD", "阈值预警"),
FIRE_ALARM("FIRE_ALARM", "消防预警"),
SAFETY_WARN("SAFETY_WARN", "安防预警"),
TYPHOON_WARNING("TYPHOON_WARNING", "台风预警"),
OTHER_ALARM("OTHER_ALARM", "其他"),
;
}
告警状态
/**
* 告警事件状态
* @author zhangq
* @date 2023-3-13
*/
public enum EventStatusType {
PENDING(0, "待处理"),
PROCESSING(1, "处理中"),
PROCESSED(2, "已处理"),
IGNORED(3, "已忽略"),
MY_RESUME(4, "自恢复"),
;
}
功能请求状态
/**
* 功能请求状态
* @author zhangq
* @date 2023-3-13
*/
public enum FuncStatusType {
TO_BE_SENT(0, "待发送"),
TO_BE_SECCESS(1, "发送成功"),
TO_BE_ERROR(1, "发送失败"),
TO_BE_RETURNED(2, "完成"),
TO_BE_TIME_OUT(3, "超时"),
;
}
常见异常
/**
* 业务错误代码定义枚举类
*/
public enum BaseErrors {
//手动指定错误码
ERR_1001("not_supported", "不支持"),
ERR_1002("func_unrealized", "未实现"),
ERR_1003("param_deletion", "参数缺失"),
ERR_1004("param_null", "参数为空"),
ERR_1005("subsystem_service_err", "第三方服务连接异常"),
ERR_1006("authorization_err", "认证授权失败"),
//... 其他错误码的定义
;
}