Appearance
能源管家OpenAPI文档 v1.0
1. 概述
由第三方使用HTTP形式进行数据对接、获取能源管家系统相关信息。
2. 前置准备/步骤
2.1 申请clientId和clientSecret
- 线下找对接人申请clientId和clientSecret(对clientId和clientSecret信息进行保密,不要随意泄漏)
clientId:应用的唯一标识。clientSecret:clientId对应的密钥,访问用户资源时用来验证应用的合法性。
2.2 申请请求域名
- 具体环境域名线下找对接人提供
- 请求域名:
https://xxx - 接口请求示例如:查询计量设备读数
https://xxx/api/open/energy-manager-service/openApi/queryDeviceReading - 所有接口需通过clientId和clientSecret获取鉴权
3. 系统交互图
3.1 http请求交互图

4. 接口鉴权算法及请求示例
4.1 获取签名逻辑
- 对需要保护的数据进行拼接
- 拼接方式:
http请求方法+ "\n" +contentType+ "\n" +日期格式字符串+ "\n" +请求资源uri
- 拼接方式:
- 对拼接好的字符串和
clientSecret进行HmacSHA1加密,并对加密结果进行base64编码 - 截取base64编码后的第5位开始的后续10个字符作为签名
4.2 获取签名示例
签名数据
| 项目 | 值 |
|---|---|
| clientId | f3u5rgcjztb50jk5 |
| clientSecret | xtmrzck6q71rytdncigbnqwit685zij0gpk3lm6zyj54wcu |
| http请求方法 | POST |
| contentType | application/json |
| 日期格式 | RFC1123规范,例如:"EEE, dd MMM yyyy HH:mm:ss zzz" |
| 请求的接口 | https://xx/api/open/energy-manager-service/openApi/test |
签名过程
拼接后的字符串:
POST application/json; charset=UTF-8 Sun, 04 Jan 2026 02:29:03 GMT /api/open/energy-manager-service/openApi/test进行HmacSHA1加密和base64加密结果:
X4CMXyE2MHS9zlmwEpoSL9PKJk4=截取base64加密后的第5位开始的后续10个字符作为签名:
yE2MHS9zlm
最终http请求头需携带的信息
Authorization = clientId:sign
Date = EEE, dd MMM yyyy HH:mm:ss zzz
Content-Type = application/json请求示例
- 方法:POST
- URL:
https://spup-uat.icloudcity.com/api/open/energy-manager-service/openApi/test
返回内容样式:
json
{
"code": 200,
"success": true,
"data": "成功执行了测试开放接口",
"msg": "操作成功"
}4.3 Java示例代码
见附录【6.3 Java签名示例代码】
5. 接口正文
5.1 批量查询计量设备读数
请求方式:POST
请求路径:/api/open/energy-manager-service/openApi/meterReadingBatch
请求参数:
| 参数 | 参数含义 | 类型 | 长度 | 是否必填 | 说明 |
|---|---|---|---|---|---|
| projectCode | 项目编码 | String | 必填 | ||
| deviceType | 设备类型 | String | 必填 | 见6.1设备分类 | |
| deviceNumList | 设备编码 | List<string> | 200 | 必填 | ["MA-CC-SW-QE-FF", "YY-TT-RR-WW"] |
| date | 日期 | String | 必填 | 样式:2025-12-11 |
返回参数:
| 参数 | 参数含义 | 数据类型 | 说明 |
|---|---|---|---|
| code | 标识是否操作成功 | String | 200:显示成功 |
| success | boolean | true | |
| msg | 描述 | String | |
| data | 返回数据 | Object |
返回参数示例:
json
{
"code": 200,
"success": true,
"data": {
"projectCode": "P0015",
"deviceType": "01000",
"date": "2026-01-11",
"devReadList": [
{
"did": "7309853130898821120",
"deviceNum": "D4AD2053FB7B_10",
"deviceName": "L36 空调多联机[1-36KAP1]",
"deviceStatus": "1",
"currentRead": "6672.00",
"identifier": "EPI",
"reportTime": "2026-01-11 23:40:00",
"desc": "存在"
},
{
"did": "7309853128021528576",
"deviceNum": "D4AD2053FB7B_05",
"deviceName": "L14-18 住户用电[1-14-18AW]",
"deviceStatus": "1",
"currentRead": "521808.80",
"identifier": "EPI",
"reportTime": "2026-01-11 23:40:00",
"desc": "存在"
}
]
},
"msg": "操作成功"
}5.2 设备台账
请求方式:POST
请求路径:/api/open/energy-manager-service/openApi/meter
请求参数:
| 参数 | 参数含义 | 类型 | 长度 | 是否必填 | 说明 |
|---|---|---|---|---|---|
| projectCode | 项目编码 | String | 必填 | ||
| deviceType | 设备类型 | String | 必填 | 见6.1设备分类 | |
| pageNum | 页码 | int | 否 | 默认第一页 | |
| pageSize | 每页条数 | int | 否 | 默认10条,最大支持200条 |
返回参数:
| 参数 | 参数含义 | 数据类型 | 说明 |
|---|---|---|---|
| code | 标识是否操作成功 | String | 200:显示成功 |
| success | boolean | true | |
| msg | 描述 | String | |
| data | 返回数据 | Object | |
| records | 数据内容 | Object | |
| projectCode | 项目code编码 | String | |
| deviceType | 设备类型 | String | 见6.1设备分类 |
| deviceNum | 设备编码 | String | |
| deviceName | 设备名称 | String | |
| deviceStatus | 设备状态 | String | 见6.2设备状态分类 |
| total | 总条数 | int | |
| size | 数量 | int | |
| current | 当前页 | int | |
| pages | 分页数量 | int |
返回参数示例:
json
{
"code": 200,
"success": true,
"data": {
"records": [
{
"projectCode": "P0015",
"deviceType": "01000",
"deviceName": "1号变压器进线柜",
"deviceNum": "D4AD2053FB7B_02",
"deviceStatus": "1"
}
],
"total": 119,
"size": 1,
"current": 30,
"pages": 119
},
"msg": "操作成功"
}5.3 设备用量数据查询
请求方式:POST
请求路径:/api/open/energy-manager-service/openApi/queryEnergyData
请求参数:
| 参数 | 参数含义 | 类型 | 长度 | 是否必填 | 说明 |
|---|---|---|---|---|---|
| projectCode | 项目编码 | String | 必填 | ||
| deviceType | 设备类型 | String | 必填 | 见6.1设备分类 | |
| deviceNumList | 设备编码 | List<string> | 50 | 必填 | ["MA-CC-SW-QE-FF", "YY-TT-RR-WW"] |
| dateType | 时间类型 | String | 必填 | 日:day, 月:month, 年:year | |
| date | 时间 | String | 必填 | 日:yyyy-MM-dd, 月:yyyy-MM, 年:yyyy |
返回参数:
| 参数 | 参数含义 | 数据类型 | 说明 |
|---|---|---|---|
| code | 标识是否操作成功 | String | 200:显示成功 |
| success | boolean | true | |
| msg | 描述 | String | |
| data | 返回数据 | Object | |
| projectCode | 项目code编码 | String | |
| deviceType | 设备类型 | String | 见6.1设备分类 |
| deviceNum | 设备编码 | String | |
| deviceName | 设备名称 | String | |
| deviceStatus | 设备状态 | String | 见6.2设备状态分类 |
| usageDetails | 用量明细 | Object | |
| date | 具体的时间 | String | 传year会返回yyyy-MM,月会返回yyyy-MM-dd,日会返回yyyy-MM-dd |
| time | 详细的时间范围 | String | 传year:time为月份,传month:time为某一天,传day:time为某小时 |
| used | 用能量 | String |
返回参数示例:
json
{
"code": 200,
"success": true,
"data": {
"projectCode": "P0015",
"deviceType": "01000",
"did": "7309853126712905728",
"deviceNum": "D4AD2053FB7B_02",
"deviceName": "1号变压器进线柜",
"deviceStatus": "1",
"usageDetails": [
{
"did": "7309853126712905728",
"deviceNum": "D4AD2053FB7B_02",
"date": "2026-01",
"time": "01",
"used": "704.00"
}
]
},
"msg": "操作成功"
}6. 附录
6.1 设备分类
| 编码 | 描述 |
|---|---|
| 01000 | 电表 |
| 02000 | 水表 |
| 03000 | 燃气 |
| 04000 | 供热 |
| 05000 | 供冷 |
| 06000 | 压缩空气 |
| 07000 | 氮气 |
6.2 设备状态分类
| 编码 | 描述 |
|---|---|
| 1 | 在线 |
| 2 | 离线 |
| 0 | 未激活 |
6.3 Java签名示例代码
java
import java.nio.charset.StandardCharsets;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.entity.ContentType;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;
@Slf4j
public class OpenApiClientAuth {
private OpenApiClientAuth() {
}
private static final String DATE = "Date";
private static final String KEY_MAC_SHA1 = "HmacSHA1";
private static final String CONTENT_TYPE = "Content-Type";
private static final String AUTHORIZATION = "Authorization";
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.ENGLISH);
private static Map<String, String> getSignHeaders(final String httpMethod, final String url, final String clientId, final String clientSecret, final String contentType) throws Exception {
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, clientSecret);
final Map<String, String> authHeaders = new HashMap<>(4);
authHeaders.put(OpenApiClientAuth.DATE, dateValue);
authHeaders.put(OpenApiClientAuth.AUTHORIZATION, clientId + ": " + sign);
authHeaders.put(OpenApiClientAuth.CONTENT_TYPE, contentTypeValue);
return authHeaders;
}
private static String getPathResource(final String url) {
final String substring = url.substring(url.indexOf("/") + 3);
return substring.substring(substring.indexOf('/'));
}
private static String calculateSing(final String httpMethodString, final String contentTypeValue, final String dateValue, final String pathResource, final String appSecret) throws Exception {
final String signToString = OpenApiClientAuth.builderStringToSign(httpMethodString, contentTypeValue, dateValue, pathResource);
final String base64HashString = hmacSha1Encrypt(signToString, appSecret);
return base64HashString.substring(5, 15);
}
private 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;
}
private static String handleNullString(final String str) {
return !StringUtils.hasText(str) ? "" : str;
}
private static String hmacSha1Encrypt(final String encryptText, final String encryptKey) throws Exception {
final byte[] text = encryptText.getBytes(StandardCharsets.UTF_8);
final byte[] keyData = encryptKey.getBytes(StandardCharsets.UTF_8);
final SecretKeySpec secretKey = new SecretKeySpec(keyData, 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);
}
/**
* @param url 请求地址
*/
public static String openApiClientExecute(String url, String body, HttpMethod httpMethod, String clientId, String clientSecret) {
// 方法实现...
return null;
}
public static void main(String[] args) {
String clientId = "yh5zmklapb0ehka0";
String clientSecret = "cb9wt3osfum3gsle37trp4lrjk1kkq4ywcgeeg7b9e602qe";
String postUrl = "https://spup-uat.icloudcity.com/api/open/smartpark-equipment/openApi/test";
JSONObject body = new JSONObject();
body.put("projectCode", "项目编码");
body.put("equipmentName", "设备名称");
String s2 = openApiClientExecute(postUrl, body.toJSONString(), HttpMethod.POST, clientId, clientSecret);
System.out.println(s2);
}
}