Appearance
消防管家 OpenAPI 文档 V1.0
1. 概述
本文档目的是方便第三方应用系统对接消防管家,包括但不限于将事件接入到消防管家或者从消防管家订阅事件。
2. 前置条件
向消防管家(简称 IOC 工作台,IOC)申请应用 AK、SK,用来鉴定请求合法性。

2.1 对接前准备工作
- 找交付经理申请应用的 AK、SK:提供第三方系统名称
- 数据接入:第三方系统在边端,和消防管家在同一个局域网内,可通过 HTTP 或 RabbitMQ 方式接入;如果第三方应用在云端,则需要通过云端 RabbitMQ 方式接入,需要提供云端 RabbitMQ 信息
- 数据订阅:如需从消防管家订阅数据,需要提供 HTTP/HTTPS 推送地址或者 RabbitMQ 信息(IP、Port、VirtualHost、User、Password)
数据订阅以 HTTP/HTTPS 订阅的,第三方系统需要对推送请求鉴权,鉴权机制请查阅 OpenAPI 通用鉴权机制
2.2 OpenAPI 通用鉴权机制
请求接口时,携带三个请求头:Authorization、Date、Content-Type
- Authorization:格式为
appkey:sign,将 appKey 和 sign 签名用冒号连接,appkey 为申请应用 AK,sign 为通过下文算法计算出来 - Date:为请求时的时间,格式为:
EEE, dd MMM yyyy HH:mm:ss zzz,如Wed, 19 Nov 2025 02:41:20 GMT - Content-Type:固定为
application/json
注:对于 Content-Type 的值,在请求头中传输的值可能后面会多一个
;charset=utf-8。第三方服务最好将 Content-Type 的值做截取操作,只取;前的字符串,避免校验不通过。
2.2.1 sign 签名算法
拼接字符串:将 HTTP 方法、Content-Type(固定为 application/json)、日期字符串和路径资源按以下格式拼接:
HTTP方法\nContent-Type\n日期字符串\n路径资源HmacSHA1 加密:使用 appSecret 对拼接后的字符串进行 HmacSHA1 加密
Base64 编码:对加密结果进行 Base64 编码
截取签名:从 Base64 编码结果中截取第5位开始的10个字符作为签名
Java 代码参考:详见附录 7.3 附录三:鉴权相关参考代码
3. 名称解释
- 事件:泛指系统或服务中发生的任何状态变化,可能是正常的(如服务重启),也可能是异常的(如服务器宕机)
- 告警:是事件的一种特殊类型,当系统检测到异常(如 CPU 使用率超过阈值)时,会主动发出通知,要求立即处理
本文中的事件通常是指告警。
4. 系统交互图介绍

