EV

不用自己开发的EV充电App:基于OCPP ID标签的二维码充电方案

大多数OCPP教程解释的是充电桩如何与后端通信,但几乎没有人讲司机是如何进入系统的。

大多数计划开发司机端App的团队,第一反应都是"做一个原生App",但这会悄悄变成项目中最昂贵的一项:两套代码库、应用商店审核周期、每次收费结构调整都要强制更新,以及大多数司机不愿意为一次性充电而下载App的现实。

其实有一种更简单的模式,也是我们在生产环境中实际运行的方式:充电桩上的二维码直接打开手机网页,无需安装、无需注册账号,司机四次点击内即可开始充电。本文将说明这套方案在OCPP协议下如何运作、后端需要构建什么,并提供一个可以立即生成真实二维码的实时演示。


目录

  1. 司机身份验证在OCPP中的位置
  2. 两种授权方式:RFID卡 vs App生成的ID标签
  3. 完整的二维码流程
  4. 后端需要构建的内容
  5. 立即体验
  6. 合规注意事项
  7. 常见问题

司机身份验证在OCPP中的位置

OCPP 1.6并不关心司机的身份是如何被验证的——它只关心Authorize.reqStartTransaction.req中是否附带了idTag。协议本身对标签的来源保持中立,可以是:

  • 充电桩自带读卡器读取的实体RFID卡
  • 通过充电桩本地键盘输入的标签
  • 后端通过RemoteStartTransaction.req远程下发给充电桩的标签

正是第三种方式,让免App充电成为可能。后端不需要等待充电桩读卡——只要司机在网页上点击"开始",后端立即下发带有生成标签的启动指令。充电桩接收这条指令的方式,与接收RFID刷卡完全一致。

CS→CP: RemoteStartTransaction.req(connectorId, idTag)
CP→CS: RemoteStartTransaction.conf(status=Accepted)
CP→CS: StatusNotification.req(status=Preparing)
CP→CS: StartTransaction.req(connectorId, idTag, meterStart, timestamp)
CS→CP: StartTransaction.conf(transactionId, idTagInfo.status=Accepted)

这与运营人员在后台仪表盘点击"远程启动"时使用的消息序列完全相同——司机端App只是同一后端函数的第二个调用者,只是把范围限定在了单个充电桩和单次会话上。


两种授权方式:RFID卡 vs App生成的ID标签

两种模式可以在同一个CSMS上并存,大多数生产环境部署也确实如此:

RFID卡 App生成的ID标签
单用户初始配置 邮寄或现场发放实体卡 无需配置——首次扫码时生成
授权发生位置 充电桩自带读卡器 后端生成后通过RemoteStart下发
适用场景 车队场站、员工、持有实体卡的常客 公共充电桩、酒店客人、一次性访客
撤销方式 停用卡片对应的id_tag记录 仅限单次会话,无需撤销操作
后端要求 存在匹配id_tag的用户记录 URL与充电桩的映射关系+RemoteStart调用

RFID路径需要一条User记录,其id_tag字段必须与卡片发送的字符串完全一致——未注册的标签会被直接拒绝。而App生成标签的路径则完全跳过了普通司机的用户记录环节:网页本身会生成一个仅限该次会话使用的一次性标签并自动注册。

对于大多数公共或半公共场景——酒店停车场、零售商户、公寓访客充电——App生成标签是更合适的默认方案,因为你不需要让一次性访客为了充二十分钟电而走完整套发卡流程。


完整的二维码流程

flowchart TD
    A["司机扫描充电桩上的二维码"] --> B["手机网页打开无需安装"]
    B --> C["如有多个接口则选择连接器"]
    C --> D["设置充电预算或自定义金额"]
    D --> E["App生成ID标签并调用RemoteStartTransaction"]
    E --> F["充电桩完成授权并启动会话"]
    F --> G["实时会话界面显示电量费用和时长"]
    G --> H["司机点击停止"]
    H --> I["系统生成收据"]

