feat: 上线历史剩余氢质量批量查询接口

This commit is contained in:
lingniu
2026-09-09 01:00:29 +08:00
parent 4ab654e1c1
commit 1849bc1870
12 changed files with 1457 additions and 7 deletions
@@ -24,7 +24,7 @@
<a class="brand" href="#overview"><span class="brand-name">羚牛 · 数据开放平台</span><span class="brand-subtitle">车辆数据 API Reference</span></a>
<nav>
<div class="nav-group"><span class="nav-title">开始使用</span><a class="nav-link docs" href="#overview">平台简介</a><a class="nav-link docs" href="#authentication">认证与授权</a><a class="nav-link docs" href="#request-examples">请求体样例</a></div>
<div class="nav-group"><span class="nav-title">车辆数据</span><a class="nav-link primary" href="#daily-hydrogen">车辆单日用氢量</a><a class="nav-link primary" href="#daily-mileage">车辆单日里程</a><a class="nav-link primary" href="#mileage-range">车辆区间日里程</a><a class="nav-link primary" href="#total-mileage">指定时刻总里程</a><a class="nav-link primary" href="#realtime">实时位置与状态</a></div>
<div class="nav-group"><span class="nav-title">车辆数据</span><a class="nav-link primary" href="#daily-hydrogen">车辆单日用氢量</a><a class="nav-link primary" href="#historical-hydrogen">历史剩余氢质量</a><a class="nav-link primary" href="#daily-mileage">车辆单日里程</a><a class="nav-link primary" href="#mileage-range">车辆区间日里程</a><a class="nav-link primary" href="#total-mileage">指定时刻总里程</a><a class="nav-link primary" href="#realtime">实时位置与状态</a></div>
<div class="nav-group"><span class="nav-title">加氢服务</span><a class="nav-link station" href="#stationary">加氢车辆停留核验</a><a class="nav-link station" href="#stations">加氢站地图点位</a></div>
<div class="nav-group"><span class="nav-title">通用说明</span><a class="nav-link docs" href="#response-fields">返回字段与枚举</a><a class="nav-link docs" href="#protocols">总里程协议口径</a><a class="nav-link docs" href="#errors">异常与状态码</a></div>
</nav>
@@ -69,6 +69,16 @@
"cooperateOnly": true
}</pre></article></div></section>
<section class="section" id="historical-hydrogen"><div class="section-head"><div><h2>历史时刻剩余氢质量 · 1.10.0</h2><div class="endpoint"><span class="method">POST</span>/api/v1/vehicles/hydrogen-remaining/history/query</div><p>仅查询2026-08-01起的真实历史 event_time,不使用未来采样、实时值或日用氢量填补。最近氢相关帧异常或字段不全时显式返回,不跳过它找旧正常值。</p></div><a class="anchor" href="#historical-hydrogen">#</a></div><div class="grid"><div><h3 class="subhead">请求参数</h3><table class="param-table"><tr><th>字段</th><th>必填</th><th>说明</th></tr><tr><td>queries</td><td></td><td>1200项</td></tr><tr><td>queries[].requestId</td><td></td><td>本批唯一非空,最多128字节,原样回显</td></tr><tr><td>queries[].vin / time</td><td></td><td>VIN规范化大写17位且不含I/O/Q;北京时间yyyy-MM-dd HH:mm:ss,不可未来或早于2026-08-01</td></tr><tr><td>queries[].protocol</td><td></td><td>GB32960 / YUTONG_MQTT / JT808;省略固定GB32960,后两者当前UNSUPPORTED,不跨协议回退</td></tr><tr><td>maxTimeDifferenceSeconds</td><td></td><td>整数0–300,默认300;0要求精确命中</td></tr></table><div class="note">应用与逐车授权需同时覆盖查询时刻和采样时刻(结束时间不含端点);FORBIDDEN不泄露采样元数据。当前appKey无效/过期为401,非法结构400。</div></div><div><h3 class="subhead">请求示例(非真实读数)</h3><pre class="code">{
"queries": [{
"requestId": "job-start",
"vin": "LA9GG68L2PBAF4773",
"time": "2026-08-03 16:02:43",
"protocol": "GB32960"
}],
"maxTimeDifferenceSeconds": 300
}</pre><p>合法批量HTTP200/SUCCESS,逐项状态判断:NORMAL、NO_DATA、MISSING、STALE、UNSUPPORTED、INVALID、FORBIDDEN、ERROR。非NORMAL质量null,不丢项,不补零。</p><p>每app每实例30批/60秒,最多2个并发批;429读取Retry-After秒后重试。整批9秒预算、4个工作协程,超时项ERROR而不是NO_DATA。200项是结构上限,不保证200个不同点均能按时完成;建议从20个不同点开始,超时缩小批量并退避重试。</p></div></div><div class="note">历史容量需要历史适用版本;当前表不能回套历史。当前只有REPORTED质量可用,缺历史容量版本时不估算,返回MISSING。同批按规范化VIN+time+protocol去重,同点共享单次查询/授权结果和来源版本,所有requestId独立回显;不同点仍是非原子快照,保留各项版本和原始证据。质量保留原精度,Seeker自行计算两端净减少量并在负差值时归零。</div></section>
<section class="section" id="daily-hydrogen"><div class="section-head"><div><h2>车辆单日用氢量</h2><div class="endpoint"><span class="method">POST</span>/api/v1/vehicles/hydrogen-consumption/query</div><p>查询车辆单日用氢量,单位 kg。NORMAL + OK + PRELIMINARY 仅供初步监控;正式报表要求 FINAL 并核对证据与版本。两个日统计接口没有共同快照,区间缺失或不同不能直接计算百公里氢耗。</p></div><a class="anchor" href="#daily-hydrogen">#</a></div><div class="grid"><div><h3 class="subhead">请求参数</h3><table class="param-table"><tr><th>字段</th><th>必填</th><th>说明</th></tr><tr><td>date</td><td class="required"></td><td>日期,格式 yyyy-MM-dd</td></tr><tr><td>plateNumbers</td><td class="optional"></td><td>车牌数组;省略或 [] 时查询全部授权车辆</td></tr></table></div><div><h3 class="subhead">成功返回 · 200</h3><pre class="code">{<br> <span class="key">"code"</span>: <span class="string">"SUCCESS"</span>,<br> <span class="key">"data"</span>: [{<br> <span class="key">"plateNumber"</span>: <span class="string">"浙F06618F"</span>,<br> <span class="key">"hydrogenConsumptionKg"</span>: <span class="number">12.315</span>,<br> <span class="key">"status"</span>: <span class="string">"NORMAL"</span><br> }]<br>}</pre><ul class="errors"><li>400:日期或车牌格式不正确</li><li>401appKey 无效、停用或过期</li><li>403:指定车辆未授权</li></ul></div></div></section>
<section class="section" id="daily-mileage"><div class="section-head"><div><h2>车辆单日里程</h2><div class="endpoint"><span class="method">POST</span>/api/v1/vehicles/mileage/query</div><p>返回当日行驶里程、当日累计总里程和实际选用的数据协议,单位 km。</p></div><a class="anchor" href="#daily-mileage">#</a></div><div class="grid"><div><h3 class="subhead">请求参数</h3><table class="param-table"><tr><th>字段</th><th>必填</th><th>说明</th></tr><tr><td>date</td><td class="required"></td><td>日期,格式 yyyy-MM-dd</td></tr><tr><td>plateNumbers</td><td class="optional"></td><td>省略时查询全部授权车辆</td></tr><tr><td>protocolPriority</td><td class="optional"></td><td>协议选源顺序,例如 ["GB32960","MQTT","JT808"]</td></tr></table><div class="note"><strong>缺数规则:</strong>若当日没有有效里程,日里程为 0;累计总里程沿用上一个有效统计周期,计算时间也显示该周期时间。</div></div><div><h3 class="subhead">成功返回 · 200</h3><pre class="code">{<br> <span class="key">"code"</span>: <span class="string">"SUCCESS"</span>,<br> <span class="key">"data"</span>: [{<br> <span class="key">"dailyMileageKm"</span>: <span class="number">182.437</span>,<br> <span class="key">"totalMileageKm"</span>: <span class="number">12345.679</span>,<br> <span class="key">"sourceProtocol"</span>: <span class="string">"GB32960"</span>,<br> <span class="key">"status"</span>: <span class="string">"NORMAL"</span><br> }]<br>}</pre><ul class="errors"><li>400:日期、车牌或协议参数错误</li><li>403:授权期未覆盖查询日</li><li>无统计:单车以 NO_DATA 返回</li></ul></div></div></section>
@@ -98,6 +108,19 @@
["traceId", "string", "本次请求的唯一追踪标识;出现问题时请完整提供给羚牛技术支持。"]
];
const fields = {
"historical-hydrogen": [
["data[].requestId / vin / queryTime", "string", "逐项对应请求;不得只依赖数组位置配对作业起终点。"],
["data[].plateNumber", "string | null", "当前缺少历史车牌证据,为null,不把当前车牌冒充历史车牌。"],
["data[].remainingHydrogenKg / remainingHydrogenKgStatus", "number | null / enum", "仅NORMAL给原始精度kg;其他状态null。有效质量超过容差STALE;最新INVALID/MISSING保留原状态。无历史氢相关帧NO_DATA;分块重组失败或扫描预算耗尽ERROR,不得回退。"],
["data[].hydrogenRecordTime / timeDifferenceSeconds", "datetime | null / number | null", "真实event_timeRFC3339带时区)与查询采样偏差秒数,绝不使用查询之后的帧。"],
["data[].hydrogenValueSource / hydrogenSourceProtocol", "string | null", "当前REPORTED表示终端上报(不等同直接测量),GB32960为实际氢协议。ESTIMATED保留但缺历史容积版本时不输出估算值。"],
["data[].sourceRecordId", "string | null", "raw-sha256采样身份指纹,便于识别同一采样命中;内容版本另看sourceDataVersion,不是批次快照。"],
["data[].sourceDataVersion", "string | null", "sha256原始JSON与解析状态内容指纹,识别同采样修订;不同起终点内容不同是正常的,不要求两端此字段相等。"],
["data[].hydrogenCalculationVersion / hydrogenCapacityVersion", "string | null", "REPORTED_HYDROGEN_KG_V1解码转换版本;历史容量版本缺证据为null,不能用当前值回套。"],
["data[].updatedAt", "datetime | null", "原始记录接收时间,不代替采集时间;即使时间不变,内容修订仍会改变sourceDataVersion。"],
["data[].reasonCode / message", "string | null", "可程序识别原因与中文说明;ERROR应重试,不能当NO_DATAFORBIDDEN不返回采样证据。"],
["data[].hydrogenEstimatePressureMPa / hydrogenEstimateTemperatureC / hydrogenTankCapacityL / hydrogenPressureTemperatureSource", "number | null / string | null", "有同帧温压可返回诊断证据;MAX_SENSOR_AGGREGATE不保证同瓶。没有历史容量证据仍MISSING,容积null。"]
],
"daily-hydrogen": [
["data[]", "array", "按请求车牌顺序返回的车辆数据数组。"],
["data[].vin", "string", "授权车辆 VIN,必须与实时、里程记录共同核对。"],
@@ -1,7 +1,7 @@
openapi: 3.0.3
info:
title: 车辆数据开放平台 API
version: 1.9.0
version: 1.10.0
license:
name: Proprietary
description: |
@@ -16,6 +16,55 @@ tags:
- name: 开放平台管理
description: 仅车辆数据平台管理员可调用的应用和车辆授权管理接口
paths:
/api/v1/vehicles/hydrogen-remaining/history/query:
post:
tags: [合作方数据接口]
summary: 批量查询历史时刻剩余氢质量
description: |
按真实 event_time 查询不晚于指定时刻的最近氢相关帧,不跳过最新异常记录,不使用实时值或日用氢量填补。
历史支持从 2026-08-01 起;实际车辆/时间覆盖以保留的原始帧为准,日期可请求不代表每个时点均有有效氢量。
历史容量必须具有适用于历史时点的证据;不能用当前配置回套历史。当前缺少历史容量版本,只输出有证据的REPORTED质量,温压有效但无容量版本时 MISSING。
同批按规范化VIN+time+protocol去重,同一点共享一次查询/授权结果与来源版本,各requestId仍独立回显;不同点为非原子快照,不以同批证明两端可比。
200项仅为结构上限,不保证200个不同点能在9秒完成。建议先用20个不同点,ERROR超时时缩小批量并退避重试。
有效采样超容差为STALE,最新帧INVALID/MISSING优先保留原原因;分块原始帧重组失败或候选预算耗尽为ERROR,不伪装NO_DATA。
每项均返回 requestIdFORBIDDEN、ERROR 等失败不丢项,非 NORMAL 质量为 null。
appKey须当前有效,并逐项校验请求时刻与采样时刻授权(结束时间不含端点);FORBIDDEN不返回采样元数据。
每app每服务实例30批/60秒,最多2个并发批;429包含Retry-After。整批9秒预算、最多4个工作协程,超时项ERROR,可重试。
operationId: queryHistoricalHydrogenRemaining
security:
- AppKeyAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/HistoricalHydrogenQuery'
example:
queries:
- requestId: job-start
vin: LA9GG68L2PBAF4773
time: '2026-08-03 16:02:43'
protocol: GB32960
maxTimeDifferenceSeconds: 300
responses:
'200':
description: 批量处理完成;每项状态独立判断,包括 FORBIDDEN 或 ERROR
content:
application/json:
schema:
$ref: '#/components/schemas/HistoricalHydrogenQueryResponse'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'429':
description: 超出历史查询限流;读取 Retry-After 秒数后重试
headers:
Retry-After:
schema: { type: integer, minimum: 1 }
description: 建议等待秒数
'500':
$ref: '#/components/responses/InternalError'
/api/v1/vehicles/hydrogen-consumption/query:
post:
tags: [合作方数据接口]
@@ -529,7 +578,7 @@ components:
properties:
vin:
type: string
pattern: '^[A-HJ-NPR-Z0-9]{17}$'
pattern: '^[A-HJ-NPR-Za-hj-npr-z0-9]{17}$'
description: 已授权车辆 VIN
time:
type: string
@@ -598,6 +647,67 @@ components:
minLength: 1
maxLength: 32
description: 可选;省略或传空数组时查询当前有效授权的全部车辆
HistoricalHydrogenQuery:
type: object
additionalProperties: false
required: [queries]
properties:
queries:
type: array
minItems: 1
maxItems: 200
items:
type: object
additionalProperties: false
required: [requestId, vin, time]
properties:
requestId: { type: string, minLength: 1, maxLength: 128, description: 本批唯一非空关联标识,最多128字节,原样返回 }
vin: { type: string, minLength: 17, maxLength: 17, pattern: '^[A-HJ-NPR-Za-hj-npr-z0-9]{17}$', description: 查询VIN按大写规范化,禁止I/O/Q }
time: { type: string, description: '北京时间 yyyy-MM-dd HH:mm:ss;不得早于2026-08-01或晚于请求时刻' }
protocol: { type: string, enum: [GB32960, YUTONG_MQTT, JT808], default: GB32960, description: 省略固定GB32960;显式协议不切换,YUTONG_MQTT/JT808当前UNSUPPORTED }
maxTimeDifferenceSeconds:
type: integer
minimum: 0
maximum: 300
default: 300
description: 允许采样早于查询的最大秒数;0要求精确命中,不静默放宽
HistoricalHydrogenQueryResponse:
allOf:
- $ref: '#/components/schemas/SuccessEnvelope'
- type: object
required: [data]
properties:
data:
type: array
items: { $ref: '#/components/schemas/HistoricalHydrogenResult' }
HistoricalHydrogenResult:
type: object
required: [requestId, vin, plateNumber, queryTime, remainingHydrogenKg, hydrogenRecordTime, timeDifferenceSeconds, remainingHydrogenKgStatus, hydrogenValueSource, hydrogenSourceProtocol, sourceRecordId, sourceDataVersion, hydrogenEstimatePressureMPa, hydrogenEstimateTemperatureC, hydrogenTankCapacityL, hydrogenPressureTemperatureSource, hydrogenCalculationVersion, hydrogenCapacityVersion, updatedAt, reasonCode, message]
properties:
requestId: { type: string, description: 本批对应请求标识 }
vin: { type: string }
plateNumber: { type: string, nullable: true, description: 无可证明历史车牌时为 null,不冒用当前车牌 }
queryTime: { type: string, description: 请求北京时间 }
remainingHydrogenKg: { type: number, nullable: true, minimum: 0, description: '全车剩余氢质量kg,保留源/模型计算精度;仅NORMAL可用,其他状态null。不得用缺值补0' }
hydrogenRecordTime: { type: string, format: date-time, nullable: true, description: 真实原始帧 event_timeRFC3339带时区 }
timeDifferenceSeconds: { type: number, nullable: true, minimum: 0, description: queryTime减真实采集时间的秒数 }
remainingHydrogenKgStatus:
type: string
enum: [NORMAL, NO_DATA, MISSING, STALE, UNSUPPORTED, INVALID, FORBIDDEN, ERROR]
description: 仅NORMAL参与业务计算;ERROR明确为处理失败,可按原因重试;FORBIDDEN不泄露采样
hydrogenValueSource: { type: string, nullable: true, enum: [REPORTED, ESTIMATED], description: 终端上报不等同于直接测量;估算需历史温压/容积证据 }
hydrogenSourceProtocol: { type: string, nullable: true, enum: [GB32960, YUTONG_MQTT, JT808] }
sourceRecordId: { type: string, nullable: true, description: raw-sha256采样身份指纹;两端相同需识别采样分辨率不足,内容修订另看sourceDataVersion }
sourceDataVersion: { type: string, nullable: true, description: 'sha256原始JSON和解析状态内容指纹;同采样被修订时变化,不是两端必须相等的口径版本' }
hydrogenEstimatePressureMPa: { type: number, nullable: true, description: 有效同帧最大氢压MPa证据,缺历史容量仍可诊断返回 }
hydrogenEstimateTemperatureC: { type: number, nullable: true, description: 有效同帧最大氢温摄氏度证据 }
hydrogenTankCapacityL: { type: number, nullable: true, description: 当前缺历史容量版本始终null,不能回套当前容积 }
hydrogenPressureTemperatureSource: { type: string, nullable: true, enum: [MAX_SENSOR_AGGREGATE], description: 最大温压聚合不保证同瓶 }
hydrogenCalculationVersion: { type: string, nullable: true, description: 当前REPORTED_HYDROGEN_KG_V1,质量不额外舍入;ESTIMATED预留但当前缺历史容积版本不输出估算值 }
hydrogenCapacityVersion: { type: string, nullable: true, description: 历史时点适用容积版本;估算必需,无证据不估算 }
updatedAt: { type: string, format: date-time, nullable: true, description: 原始记录received_atRFC3339带时区;不代替采集时间,同时间戳修订通过sourceDataVersion识别 }
reasonCode: { type: string, nullable: true, description: 可程序识别的状态原因 }
message: { type: string, nullable: true, description: 中文状态说明 }
HydrogenStationQuery:
type: object
additionalProperties: false