摘要:充电过程中展示单价、累计费用和最终费用,需要在计量数据、费率规则、充电设备显示能力和后台系统之间建立明确的数据链路。OCPP 1.6 没有原生资费消息,通常需要使用 DataTransfer 承载约定的扩展消息;OCPP 2.0.1提供了显示消息、授权响应、费用更新和交易事件等标准消息,并允许通过CustomData 补充设备本地计算实时费用所需的单价信息。本文整理一份面向协议实现的技术说明,讨论消息模型、实时费用计算、空闲费用、多语言显示、离线场景和测试边界。
一 问题背景
资费显示与普通状态上报不同。后台系统通常掌握完整的费率规则和用户价格,充电设备掌握实时电量、功率和连接状态,显示端则需要在通信延迟或暂时离线时继续展示当前信息。系统如果只在交易结束后发送总费用,用户无法获得实时反馈;如果完全由充电设备自行计算,又可能缺少用户价格或费率变更信息。
一个可实施的分工是:后台系统负责费率确定和权威费用计算,充电设备使用后台下发的单价信息进行本地估算和显示,后台在收到新的电表值后发送更新的累计费用,设备再以后台结果校准本地结果。这样可以兼顾计算权威性与显示实时性。
需要区分三种信息:用于显示的文字、用于计算的结构化单价、以及绑定交易的累计或最终费用。文字适合面向用户,结构化字段适合程序计算,交易编号和时间戳用于保证消息关联和结果可追溯。
二 OCPP 1.6 与 OCPP 2.0.1 的能力边界
OCPP 1.6 原始消息没有专门的价格和费用字段,因此实现资费显示时需要在中央系统和充电设备两侧同时增加扩展约定。常见做法是使用 ChangeConfiguration保存默认价格,使用 DataTransfer 传递用户价格、运行费用和最终费用。
OCPP 1.6 扩展消息需要使用固定的 vendorId 和 messageId,以便双方识别同一种约定。应用说明中使用的扩展消息包括 SetUserPrice、RunningCost、FinalCost和 ConnectorUnplugged 等。扩展消息不能替代普通 OCPP 消息,普通授权、交易启动和状态上报仍应按照原协议执行。
OCPP 2.0.1 可以使用 SetDisplayMessageRequest、AuthorizeResponse、CostUpdatedRequest 和 TransactionEventResponse 等标准消息。运行费用所需的单价、空闲费用和触发条件可以放入 CostUpdatedRequest 的 CustomData,同时由设备模型变量控制费率、货币、离线回退信息和显示能力。
因此,设计时应先确认充电设备使用的 OCPP 版本,再决定是实现 OCPP 1.6扩展协议,还是使用 OCPP 2.0.1 的标准消息加少量 CustomData。不要把两种版本的字段直接混合使用。
三 费用数据模型
1 默认价格 用于用户尚未完成识别或设备处于离线状态时的展示。除了显示文字,还可以包含按电量、按时间和固定费用组成的结构化字段。
2 用户价格 授权后根据用户或合同返回的价格。它与授权标识关联,主要用于显示和后续运行费用计算,不应覆盖交易编号关联关系。
3 运行费用 与交易编号、电表值和时间戳绑定,表示某个计量点之前的累计费用,同时携带当前充电状态和下一时段的费率信息。
4 最终费用 在交易结束时发送,包含总费用以及电量、时间和费用组成等显示信息。最终费用的生成方应在系统设计中明确。
5 触发条件 用于要求设备在特定时间、累计电量、功率阈值或充电状态变化时上报新的计量值,以便后台及时更新费用和费率。
RunningCost
transactionId
timestamp
meterValue
totalCost
state: Charging | Idle
chargingPrice: kWhPrice | hourPrice | flatFee
idlePrice: graceMinutes | hourPrice
nextPeriod
triggerMeterValue
四 OCPP 1.6 的扩展实现
在 OCPP 1.6 中,可以先通过配置消息设置默认价格,并通过 DataTransfer传递用户价格和运行费用。设备收到 RunningCost 后,根据 meterValue、chargingPrice 和 idlePrice 在本地计算显示值;后台收到新的 MeterValues后重新计算权威累计费用,再发送下一条 RunningCost。
DataTransfer.req
{
"vendorId": "org.openchargealliance.costmsg",
"messageId": "RunningCost",
"data": {
"transactionId": "...",
"timestamp": "...",
"meterValue": 0,
"cost": 0.0,
"state": "Charging",
"chargingPrice": { "kWhPrice": 0.0 }
}
}
设备端必须校验 transactionId 是否属于当前交易,校验 meterValue 是否倒退,校验价格字段是否为合法数值,并处理未知字段。后台端应保留每次费用更新的输入电表值、费率版本和计算结果,避免只保存最后一个总费用。
如果需要识别交易结束后车辆仍然连接的情况,单独依赖 Available 状态可能不够可靠,尤其是在设备离线期间。扩展实现可以增加可靠的连接器拔出消息,但该消息是补充信号,不能替代原有 StatusNotification。
五 OCPP 2.0.1 的标准消息
OCPP 2.0.1 可以使用 SetDisplayMessageRequest 发送通用费率信息,使用 AuthorizeResponse 返回授权后的用户价格,使用 CostUpdatedRequest发送交易过程中的累计费用。交易结束时,TransactionEventResponse 可以携带最终总费用和展示文字。
对于设备在两个后台费用更新之间进行本地实时计算的场景,可以在CostUpdatedRequest 的 CustomData 中传递 chargingPrice、idlePrice、nextPeriod 和 triggerMeterValue。设备使用这些字段估算中间时刻的费用,下一次收到后台更新时完成校准。
设备模型中的 TariffCostCtrlr 可以用于设置是否显示费率和费用、使用的货币、离线状态下的回退文字以及离线交易使用的电量和时间单价。将这些参数作为设备模型变量管理,可以减少自定义配置键的数量。
六 空闲费用的状态切换
空闲费用不是计量法规本身必然要求的能力,而是某些价格模型中的可选规则。系统需要区分交易中的暂停和交易结束后的持续连接。交易中的暂停可以由功率下降、MeterValues 不变化或设备上报 SuspendedEV、SuspendedEVSE 判断。
1 进入暂停 后台确认车辆不再充电后,将费用状态切换为 Idle,并发送宽限时间和空闲单价。
2 宽限阶段 从状态切换消息的时间开始计算宽限时间,宽限期间不累计空闲费用。
3 空闲阶段 超过宽限时间后,设备按 idlePrice 估算显示费用,后台继续发送权威费用。
4 恢复充电 设备重新进入 Charging 或功率跨过触发阈值后,后台将状态切回 Charging。
功率阈值触发可能在上升和下降两个方向发生。实现时建议增加滞回,避免功率在阈值附近波动而反复触发计量上报和状态切换。
七 多语言显示
v3.0 增加了多语言资费显示的处理方式。设备需要报告默认语言和支持的语言列表,后台根据语言代码下发相应的费率文字。语言代码应使用 RFC 5646约定,显示文字与结构化价格数据分开处理。
OCPP 1.6 扩展可以为默认价格、用户价格和最终费用增加多语言文字字段,并限制额外语言数量。OCPP 2.0.1 可以使用 personalMessage、updatedPersonalMessage 以及 CustomData 中的额外消息列表传递不同语言。
多语言显示的关键不是简单翻译文字,而是保证同一条消息中的金额、单位、宽限时间和费用组成与默认语言保持一致。语言缺失时应回退到设备默认语言,不能因为翻译内容不存在而丢失结构化计费数据。
八 离线场景
离线时后台不能立即发送用户价格、运行费用或最终费用,设备只能使用之前保存的默认价格和已知单价进行本地计算。系统需要在交易开始前明确离线策略,例如禁止离线交易、允许但不计算费用,或者允许使用默认价格计算。
1 交易中短暂离线 设备继续使用当前和下一时段的已知单价估算显示,恢复连接后由后台费用更新重新校准。
2 离线结束交易 设备保存停止交易消息,恢复连接后补发交易数据,后台完成最终费用计算。
3 完全离线交易 设备只能依据预先配置的默认价格估算,后台收到起止电表值后再按默认规则完成核算。
离线费用显示必须向用户明确当前数据的来源和适用范围。设备端需要持久化交易编号、起止电表值、费率版本和交易时间,避免断电或重启后无法恢复。
九 测试重点
1 消息兼容 验证 OCPP 1.6 扩展的 vendorId、messageId、JSON 字段和长度限制,验证OCPP 2.0.1 标准字段与 CustomData 的组合。
2 计算一致性 使用同一组电表值、费率和时间,比较后台权威结果与设备本地估算结果,验证校准逻辑和小数精度。
3 费率切换 测试下一时段价格、时间触发、电量触发、功率触发和充电状态切换,检查边界时刻是否重复计费或漏计费用。
4 空闲费用 测试宽限时间、暂停恢复、交易结束后持续连接、连接器拔出和离线补发。
5 故障恢复 测试重复消息、乱序电表值、设备重启、后台重连、消息积压和费用消息超时。
6 显示检查 测试金额、货币、单位、时间格式、多语言回退和最终费用保持时长,确认显示文字与结构化数据一致。
十 实现边界
OCPP 消息只负责在充电设备和后台之间传递必要的价格、计量和交易信息,不替代本地法规、计量器具、支付系统或发票系统的完整职责。文章中的离线策略、价格选择和空闲费用规则仍需要结合具体业务和适用地区要求确认。
对于 OCPP 1.6,自定义 DataTransfer 消息必须在通信双方同时实现并保持字段一致;对于 OCPP 2.0.1,应优先使用标准消息,只有标准字段无法覆盖的内容才放入 CustomData。协议版本、设备能力和实际测试结果应在项目文档中单独记录。
十一 结语
资费显示的实现本质上是费用规则、计量数据和设备显示之间的同步问题。后台负责确定费率和计算权威结果,设备负责采集计量值并在短时间内保持可用的本地显示,协议消息负责传递两者之间的关联信息。
实现时应优先明确版本边界、费用数据模型、离线策略和状态转换,再处理多语言、空闲费用和兼容性扩展。只有保存交易编号、电表值、费率版本、时间戳和处理结果,才能在费用显示出现差异时完成复核。
参考资料:OCA Application Note,OCPP and California Pricing Requirements,v3.0,2024-02-22。本文为协议内容的技术整理,不替代正式规范和适用法规。