简电云 | OCPP 1.6 充电桩平台基于 OCPI 2.3.0 实现 POS 云端对接方案
发布时间:2026/9/30 6:38:29来源:尧图网络
一、为什么需要 POS 云端对接公共充电站越来越需要支持银行卡、非接触式信用卡和手机钱包。传统方案通常把 POS 与充电桩通过串口或局域网直连这种方式在单一设备上容易落地但也带来几个问题POS、桩控板和固件强耦合换一个终端品牌就可能重新开发终端配置、密钥更新和故障处理依赖现场维护一台 POS 难以服务同站多台充电桩支付流水与平台充电订单分散退款、对账和审计成本高海外项目还要处理多币种、税费、电子凭证和 PCI DSS 等要求。云端对接把 POS 的支付能力抽象为独立服务POS 接入支付终端提供方 PTPPayment Terminal Provider云平台充电运营商 CPOCharge Point Operator继续用 OCPP 1.6 管理充电桩双方通过 OCPI 2.3.0 交换终端、站点、费率、充电会话和支付结果。这里要先澄清一个常见误区OCPI 不是用来替代 OCPP 的。OCPP 负责平台与充电桩之间的设备控制OCPI 负责不同业务平台之间的数据和业务协同。POS 云平台不会直接向充电桩发送 OCPP 报文。二、OCPI 2.3.0 为 POS 场景增加了什么OCPI 2.3.0 将 Payments 作为独立功能模块发布主要服务“临时用户直接支付”场景。它引入了 PTP 角色并定义两个核心对象对象数据所有方作用TerminalPTP描述物理支付终端并建立终端与 Location、EVSE 的绑定关系FinancialAdviceConfirmationPTP将最终收款金额、收款状态和发票所需 EFT 数据回传给 CPO但 Payments 模块本身不负责完整的充电交易。一个可用的 POS 云端方案还需要组合以下模块OCPI 模块在 POS 充电流程中的职责Credentials / Versions双方注册、令牌交换、版本和端点发现Payments终端开通、站点绑定、收款确认Locations同步站点、EVSE、Connector、状态和能力Tariffs提供价格、币种、税率和预授权金额Commands异步发送START_SESSION、STOP_SESSIONSessions同步充电中的电量、费用和状态CDRs发送不可变的最终充电记录和应收金额因此工程上不能只实现一个/payments接口就声称完成 OCPI POS 对接。至少要打通 Locations、Tariffs、Commands、Sessions、CDRs 和 Payments 六条业务链路。三、总体架构与职责边界银行卡 / 手机钱包 | POS 终端 | 收单终端协议 v PTP 云平台 / PSP 收单机构 | | OCPI 2.3.0 HTTPS v CPO 充电运营平台 |-- OCPI 网关 |-- POS 订单与支付关联服务 |-- 计费、订单、发票、对账服务 | | OCPP 1.6J WSS v 充电桩各系统的职责应保持单一POS/PTP读卡、持卡人验证、预授权、请款、撤销、支付凭证和终端管理CPO 平台站点管理、费率发布、充电控制、计量计费、订单、CDR 和发票OCPP 1.6 充电桩执行启停、采集电表、上报连接器状态和交易事件PSP/收单机构连接卡组织与发卡行处理资金授权和清算。推荐在 CPO 平台新增 OCPI Gateway 和 Payment Orchestrator。前者严格处理 OCPI 对象、鉴权和版本兼容后者维护预授权、充电订单、OCPP 交易与最终收款之间的状态关系。不要让 OCPI 接口直接读写 OCPP 核心表。四、接入前的主数据映射1. 终端与充电设施映射PTP 创建TerminalCPO 再把允许该终端服务的location_ids和evse_uids更新给 PTP。一台 POS 可以服务一个站点也可以只服务指定 EVSE。{ terminal_id: 9e94f62c-661b-4afa-b6da-019b58fab9ac, customer_reference: CPO-AZ-001, invoice_base_url: https://cpo.example.com/invoices, invoice_creator: CPO, location_ids: [PHX-SITE-01], evse_uids: [PHX-01-EVSE-01, PHX-01-EVSE-02], last_updated: 2026-09-28T08:00:00Z }其中terminal_id是 PTP 侧终端标识不能用 POS 序列号临时替代location_ids和evse_uids必须引用 Locations 模块中已经存在的对象。终端移机时要先解除旧映射再更新地址和绑定关系避免用户在错误站点发起支付。2. OCPP 1.6 与 OCPI 对象映射OCPP 1.6 和 OCPI 的设备层级并不完全相同建议建立显式映射表CPO 内部字段OCPP 1.6OCPI 2.3.0充电桩WebSocket 路径中的 charge point identityLocation 下的一个或多个 EVSE枪口connectorIdEVSE.uidConnector.id充电交易transactionIdSession.id启动凭证idTagToken.uid支付授权关联号无标准字段authorization_reference过程计量MeterValuesSession 的kwh、total_cost等最终记录StopTransactionCDR对于 OCPP 1.x一个 EVSE 下存在多个 Connector 时容易产生语义冲突。按照 OCPI 规范建议CPO 应把需要独立启停的 OCPPconnectorId暴露为独立 EVSE再在 EVSE 下提供连接器规格。这样START_SESSION才能稳定映射到唯一枪口。3. 四个核心关联键平台至少要长期保存以下关联terminal_id - authorization_reference - OCPI session_id - OCPP transactionIdauthorization_reference由 PTP 在预授权成功后生成并放入START_SESSION。CPO 必须把它继续写入 Session 和 CDR。它是支付交易、充电会话和发票之间最关键的关联号不能在重试时重新生成。五、完整业务流程1. 建立 OCPI 连接CPO 与 PTP 先通过 Credentials 完成双向注册交换访问令牌再通过 Versions 获取 2.3.0 端点。双方应明确各模块的 Sender/Receiver 接口、国家代码、Party ID、回调地址和超时时间。生产环境建议为每个合作方单独签发 OCPI Token所有请求使用 HTTPS并在网关校验来源、权限和限流策略。OCPI Token 不是司机的支付令牌也不能用于 POS 持卡人认证。2. 开通并绑定 Terminal对于集成式 POSCPO 可使用设备参考号向 PTP 发起激活PTP 完成配置后在 CPO 侧创建Terminal。对于已在 PTP 侧开通的终端CPO 可拉取或接收终端数据再通过 PATCH 分配location_ids、evse_uids。终端只有同时满足以下条件才可接单Terminal 在 PTP 侧有效终端已绑定当前 Location 或 EVSELocation、EVSE、Connector 在 OCPI 中可用充电桩已通过 OCPP 上线目标枪口不是Faulted、Unavailable或被占用Tariff 已配置币种、税率和预授权上限。3. 展示枪口和费率用户在 POS 上选择枪口后PTP 拉取或读取缓存的 Location/EVSE 数据取得 Connector 对应的tariff_ids再获取 Tariff 展示价格。OCPI 2.3.0 的支付流程依赖 Tariff 中的preauthorize_amount确定预授权额度。这里要区分两个金额预授权金额是风险控制上限最终应收金额来自 CDR。POS 页面应清楚显示币种、能源费、时间费、占位费、固定服务费、税费以及预授权提示不能把预授权金额显示为已经扣款。4. 预授权并远程启动用户确认费率并刷卡后PTP 向 PSP 发起预授权。成功后PTP 生成全局唯一的authorization_reference然后向 CPO 发送 OCPISTART_SESSION。下面只保留与方案相关的关键字段{ response_url: https://ptp.example.com/ocpi/commands/result/start-20260928-001, token: { country_code: US, party_id: PTP, uid: POS-20260928-001, type: AD_HOC_USER, contract_id: US-PTP-POS000001 }, location_id: PHX-SITE-01, evse_uid: PHX-01-EVSE-01, connector_id: 1, authorization_reference: AUTH-20260928-000001 }CPO 收到请求后的处理顺序如下校验 OCPI 调用方、终端绑定、EVSE 状态和重复请求立即返回 OCPICommandResponse说明命令是否进入处理将Token.uid映射为长度符合 OCPP 1.6 限制的idTag向充电桩发送RemoteStartTransaction.req收到桩端响应后将最终CommandResult异步 POST 到response_url收到StartTransaction.req后创建 Session并绑定 OCPPtransactionId。OCPI Commands 是异步接口。第一步返回ACCEPTED只代表 CPO 接受并尝试下发不代表车辆已经开始充电。PTP 必须等待CommandResult并继续观察 Session如果桩端返回拒绝、超时或最终没有生成 Session应撤销预授权。5. 充电中同步 Session充电桩通过 OCPPMeterValues上报电量和功率CPO 根据费率计算阶段费用再向 PTP 推送 Session 更新。建议维护如下映射OCPP 事件CPO 内部动作OCPI 输出StartTransaction.req创建交易并记录表底新建 Session状态为ACTIVEMeterValues.req更新电量、功率和预估金额PATCH/PUT SessionStatusNotification.req更新枪口状态更新 EVSE/Connector 状态StopTransaction.req固化结束表底和停止原因完成 Session生成 CDRPTP 可以根据 Session 的kwh和total_cost监控预授权余额。当预计费用接近上限时可发送STOP_SESSIONCPO 也应设置自己的金额保护阈值。任何一方触发停止都要使用同一个 Session 继续处理不能创建第二笔订单。6. 停止、生成 CDR 与最终扣款停止充电可能来自 POS、车辆、充电桩或 CPO。POS 主动停止时PTP 向 CPO 发送STOP_SESSIONCPO 把session_id映射为 OCPPtransactionId下发RemoteStopTransaction最终以桩端StopTransaction.req的表底和时间为准完成计费。CPO 随后向 PTP 发送 CDR。CDR 是最终充电记录应包含位置快照、Token、充电时段、费率、用电量、总费用、币种以及authorization_reference。Session 是可更新的过程数据CDR 是结算凭据两者不能混用。PTP 根据 CDR 的最终金额向 PSP 发起 capture最终金额小于预授权按实际金额请款释放剩余额度最终金额等于预授权全额请款最终金额超过预授权按收单机构规则增补授权或转异常处理不能直接假定超额扣款成功金额为零撤销预授权并保留零金额 CDR 供审计。7. 回传 FinancialAdviceConfirmation如果发票由 CPO 创建PTP 完成 capture 后向 CPO 创建FinancialAdviceConfirmation。示例如下{ id: FAC-20260928-000001, authorization_reference: AUTH-20260928-000001, total_costs: { before_taxes: 18.00, taxes: [ { name: VAT, percentage: 10.0, amount: 1.80 } ] }, currency: USD, eft_data: [ Mastercard, Card: **** **** **** 1234, Authorization: A12345, Amount: USD 19.80 ], capture_status_code: SUCCESS, capture_status_message: Capture successful, last_updated: 2026-09-28T09:15:00Z }capture_status_code可表达SUCCESS、PARTIAL_SUCCESS和FAILED。CPO 不能只要收到该对象就把订单置为已支付而应根据状态和金额核对 CDR。若由 PTP 开票则 PTP 直接向用户提供凭证CPO 仍需保存支付确认用于对账。六、平台状态机设计推荐把充电状态与支付状态分开维护避免一次网络超时把两条链路同时改错。支付状态 CREATED - PREAUTHORIZING - PREAUTHORIZED - CAPTURING - CAPTURED | | | DECLINED VOIDING CAPTURE_FAILED | VOIDED 充电状态 PENDING - STARTING - CHARGING - STOPPING - FINISHED - CDR_SENT | | START_FAILED STOP_UNKNOWN订单只有在CDR_SENT CAPTURED后才进入最终完成状态。FINISHED但未收款成功时充电事实仍然成立应进入支付重试或人工对账不能删除订单或反向修改电量。建议对以下键建立唯一约束OCPI Commands合作方 response_url中的业务请求号支付授权PTP authorization_referenceSessionCPOcountry_codeparty_idsession_idCDRCPOcountry_codeparty_idcdr_idOCPP 交易charge point identity transactionId收款确认PTP FinancialAdviceConfirmation.id。七、异常场景与补偿策略1. 预授权成功但远程启动失败PTP 撤销预授权CPO 将充电订单标记为START_FAILED。如果 OCPI Command 先超时、稍后桩又启动成功CPO 必须以实际StartTransaction和 Session 为准触发告警不能简单创建新订单。可设置短暂的观察窗口后再确认撤销。2. OCPI 返回 ACCEPTED但没有回调PTP 不应重复生成新的authorization_reference。应使用原业务号查询或重试CPO 则返回已保存的命令结果。命令、回调和 Session 创建都要幂等。3. OCPP 断线充电可能仍在进行OCPP 1.6 连接断开不等于交易结束。CPO 将订单置为CHARGING_UNKNOWN等待桩重连后补传MeterValues或StopTransaction。在没有最终表底时不要生成正式 CDR也不要提前按预估金额请款。4. 已收到 CDR但 capture 超时PTP 应先按原支付流水向 PSP 查询再决定是否重试。盲目创建新支付流水会导致重复扣款。持续失败时回传FAILED双方把订单送入异常对账队列。5. 金额或币种不一致Tariff、CDR 和 FinancialAdviceConfirmation 必须使用一致的 ISO 4217 币种。平台比较金额时应使用十进制定点数禁止使用二进制浮点直接计算货币。若最终 capture 金额与 CDR 不一致自动暂停开票并报警。6. 消息乱序或重复OCPI 推送、异步命令回调和 OCPP 上报都可能重试或乱序。对象更新应比较last_updated状态迁移使用条件更新CDR 到达后较旧的 Session 更新不得把订单重新改为充电中。八、安全与合规POS 云端接入同时涉及充电基础设施和支付数据建议至少落实以下措施OCPP 使用wss://OCPI 使用 TLS 1.2 及以上合作方访问令牌独立签发、定期轮换。PAN、磁道数据、CVV 和终端密钥不得进入 CPO 日志、Session 或 CDR平台只保存支付令牌、卡品牌、末四位和授权码等必要信息。eft_data进入日志和客服页面前需要脱敏并按当地发票法规控制访问权限和保存周期。POS 侧遵循 PCI PTS支付处理环境按业务边界评估 PCI DSSEMV、SCA、退款和预授权有效期以收单机构规则为准。OCPI Commands 接口增加时间窗、重放检测、速率限制和终端到 EVSE 的授权校验。原始 OCPI 报文、OCPP 报文、订单事件和 PSP 流水使用统一追踪号审计日志只追加、不覆盖。九、上线测试清单协议与主数据Credentials 注册、Token 轮换、版本发现和模块端点校验Terminal 创建、激活、移机、停用和 Location/EVSE 重新绑定Location、Connector、Tariff 增量同步及last_updated冲突OCPPconnectorId与 OCPI EVSE/Connector 的一一映射。正常业务刷卡、预授权、启动、计量、停止、CDR、capture、发票全流程POS 停止、车辆停止、急停、金额上限停止一台 POS 服务多台桩多台 POS 服务同一站点能源费、时间费、占位费、固定费和税费组合计费。异常与恢复预授权拒绝、启动拒绝、命令回调超时、桩离线OCPP 断线续充、桩重启、补传 StopTransactionOCPI 重复请求、乱序更新、CDR 重发、capture 回调重发撤销失败、部分收款、退款、跨日交易和预授权过期CDR 与收款金额不一致、币种不一致、税额舍入差异。上线前应完成 PTP、CPO、PSP 和真实充电桩的四方联调。只使用接口模拟器无法覆盖 OCPP 离线缓存、枪口状态变化和收单网络超时等关键问题。十、实施建议对于已有 OCPP 1.6 平台可以分三阶段上线第一阶段完成 OCPI 基础连接、Locations、Tariffs 和 Terminal 管理先验证终端、站点、枪口和价格是否一致。第二阶段打通 Commands、Sessions 和 CDRs使用测试 Token 跑通远程启停与计费不接真实资金。第三阶段接入 PSP 预授权与 capture再启用 Payments 的 FinancialAdviceConfirmation、电子凭证和自动对账。这种拆分可以把“充电是否成功”和“资金是否成功”分开验收也便于定位问题属于 POS、PTP、OCPI 网关、CPO 订单系统还是 OCPP 充电桩。结语基于 OCPI 2.3.0 的 POS 云端对接核心不是新增一个支付接口而是建立一条可追踪的跨平台交易链Terminal 解决“哪台 POS 服务哪些枪口”Tariff 解决“向用户展示什么价格”Commands 和 OCPP 解决“如何启动与停止”Sessions 和 CDRs 解决“实际充了多少、应收多少”FinancialAdviceConfirmation 解决“最终收了多少、发票如何补齐”。只要严格划分 PTP、CPO、PSP 和充电桩的职责以authorization_reference串联预授权、Session、CDR 与收款结果再配合幂等、状态机和对账机制现有 OCPP 1.6 平台无需改变桩端协议也能形成标准化、可扩展的 POS 云端支付能力。说明本文基于 OCPI 2.3.0 官方规范及 Payments 模块编写。示例域名、标识和金额仅用于说明实际接口字段、必填项和行为应以项目采用的 OCPI 2.3.0 正式文档、收单机构规范及当地监管要求为准。参考资料OCPI 官方规范仓库OCPI 2.3.0 Payments 模块Open Charge AllianceOCPP 1.6
网站建设高端定制企业官网