OCPP
OCPP 驱动参考:内置的中央系统、充电桩证书、充电接口点位,以及 Meter/Status 的命名规则。
OCPP 驱动让 Ganter Lab 成为那些说 Open Charge Point Protocol 的电动汽车充电桩的中央系统。和 LoRaWAN 一样,方向是反过来的:不是工作站去连充电桩,而是充电桩通过一条 WebSocket 连到 Ganter Lab、自行注册,并把它的遥测数据推送进来。
内置的中央系统在第一台已启用的 OCPP 设备被载入正在跑的连接器时启动,在最后一台被移除或禁用时停下:一台充电桩都没配置时,端口上根本没有人在听。加一台就把它带回来,不必重启应用。你配置的每一台设备代表一台充电桩,由它连接时所用的那个 id 来标识。
中央系统与端口
| 项目 | 取值 |
|---|---|
| 协议版本 | OCPP 1.6、2.0、2.0.1 和 2.1(WebSocket 子协议协商;JSON) |
| 监听 | 所有接口,TCP 端口 19521,只走 TLS |
| 充电桩地址 | wss://<station-address>:19521/<charge-point-id> |
| 身份 | WebSocket 路径的最后一段就是充电桩的 id |
监听永远是 TLS;除了本地回环地址(它的存在只是为了进程内测试)之外,任何地方都拒绝明文 HTTP 的监听。充电桩用它的 BootNotification 自行注册(应答里给的心跳间隔是 60 秒),而每一张出示来做授权的卡都被接受:Ganter Lab 观察充电过程,它不管资费,也不管门禁。
证书
TLS 握手的服务器一侧出示的是应用自己的那份 OPC UA 证书。每一台充电桩都必须出示一份客户端证书:
- 它必须在这台 Windows 机器上构成一条有效的证书链,没有任何 TLS 策略错误;检查不通过就拒绝连接,诊断日志记下是哪一项检查没过。
- 它的主体通用名或者一个 DNS 主体备用名必须点名它连接时所用的那个充电桩 id。一份点名了另一台充电桩、而不是连接路径里那一台的证书会被拒绝。
没有客户端证书的握手,在任何数据流动之前就被丢掉。
连接字段
| 字段 | 它是什么 | 格式 | 默认值 |
|---|---|---|---|
| 标识符 | 这台设备所代表的那个充电桩 id:也就是充电桩放在它连接 URL 末尾、并写在它证书里的那个 id。 | 自由文本,比较时忽略大小写。留空就退回到规整过的设备名称。 | 空 |
没有主机、端口或凭据字段:连接的细节握在充电桩手里,本工作站只需要知道这台设备指的是哪一台充电桩。也没有轮询间隔字段。OCPP 是推送式的,充电桩按它自己的节奏发 MeterValues 和 StatusNotification 消息,而点位以固定的一秒周期从最近收到的数据里刷新。
因此,一台还没连上来的充电桩,或者一个还没报告过的充电接口,是没有读数,而不是读数失败。它的点位保持空,设备报告的是“什么都还没观察到”,而不是转为离线,也不会有失败写进诊断日志:这是一台刚配置好、还没到场的充电桩的正常状态。
点位
OCPP 的点位读的是这台充电桩的一个充电接口(OCPP 意义上的 connector:一个插枪位,从 1 开始编号)。存在两种点位,靠点位名称的后缀区分开,而这个后缀是要校验的:
| 点位名以什么结尾 | 读的是什么 | 合适的类型 |
|---|---|---|
Meter |
这个充电接口最近报告的那次采样电表值(OCPP MeterValues)。单位是充电桩发来的那个,通常是 Wh。服务器保留最近 10 次采样,点位读的是最新那一次。从没报告过的充电接口读作一个空值,不是零。 | Float 或 Double |
Status |
最近一次 StatusNotification 里那个充电接口的状态文字(例如 Available、Charging、Faulted)。 |
String |
两种后缀都没有的名字会被校验拒绝:请把点位命名成 Connector1Meter 和 Connector1Status 这样。
| 字段 | 作用 | 取值 | 默认值 |
|---|---|---|---|
| Connector | 这个点位读的是充电桩上的第几个充电接口。 | 1 或更大 | 1 |
| 数据类型 | 这个值对外暴露成的那个 OPC UA 类型。 | Int32、Float、Double、String | Float |
OCPP 的点位是只读的:读写字段不提供可写的选项,一次写入会被拒绝而不是被假装成功。给充电桩下命令是它自己的一套命令,下面就讲,不是往点位里写一个值。
命令
充电桩不只是被读,也会被下命令。每一台 OCPP 设备都在本工作站自己的 OPC UA 地址空间里,把下面这些命令作为设备上的方法带着,所以任何能调用方法的东西都能下发一条:一个 OPC UA 客户端,或者一个去调它的 Logic 动作。
每一条命令都以充电桩 id 作为它的第一个参数,并把充电桩自己的回答作为结果交回来。
| 命令 | 其余参数 | 作用 |
|---|---|---|
| ChangeAvailability | ConnectorId、Type(Operative 或 Inoperative) |
把一个充电接口投入或退出运行。 |
| 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)。 |
AttributeType 是 Actual、Target、MinSet、MaxSet 之一。
等那个回答。 工作站把命令发出去,这条命令并不算完。工作站会把这次调用一直挂着,直到充电桩回答的正是它发出去的那一条为止,靠随命令一起走的关联标识符来配对,然后才报告成功并把答复交回来。有三件事会以别的方式把它结束掉,每一种都作为失败连同原因一起报告:
- 充电桩没有连上,或者它的连接没有打开。什么都不会被发出去。
- 充电桩答的是一个 OCPP 错误,例如一条它没有实现的命令。错误码就是原因。
- 过了 30 秒还完全没有回答。没有人回答的命令是一次失败,绝不是成功。
为一台某个设备并不代表的、或者没有连上的充电桩下发的命令,会当场被拒绝,而不是排队等着。
设备发现
OCPP 驱动上的发现设备列出此刻连在中央系统上的那些充电桩,而读取一个候选项的通道,会为这台充电桩到目前为止报告过的每一个充电接口各提议一个 Meter 点位和一个 Status 点位。
第一台充电桩永远是手工配置的。 中央系统没在听之前什么都连不上,而它只有在这里存在一台 OCPP 设备之后才听,所以在一台充电桩都没配置的安装环境里做一次扫描,什么都找不到,而且它会这么说出来。请用充电桩将要连接时所用的那个 id 把第一台设备添加进来;此后,一台已经连上过的充电桩就能被发现了。一般的设备发现流程见 Connector 页面。
这个 id 在证书里、在连接路径里、以及和设备比对时都忽略大小写:一台以 cp-a 连上来、证书里写着 CP-A 的充电桩,和一台标识符写作 CP-A 的设备是同一台充电桩。