OCPP

OCPP 驱动参考:内置的中央系统、充电桩证书、充电接口点位,以及 Meter/Status 的命名规则。

以 Markdown 查看

OCPP 驱动让 Ganter Lab 成为那些说 Open Charge Point Protocol 的电动汽车充电桩的中央系统。和 LoRaWAN 一样,方向是反过来的:不是工作站去连充电桩,而是充电桩通过一条 WebSocket 连到 Ganter Lab、自行注册,并把它的遥测数据推送进来。

内置的中央系统在第一台已启用的 OCPP 设备被载入正在跑的连接器时启动,在最后一台被移除或禁用时停下:一台充电桩都没配置时,端口上根本没有人在听。加一台就把它带回来,不必重启应用。你配置的每一台设备代表一台充电桩,由它连接时所用的那个 id 来标识。

中央系统与端口

项目 取值
协议版本 OCPP 1.62.02.0.12.1(WebSocket 子协议协商;JSON)
监听 所有接口,TCP 端口 19521,只走 TLS
充电桩地址 wss://<station-address>:19521/<charge-point-id>
身份 WebSocket 路径的最后一段就是充电桩的 id

监听永远是 TLS;除了本地回环地址(它的存在只是为了进程内测试)之外,任何地方都拒绝明文 HTTP 的监听。充电桩用它的 BootNotification 自行注册(应答里给的心跳间隔是 60 秒),而每一张出示来做授权的卡都被接受:Ganter Lab 观察充电过程,它不管资费,也不管门禁。

证书

TLS 握手的服务器一侧出示的是应用自己的那份 OPC UA 证书。每一台充电桩都必须出示一份客户端证书

  1. 它必须在这台 Windows 机器上构成一条有效的证书链,没有任何 TLS 策略错误;检查不通过就拒绝连接,诊断日志记下是哪一项检查没过。
  2. 它的主体通用名或者一个 DNS 主体备用名必须点名它连接时所用的那个充电桩 id。一份点名了另一台充电桩、而不是连接路径里那一台的证书会被拒绝。

没有客户端证书的握手,在任何数据流动之前就被丢掉。

连接字段

字段 它是什么 格式 默认值
标识符 这台设备所代表的那个充电桩 id:也就是充电桩放在它连接 URL 末尾、并写在它证书里的那个 id。 自由文本,比较时忽略大小写。留空就退回到规整过的设备名称。

没有主机、端口或凭据字段:连接的细节握在充电桩手里,本工作站只需要知道这台设备指的是哪一台充电桩。也没有轮询间隔字段。OCPP 是推送式的,充电桩按它自己的节奏发 MeterValues 和 StatusNotification 消息,而点位以固定的一秒周期从最近收到的数据里刷新。

因此,一台还没连上来的充电桩,或者一个还没报告过的充电接口,是没有读数,而不是读数失败。它的点位保持空,设备报告的是“什么都还没观察到”,而不是转为离线,也不会有失败写进诊断日志:这是一台刚配置好、还没到场的充电桩的正常状态。

点位

OCPP 的点位读的是这台充电桩的一个充电接口(OCPP 意义上的 connector:一个插枪位,从 1 开始编号)。存在两种点位,靠点位名称的后缀区分开,而这个后缀是要校验的:

点位名以什么结尾 读的是什么 合适的类型
Meter 这个充电接口最近报告的那次采样电表值(OCPP MeterValues)。单位是充电桩发来的那个,通常是 Wh。服务器保留最近 10 次采样,点位读的是最新那一次。从没报告过的充电接口读作一个空值,不是零。 Float 或 Double
Status 最近一次 StatusNotification 里那个充电接口的状态文字(例如 AvailableChargingFaulted)。 String

两种后缀都没有的名字会被校验拒绝:请把点位命名成 Connector1MeterConnector1Status 这样。

字段 作用 取值 默认值
Connector 这个点位读的是充电桩上的第几个充电接口。 1 或更大 1
数据类型 这个值对外暴露成的那个 OPC UA 类型。 Int32、Float、Double、String Float

OCPP 的点位是只读的:读写字段不提供可写的选项,一次写入会被拒绝而不是被假装成功。给充电桩下命令是它自己的一套命令,下面就讲,不是往点位里写一个值。

命令

充电桩不只是被读,也会被下命令。每一台 OCPP 设备都在本工作站自己的 OPC UA 地址空间里,把下面这些命令作为设备上的方法带着,所以任何能调用方法的东西都能下发一条:一个 OPC UA 客户端,或者一个去调它的 Logic 动作。

每一条命令都以充电桩 id 作为它的第一个参数,并把充电桩自己的回答作为结果交回来。

命令 其余参数 作用
ChangeAvailability ConnectorId、Type(OperativeInoperative 把一个充电接口投入或退出运行。
ChangeConfiguration Key、Value 在充电桩上设一个配置键(OCPP 1.6)。
ClearCache 清掉充电桩的授权缓存。
GetConfiguration Key 读一个配置键(OCPP 1.6)。
RemoteStartTransaction IdTag 为一个令牌启动一次充电会话。
RemoteStopTransaction TransactionId 停掉一次正在进行的会话。
GetTransactionStatus TransactionId 问一次事务是不是还在进行(OCPP 2.x)。
Reset 重启充电桩。
UnlockConnector ConnectorId 从一个充电接口上把电缆解锁放开。
SetChargingProfile ConnectorId、Limit、NumberOfPhases 设一个充电功率上限。
SetVariables ComponentName、VariableName、AttributeType、AttributeValue 设某个组件的某一个变量(OCPP 2.x)。
GetVariables ComponentName、VariableName、AttributeType 读某个组件的某一个变量(OCPP 2.x)。

AttributeTypeActualTargetMinSetMaxSet 之一。

等那个回答。 工作站把命令发出去,这条命令并不算完。工作站会把这次调用一直挂着,直到充电桩回答的正是它发出去的那一条为止,靠随命令一起走的关联标识符来配对,然后才报告成功并把答复交回来。有三件事会以别的方式把它结束掉,每一种都作为失败连同原因一起报告:

  • 充电桩没有连上,或者它的连接没有打开。什么都不会被发出去。
  • 充电桩答的是一个 OCPP 错误,例如一条它没有实现的命令。错误码就是原因。
  • 过了 30 秒还完全没有回答。没有人回答的命令是一次失败,绝不是成功。

为一台某个设备并不代表的、或者没有连上的充电桩下发的命令,会当场被拒绝,而不是排队等着。

设备发现

OCPP 驱动上的发现设备列出此刻连在中央系统上的那些充电桩,而读取一个候选项的通道,会为这台充电桩到目前为止报告过的每一个充电接口各提议一个 Meter 点位和一个 Status 点位。

第一台充电桩永远是手工配置的。 中央系统没在听之前什么都连不上,而它只有在这里存在一台 OCPP 设备之后才听,所以在一台充电桩都没配置的安装环境里做一次扫描,什么都找不到,而且它会这么说出来。请用充电桩将要连接时所用的那个 id 把第一台设备添加进来;此后,一台已经连上过的充电桩就能被发现了。一般的设备发现流程见 Connector 页面。

这个 id 在证书里、在连接路径里、以及和设备比对时都忽略大小写:一台以 cp-a 连上来、证书里写着 CP-A 的充电桩,和一台标识符写作 CP-A 的设备是同一台充电桩。