5. 接口文档
5.1 查询事件类型列表
接口定义和请求方式
- 接口地址:
/api/open/queryIncidentTypeList - 请求方式:POST
请求参数
| 字段 | 名称 | 数据类型 | 备注 |
|---|---|---|---|
| priority | 事件等级 | Integer | 0:提示 1:一般 2:重要 3:紧急 |
| pageSize | 页大小 | Integer | |
| pageNum | 页码 | Integer | |
| scene | 场景 | Integer | 1-报事事件(YQBSFW),2-设备事件(YQSBSS),3-AI事件(AIYJ),4-业务事件(YWSJ),5-消防事件(XFSJ) |
返回参数
| 字段 | 名称 | 数据类型 | 备注 |
|---|---|---|---|
| code | 状态码 | String | 200:成功 |
| isOK | 是否成功 | Boolean | true:成功; false:失败 |
| data | 承载数据 | Object |
data 中包含的对象信息
| 字段 | 名称 | 数据类型 | 备注 |
|---|---|---|---|
| id | 事件类型id | String | 字符串长度为64个字符以下 |
| scene | 场景编码 | Integer | 1-报事事件,2-设备事件,3-AI事件,4-业务事件,5-消防事件 |
| sceneStr | 场景 | String | 场景编码对应的场景名称 |
| originParentCode | 原始父编码 | String | 字符串长度为128个字符以下 |
| originCode | 原始编码 | String | 字符串长度为128个字符以下 |
| parentName | 父名称 | String | 字符串长度为64个字符以下 |
| name | 名称 | String | 字符串长度为64个字符以下 |
| code | 唯一标识 | String | 字符串长度为128个字符以下 |
| businessName | 业务事件类型 | String | 字符串长度为64个字符以下 |
| businessKey | 对应事件类型业务标识 | String | 字符串长度为128个字符以下 |
| thresholdDuration | 分钟 | Integer | |
| thresholdTimes | 次数 | Integer | |
| status | 是否启用 | Integer | 1-是 0-否 |
| autoReport | 是否自动派单标识 | Integer | 1-是 0-否 |
| autoReportStr | 是否自动派单 | String | |
| aiCheck | ai验单标识 | Integer | 0-否,1-是 |
| aiCheckStr | ai验单 | String | |
| dispatchType | 调度类型 | String | workOrder-工单, robot-移动巡检(可多选,多个使用','拼接) |
| autoDistributeTo | 自动派单对象 | String | workOrder-工单, robot-移动巡检 |
| deleted | 是否删除 | Integer | 0-否,1-是 |
| priority | 事件等级标识 | Integer | 0提示 1一般,2重要,3紧急 |
| priorityStr | 事件等级 | String | 事件等级标识对应的名称 |
| createTime | 创建时间 | String | |
| updateTime | 更新时间 | String | |
| voiceScene | 提示声音类型 | Integer | 事件在消防管家上报时,系统的提示音类型 |
| typeOriginCode | 一级事件类型code | String | 字符串长度为64个字符以下 |
| typeParentName | 一级事件类型name | String | 字符串长度为64个字符以下 |
| isWindow | 是否弹窗 | Integer | 1-是 0-否 |
请求示例
(略)
响应报文示例
json
{
"isOk": true,
"msg": null,
"cause": null,
"code": "200",
"data": {
"records": [
{
"id": "-7661345827197248065",
"scene": 3,
"sceneStr": "AI事件",
"originParentCode": "AISB_RYSD",
"originCode": "AISB_RYSD",
"parentName": "AI识别-人员摔倒",
"name": "AI识别-人员摔倒",
"code": "AISB_RYSD",
"businessName": "AI识别-人员摔倒",
"businessKey": "AISB_RYSD",
"thresholdDuration": 0,
"thresholdTimes": 0,
"status": 0,
"autoReport": 0,
"autoReportStr": "否",
"aiCheck": 1,
"aiCheckStr": "是",
"dispatchType": "workOrder",
"autoDistributeTo": "workOrder",
"deleted": 0,
"priority": 2,
"priorityStr": "重要",
"createTime": "2025-11-18 14:36:02",
"updateTime": "2025-11-18 15:23:09",
"voiceScene": 1,
"typeOriginCode": "AISB_RYSD",
"typeParentName": "AI识别-人员摔倒",
"isWindow": 0
}
],
"total": 79,
"size": 10,
"current": 1,
"orders": [],
"optimizeCountSql": true,
"searchCount": true,
"countId": null,
"maxLimit": null,
"pages": 8
}
}5.2 查询事件类型详情
接口定义和请求方式
- 接口地址:
/api/open/queryIncidentTypeDetail - 请求方式:POST
请求参数
| 字段 | 名称 | 数据类型 | 备注 |
|---|---|---|---|
| secondTypeCode | 二级事件编码 | String |
返回参数
与 5.1 返回参数中 data 对象结构一致。
请求示例
json
{
"secondTypeCode": "AISB_RYSD"
}响应报文示例
json
{
"isOk": true,
"msg": null,
"cause": null,
"code": "200",
"data": {
"id": "-7661345827197248065",
"scene": 3,
"sceneStr": "AI事件",
"originParentCode": "AISB_RYSD",
"originCode": "AISB_RYSD",
"parentName": "AI识别-人员摔倒",
"name": "AI识别-人员摔倒",
"code": "AISB_RYSD",
"businessName": "AI识别-人员摔倒",
"businessKey": "AISB_RYSD",
"thresholdDuration": 0,
"thresholdTimes": 0,
"status": 0,
"autoReport": 0,
"autoReportStr": "否",
"aiCheck": 1,
"aiCheckStr": "是",
"dispatchType": "workOrder",
"autoDistributeTo": "workOrder",
"deleted": 0,
"priority": 2,
"priorityStr": "重要",
"createTime": "2025-11-18 14:36:02",
"updateTime": "2025-11-18 15:23:09",
"voiceScene": 1,
"typeOriginCode": "AISB_RYSD",
"typeParentName": "AI识别-人员摔倒",
"isWindow": 0
}
}5.3 分页查询事件列表
接口定义和请求方式
- 接口地址:
/api/open/queryIncidentList - 请求方式:POST
请求参数
| 字段 | 名称 | 数据类型 | 备注 |
|---|---|---|---|
| pageNum | 页码 | Integer | |
| pageSize | 每页数据量 | Integer | |
| code | 事件编号 | String | 字符串长度大概为64个字符以下 |
| typeId | 事件类型等级id | List<String> | |
| incidentType | 事件状态 | String | 0:待处理 1:已结束 2:处理中 |
| startTime | 创建时间(开始) | String | |
| endTime | 创建时间(结束) | String | |
| eventStartTime | 关闭事件(开始) | String | |
| eventEndTime | 关闭时间(结束) | String |
返回参数
| 字段 | 名称 | 数据类型 | 备注 |
|---|---|---|---|
| code | 状态码 | String | |
| isOk | 是否成功 | Boolean | true:成功;false:失败 |
| data | 承载数据 | Object |
data 中包含的对象信息
| 字段 | 名称 | 数据类型 | 备注 |
|---|---|---|---|
| current | 当前页码 | Integer | |
| size | 当前页码数据量 | Integer | |
| pages | 页码总数 | Integer | |
| total | 数据量总数 | Integer | |
| records | 数据详情 | List<IncidentDto> |
IncidentDto 中包含的事件字段
| 字段 | 名称 | 数据类型 | 备注 |
|---|---|---|---|
| code | 事件编号 | String | 字符串长度在64个字符以下 |
| originIncidentCode | 第三方事件编号 | String | |
| name | 事件名称 | String | |
| range | 项目 | String | |
| position | 位置 | String | |
| typeKey | 事件类型 | String | 事件对应的二级事件编码,字符串长度在128个字符以下 |
| typeName | 事件类型名称 | String | 字符串长度在64个字符以下 |
| incidentType | 事件状态 | String | "0"--待处理;"1"--已结束;"2"--处理中 |
| createTime | 创建时间 | String | |
| eventEndTime | 关闭时间 | String | |
| alarmDuration | 持续时间 | String | 已换算成X天X小时X分X秒 |
请求示例
json
{
"id": "",
"code": "",
"typeId": ["1980462046801563649"],
"incidentType": 1,
"queryType": 1,
"pageNum": 1,
"pageSize": 15,
"startTime": "2025-12-03 00:00:00",
"endTime": "2025-12-05 23:59:59",
"eventStartTime": "",
"eventEndTime": ""
}响应报文示例
(略,详见原文档)
5.4 查询事件详情
接口定义和请求方式
- 接口地址:
/api/open/queryIncidentDetail - 请求方式:POST
请求参数
| 字段 | 名称 | 数据类型 | 备注 |
|---|---|---|---|
| id | 事件id | String |
请求示例
json
{
"id": "1995297557426274304"
}返回参数
| 字段 | 名称 | 数据类型 | 备注 |
|---|---|---|---|
| incidentDetail | 事件详情信息 | Object | |
| logOperationList | 调度记录 | List<LogOperationDto> | |
| records | 事件备注 | List<TempRecordModel> |
incidentDetail 包含字段
| 字段 | 名称 | 数据类型 | 备注 |
|---|---|---|---|
| id | 事件id | String | |
| name | 事件名称 | String | |
| description | 事件描述 | String | |
| source | 事件来源 | String | |
| deviceName | 报事设备名称 | String | |
| position | 位置 | String | |
| createTime | 上报时间 | String | |
| pictureUrl | 图片 | String | JSON数组格式字符串 |
LogOperationDto 包含字段
| 字段 | 名称 | 数据类型 | 备注 |
|---|---|---|---|
| eventId | 事件编号 | String | |
| workOrderNo | 工单编号 | String | |
| eventStatus | 事件状态 | String | |
| eventName | 事件名称 | String | |
| eventClosed | 工单是否关闭 | Boolean | true:关闭;false:未关闭 |
| eventHandler | 工单处理人 | String | |
| eventHandlerMobile | 工单处理人手机号 | String | |
| eventTime | 工单处理时间 | String | |
| eventType | 事件类型 | String | 事件sj 任务rw |
| etlCode | 唯一编号 | String | 来源-工单编号-项目编号 |
| source | 来源 | String | |
| content | 节点描述 | String | |
| sipCode | sip号 | String | |
| online | 是否在线 | String | 0:不在线;1:在线 |
| reasonOption | AI事件关闭-原因选项 | String | 风险已解除;识别错误 |
| reasonDescription | AI事件关闭-原因手动输入的描述 | String | |
| robotId | 机器人id | String | |
| robotCameraId | 机器人绑定摄像头id | String |
TempRecordModel 包含字段
| 字段 | 名称 | 数据类型 | 备注 |
|---|---|---|---|
| id | 事件id | String | |
| content | 内容 | String | |
| operator | 操作人 | String | |
| phone | 操作人手机号 | String | |
| createTime | 创建时间 | String |
6. 事件订阅
6.1 增量事件订阅
实时推送事件,事件状态变化,都进行事件推送。包括待处理,进行中,关闭三种状态。
支持 HTTP 和 RabbitMQ 方式推送,需要应用方提供 HTTP 接口地址或 RabbitMQ 配置信息。
RabbitMQ 方式订阅:RabbitMQ 的配置规则参考 7.2 附录二:RabbitMQ配置相关规则
HTTP 方式订阅
- HTTP 接口地址:第三方应用提供
- 请求方式:POST
- 请求参数:无
返回参数
| 字段 | 名称 | 数据类型 | 备注 |
|---|---|---|---|
| objectType | 订阅类型 | String | 1-事件;此处固定为1 |
| dataType | 数据类型 | String | 1-增量数据;2-全量数据 |
| data | 数据详情 | List<Object> | 增量事件订阅时此处列表为1个元素 |
data 中包含的对象信息
| 字段 | 名称 | 数据类型 | 备注 |
|---|---|---|---|
| code | 事件编码 | String | 长度不超过64个字符 |
| name | 事件名称 | String | 长度不超过32个字符 |
| originIncidentCode | 第三方事件编码 | String | 长度不超过64个字符 |
| projectCode | 项目编码 | String | 长度不超过32个字符 |
| projectName | 项目名称 | String | 长度不超过32个字符 |
| position | 位置 | String | |
| pictureUrl | 事件图片 | String | 图片url地址 |
| typeKey | 事件类型(二级事件编码) | String | 长度不超过64个字符 |
| typeName | 事件类型名称(二级事件名称) | String | 长度不超过32个字符 |
| incidentType | 事件状态 | String | 0:待处理 1:已完成 2:处理中 |
| createTime | 事件创建时间 | String | |
| eventEndTime | 事件关闭时间 | String | |
| alarmDuration | 事件持续时间 | String | 已换算成X天X小时X分钟X秒 |
| alarmDurationLong | 事件持续时间 | Long | 单位:秒 |
| deviceId | 报事设备编码 | String | 长度不超过64个字符 |
| deviceName | 报事设备名称 | String | 长度不超过32个字符 |
| thirdCode | 第三方设备编码 | String | 长度不超过64个字符 |
| thirdName | 第三方设备名称 | String | 长度不超过64个字符 |
| workOrderCode | 工单编码 | String | 长度不超过64个字符 |
| cameraIdList | 关联摄像头编码 | List<String> |
请求示例
响应报文示例:
json
{
"objectType": "1",
"dataType": "1",
"data": [
{
"code": "20251106AIYJ000527",
"originIncidentCode": "738093083545669",
"name": "周界入侵",
"projectCode": "P0000",
"projectName": "测试项目",
"position": "测试位置",
"pictureUrl": "[\"https://spfile-uat.icloudcity.com/spioc/202511/18818ffed6116b378/1430a7687bbad2b98cd.jpg\"]",
"typeKey": "AIYJ_XQZJRQ",
"typeName": "周界入侵",
"incidentType": "1",
"createTime": "2025-11-06 10:11:00",
"eventEndTime": "2025-11-06 10:13:16",
"alarmDuration": "0天00小时2分钟16秒",
"alarmDurationLong": 136,
"deviceId": "IOTPR00001124200",
"deviceName": "A-TEST-ANGG-2001",
"thirdCode": "7321429522836889600",
"thirdName": "A-TEST-ANGG-2001"
}
]
}7. 附录
7.1 附录一:二级事件类型编码和名称对应关系
AI 事件类型以及编码
| 二级事件类型名称 | 二级事件类型编码 |
|---|---|
| 周界入侵 | AIYJ_XQZJRQ |
| 机动车违停 | AIYJ_JDCWT |
| 车辆拥堵 | AIYJ_JDCDS |
| 消防通道占用 | AIYJ_XFTDDFZW |
| 人员拥堵 | AIYJ_CRKYD |
| 垃圾桶满溢 | AIYJ_LJTMY |
| 桶边垃圾 | AIYJ_TBLJ |
| 公共区域垃圾 | AIYJ_GGQYLJ |
| 员工离岗 | AIYJ_YGLG |
| 人员翻越 | AIYJ_RYFY |
| 室内明火检测 | AIYJ_SNMHJC |
| 烟雾检测 | AIYJ_YWJC |
| 专用车位占用 | AIYJ_ZYCWZY |
| 消防设备异常 | AIYJ_MHQQS |
| 抽烟识别 | AIYJ_CYSB |
| 人员摔倒 | AIYJ_RYSD |
| 人员逗留 | AIYJ_RYDL |
| 非机动车违停 | AIYJ_FJDCWT |
| 机动车滞留 | AIYJ_JDCZL |
| 玩手机识别 | AIYJ_WSJSB |
| 横幅识别 | AIYJ_HFSB |
| 散落垃圾 | AIYJ_SLLJ |
7.2 附录二:RabbitMQ 配置相关规则
事件订阅和事件类型订阅
RabbitMQ 配置规则建议:
- exchange 类型:Topic 类型
- exchange 命名规则:
ioc_{appId} - routingkey 命名规则:
ioc_incident_out.${projectCode} - queue 命名规则建议:
ioc_incident_queue_out_${appId}.${projectCode}
注:对于 queue 的命名可根据实际情况是否需要拼接项目编码,由第三方系统自己创建,并绑定 exchange。
7.3 附录三:鉴权相关参考代码
Java 代码参考
java
package com.onewo.openapi.auth;
import com.onewo.spsms.management.util.OkHttpUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.util.StringUtils;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Base64;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
/**
* @author yangming
*/
@Slf4j
public class OpenApiClientAuth {
protected OpenApiClientAuth() {
}
public static final String AUTHORIZATION = "Authorization";
public static final String CONTENT_TYPE = "Content-Type";
public static final String DATE = "Date";
public static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter
.ofPattern("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.ENGLISH);
/**
* @param httpMethod 请求方式 GET,POST,PUT。。。
* @param url http://baidu.com/xxx/xx?aa=11
* @param appKey 123123
* @param appSecret sdfdsf
* @param contentType 请求类型
* @return 返回授权说需要的Header参数
*/
@SneakyThrows
public static Map<String, String> getSignHeaders(final String httpMethod, final String url,
final String appKey, final String appSecret,
final String contentType) {
final String pathResource = OpenApiClientAuth.getPathResource(url);
final String contentTypeValue = contentType != null ? contentType : "application/json";
final String dateValue = DATE_TIME_FORMATTER.format(ZonedDateTime.now(ZoneId.of("GMT")));
final String sign = OpenApiClientAuth
.calculateSing(httpMethod, contentTypeValue, dateValue, pathResource, appSecret);
final String authorizationString = appKey + ":" + sign;
final Map<String, String> authHeaders = new HashMap<>(4);
authHeaders.put(OpenApiClientAuth.DATE, dateValue);
authHeaders.put(OpenApiClientAuth.AUTHORIZATION, authorizationString);
authHeaders.put(OpenApiClientAuth.CONTENT_TYPE, contentTypeValue);
return authHeaders;
}
protected static String getPathResource(final String url) {
final String substring = url.substring(url.indexOf("://") + 3);
return substring.substring(substring.indexOf("/"));
}
protected static String calculateSing(final String httpMethodString,
final String contentTypeValue, final String dateValue, final String pathResource,
final String appSecret) throws InvalidKeyException, NoSuchAlgorithmException {
final String signToString = OpenApiClientAuth
.builderStringToSign(httpMethodString, contentTypeValue, dateValue, pathResource);
final String base64HashString = HMAC.hmacSha1Encrypt(signToString, appSecret);
final String sign = base64HashString.substring(5, 15);
return sign;
}
protected static String builderStringToSign(final String method,
final String contentTypeValue, final String dateValue, final String pathResource) {
return method
+ "\n"
+ OpenApiClientAuth.handleNullString(contentTypeValue)
+ "\n"
+ OpenApiClientAuth.handleNullString(dateValue)
+ "\n"
+ pathResource;
}
protected static String handleNullString(final String str) {
return !StringUtils.hasText(str) ? "" : str;
}
protected static class HMAC {
private HMAC() {
}
private static final String KEY_MAC_SHA1 = "HmacSHA1";
public static String hmacSha1Encrypt(final String encryptText, final String encryptKey)
throws NoSuchAlgorithmException, InvalidKeyException {
final byte[] text = encryptText.getBytes(StandardCharsets.UTF_8);
final byte[] keyData = encryptKey.getBytes(StandardCharsets.UTF_8);
final SecretKeySpec secretKey = new SecretKeySpec(keyData, HMAC.KEY_MAC_SHA1);
final Mac mac = Mac.getInstance(secretKey.getAlgorithm());
mac.init(secretKey);
return new String(Base64.getEncoder().encode(mac.doFinal(text)),
StandardCharsets.UTF_8);
}
}
/**
* get请求
*/
public static String openApiClientGet(String url, String body, String clientId, String clientSecret) {
Map<String, String> signHeaders = getSignHeaders(HttpMethod.GET.toString(), url, clientId, clientSecret, MediaType.APPLICATION_JSON_VALUE);
return OkHttpUtil.get(url, signHeaders, String.class);
}
/**
* post请求
*/
public static String openApiClientPost(String url, String body, String clientId, String clientSecret) {
Map<String, String> signHeaders = getSignHeaders(HttpMethod.POST.toString(), url, clientId, clientSecret, MediaType.APPLICATION_JSON_VALUE);
return OkHttpUtil.post(url, body, signHeaders, String.class);
}
}请求示例
java
public static void main(String[] args) {
String getUrl = "http://替换为实际的IP:30692/api/open/testGet?queryParam=GET参数";
String postUrl = "http://替换为实际的IP:30692/api/open/testPost";
String appkey = "替换为实际的appKey";
String appSecret = "替换为实际的appSecret";
// 无body示例
String result1 = OpenApiClientAuth.openApiClientGet(getUrl, null, appkey, appSecret);
log.info("OpenApi-test GET:{}", result1);
String result2 = OpenApiClientAuth.openApiClientPost(postUrl, "{\"name\":\"POST参数\"}", appkey, appSecret);
log.info("OpenApi-test POST:{}", result2);
}