每个二维码只编码一个URL:充电桩ID以及可选的连接器编号,例如https://your-domain.com/ev?cp=CP_014&connector=2。这就是"安装App"这一步骤的全部内容——司机的手机相机识别后自动打开浏览器标签页。没有应用商店上架,没有审核排队,下个季度调整定价模型时也不需要强制推送更新。


后端需要构建的内容

在你很可能已经拥有的OCPP服务器基础上,需要构建三个部分:

1. 无状态的URL方案。 GET /ev?cp={charge_point_id}&connector={n}——在司机真正开始充电之前不需要会话令牌。这正是二维码所编码的内容,也是它可以打印并长期张贴的原因:URL永不过期或轮换,你不需要重新生成二维码。

2. 限定单个充电桩的RemoteStartTransaction接口。 司机点击"开始"后,后端生成一次性idTag(用UUID即可),将其注册到一条短生命周期的会话记录中,然后对URL中指定的充电桩调用RemoteStartTransaction。这直接复用了仪表盘已经在调用的远程启动逻辑,无需构建新的OCPP处理流程。

3. 用于实时会话界面的轮询或WebSocket推送。 在活跃交易期间,MeterValues.req消息每10到60秒从充电桩发送一次。将Energy.Active.Import.Register显示为累计kWh,再乘以电价即可实时展示费用。


立即体验

与其抽象地描述,我们直接构建了完整流程:输入充电桩ID,即可获得由真实演示CSMS实时生成的二维码和司机端App链接。

打开设置与二维码生成页 →

该页面内置中文界面,涵盖连接充电桩、申请WebSocket凭据、注册ID标签,以及——与本文最相关的部分——为任意充电桩ID生成司机端App链接和二维码,并可实时查看当前已连接的演示充电桩。


合规注意事项

即使是免安装的Web应用,仍然会收集数据——会话时长、供电量,以及(如涉及支付)交易记录。以下几点建议从一开始就纳入设计,而非事后补救:

  • 符合PIPL的数据最小化原则。 App生成的ID标签应仅限于单次会话,除非司机主动创建账户,否则不应与持久身份绑定。这能在设备丢失或会话产生争议时限制责任范围。
  • 收据留存。 涉及支付的交易记录通常需要在一定期限内可查询留存,建议在会话结束时通过邮件或短信发送收据,而不仅仅依赖浏览器内展示,尤其是在司机未注册账户的情况下。
  • 费率透明度。 在司机确认预算之前展示每kWh或每分钟的费率,而不是只在会话结束后展示总金额。

常见问题

用这种方案还需要原生App吗?
对于普通或公共充电场景不需要。基于Web的流程已覆盖会话的完整生命周期:开始、实时监控、停止、收据。只有当你需要离线排队、"充电完成"推送通知,或与司机账户绑定的持久积分/钱包系统时,原生App才值得投入开发。

如果司机在会话过程中关闭浏览器标签页会怎样?
充电会话本身不受影响——它在充电桩上持续运行,并由后端通过交易ID进行跟踪,与浏览器标签页的状态无关。重新打开同一个二维码编码的URL(或任何带有相同cpconnector参数的链接)即可重新连接到进行中的实时会话。

能否与面向注册车队司机的原生App共存?
可以。对拥有长期账户的注册用户使用RFID或原生App,对公共或访客充电使用二维码/Web流程,两者可运行在同一批充电桩和同一后端上。两条路径的区别仅在于idTag的生成和授权方式,底层的OCPP消息流程完全相同。

是否同时支持OCPP 1.6和2.0.1?
支持,但有一处差异:2.0.1使用RequestStartTransactionRequest而非RemoteStartTransaction.req,且ID令牌带有明确的type字段(如Central、ISO14443等),而非单纯的字符串。二维码加网页的模式本身与协议版本无关。


正在构建OCPP部署中司机端的部分,或想了解这如何融入完整的CSMS?我们正是在生产环境中运行这套技术栈。

体验实时演示——一分钟内生成真实二维码。

hello@simplico.net——我们通常在一个工作日内回复。

Simplico Co., Ltd. · 泰国曼谷 · 服务东盟及日本地区