OCPP
OCPP 驱动参考:内置的中央系统、充电桩证书、充电接口点位,以及 Meter、Status、Transaction 的命名规则。
OCPP 驱动让 Ganter Lab 成为那些说 Open Charge Point Protocol 的电动汽车充电桩的中央系统。和 LoRaWAN 一样,方向是反过来的:不是工作站去连充电桩,而是充电桩通过一条 WebSocket 连到 Ganter Lab、自行注册,并把它的遥测数据推送进来。
内置的中央系统在第一台已启用的 OCPP 设备被载入正在跑的连接器时启动,在最后一台被移除或禁用时停下:一台充电桩都没配置时,端口上根本没有人在听。加一台就把它带回来,不必重启应用。你配置的每一台设备代表一台充电桩,由它连接时所用的那个 id 来标识。
准备充电桩
是充电桩主动连接本工作站,而它出厂时并不知道工作站在哪里。每台 OCPP 设备的页面上都有一张“准备充电桩”卡片,按本工作站写好要填入充电桩 OCPP 设置的内容:
| 要在充电桩上设置的 | 卡片给出的 |
|---|---|
| 中央系统地址 | wss://<地址>:19521/<充电桩 id>,先是以本工作站名称写成的地址(内置 OPC UA 服务器配置中的“网络名称”,为空时是计算机名),然后是本工作站在网络上的每个 IPv4 地址各一条,每条带一个复制按钮。会核对服务器名称的充电桩需要按名称写的地址;不核对的充电桩接受其中任何一个,这时用与它同一网络的那个地址即可。 |
| 充电桩标识 | 设备的“标识符”;它为空时,就是工作站给设备起的名字。很多充电桩会自己把标识加到地址后面:对这类充电桩,地址只填到端口为止,标识填在它自己的栏位里。 |
| 安全 | 使用客户端证书的 TLS,即 OCPP 所说的安全配置文件 3。没有客户端证书的配置文件 1 和 2 不被接受。充电桩的证书在通用名称或 DNS 备用名称中写有它的标识(见证书)。 |
| 中央系统的根证书 | 本工作站根证书 GanterLabConnector-<station>.pem 的完整路径,充电桩安装它来信任中央系统;“打开文件夹”按钮会在 Windows 文件资源管理器中显示这个文件。按钮在工作站自己的窗口里起作用;在其他设备的浏览器里它保持灰色并说明原因。 |
工作站打开以来充电桩还没有连上过时,卡片是展开的;连上之后它会收起,但留在页面上,供下次设置充电桩时使用。证书没有任何 Windows 中已安装的根证书担保的充电桩,首次连接时会被拒绝,并在现场设备访问中等待。
文件在登记了充电桩、中央系统第一次启动时写出,在此之前卡片会说明这一点。本工作站所有充电桩用的是同一个文件,工作站的名称或地址变了,它也不变(见工作站的根证书)。
凡是拿到过旧版本文件的充电桩,都需要装上这个文件一次。 这个版本第一次启动时,如果工作站上的充电桩可能持有旧文件,卡片上会出现一条通知“本工作站的文件已更换”,只在那一次运行中显示。通知只是提醒,不是操作说明本身:对原来就有充电桩的工作站,不论卡片是否显示这条通知,都要在每台充电桩上把新文件装一次。会核对服务器名称的充电桩从此就会接受本工作站。
中央系统与端口
| 项目 | 取值 |
|---|---|
| 协议版本 | 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 握手的服务器一侧出示的是由本工作站自己的根证书签发的证书(见工作站的根证书)。每一台充电桩都必须出示一份客户端证书:
- 它必须以两种方式之一得到信任:在这台 Windows 机器上构成一条直到其中已安装的根证书的有效证书链,没有任何 TLS 策略错误;或者你已经在这个驱动页面的现场设备访问中批准了这份证书本身(见下文)。无论哪种方式,它都必须在有效期之内。检查不通过就拒绝连接,诊断日志记下是哪一项检查没过。
- 它的主体通用名或者一个 DNS 主体备用名必须点名它连接时所用的那个充电桩 id。一份点名了另一台充电桩、而不是连接路径里那一台的证书会被拒绝,即使它已获批准。
没有客户端证书的握手,在任何数据流动之前就被丢掉。
工作站的根证书
| 项目 | 内容 |
|---|---|
| 根证书 | 每个配置档案只创建一次,在中央系统或 LoRaWAN 网络服务器第一次启动时。它的主题是 Ganter Lab Connector (<station>),其中 <station> 是当天的网络名称。它永不过期,也不会自行更换:改计算机名、改网络名称或改工作站的地址,它都不变。 |
| 文件 | GanterLabConnector-<station>.pem,只含公开部分,位于数据文件夹的 ua\pki\station 下。充电桩和 LoRaWAN 网关用的是同一个文件,网关把它安装为 tc.trust。 |
| 中央系统出示的证书 | 由这个根证书签发。它写明工作站的网络名称(内置 OPC UA 服务器配置中的“网络名称”,为空时是计算机名)、localhost 和工作站的每个 IPv4 地址,所以会核对服务器名称的充电桩(安全配置文件 3)也接受它。网络名称或某个地址变了,只有这份证书会自动重新签发,充电桩上无需做任何事。 |
| OPC UA 服务器的证书 | 此处不使用。内置的 OPC UA 服务器保留它自己的证书,供 OPC UA 客户端使用。 |
已保存的根证书如果再也打不开(例如是另一个 Windows 账户写入的),会被一个新的根证书取代。这时每台充电桩都需要新文件一次,卡片会说明这一点。
现场设备访问
如果一台充电桩的证书是自签名的,或者由制造商自己的证书颁发机构签发,因而没有任何 Windows 中已安装的根证书为它担保,也不需要把那个根证书安装到这台电脑上。它的第一次连接会被拒绝,它的证书在 OCPP 驱动页面末尾的现场设备访问里等待你的决定,这和 OPC UA 驱动页面上的是同一张卡片。
| 分组 | 列出的内容 | 你能做的事 |
|---|---|---|
| 等待批准 | 每一份被拒绝的证书,列在它连接时所用的充电桩 id 之下:它的 SHA-256 指纹、最近一次尝试的时间和尝试次数,以及它的详细信息(主体、颁发者、域名、有效期)。 | 批准从充电桩的下一次连接起接纳这份证书。阻止继续拒绝它,且不再把它列到这里。丢弃所有待处理的证书清空列表,不批准也不阻止任何东西。 |
| 已批准的现场设备 | 你批准过或导入过的证书,并注明是谁、在什么时候做的决定。 | 撤回批准关闭充电桩的连接,并把它的证书放回列表。导入证书在充电桩第一次连接之前就批准它的公开证书。 |
| 被阻止的现场设备 | 你阻止过的证书。被阻止的证书即使 Windows 信任它也会被拒绝。 | 解除阻止把证书放回列表,但不批准它。 |
批准的是一份一份的证书,从来不是签发它的证书颁发机构,所以同一制造商的第二台充电桩要等待它自己的批准。批准之前,先把指纹和充电桩报出的指纹核对一遍。批准不会改变这份证书是哪一台充电桩:它仍然只以它点名的那个充电桩 id 被接纳,而且只在有效期之内。Windows 已经信任的证书照旧被接纳,从不出现在这里;没有任何东西会被自动批准。
这些决定保存在工作站数据文件夹的 ua\pki\ocpp 下,重启后依然保留。只有可以配置 Connector 的角色才会看到这些命令,而且它们只在工作站自己的窗口里起作用:另一台设备上的浏览器只能读这张卡片,不能修改;也没有任何代理工具能批准证书。列表最多保存 100 份等待批准的证书;列表满了以后,新的证书仍会被拒绝,但不会列出,卡片会说明这一点。
连接字段
| 字段 | 它是什么 | 格式 | 默认值 |
|---|---|---|---|
| 标识符 | 这台设备所代表的那个充电桩 id:也就是充电桩放在它连接 URL 末尾、并写在它证书里的那个 id。 | 自由文本,比较时忽略大小写。留空就退回到规整过的设备名称。 | 空 |
没有主机、端口或凭据字段:连接的细节握在充电桩手里,本工作站只需要知道这台设备指的是哪一台充电桩。也没有轮询间隔字段。OCPP 是推送式的,充电桩按它自己的节奏发 MeterValues 和 StatusNotification 消息,而点位以固定的一秒周期从最近收到的数据里刷新。
因此,一台还没连上来的充电桩,或者一个还没报告过的充电接口,是没有读数,而不是读数失败。它的点位保持空,也不会有失败写进诊断日志:充电桩还没发来的点位,正是协议在正常工作。
充电桩的健康状态
充电桩有了点位才发过来,所以光凭点位没有动静,分不清一台还没报告的充电桩和一台已经不在的充电桩。它的健康状态,也就是它在树里那一行上的圆点和驱动页面上的健康状态一列,改为跟随它与本工作站中央系统的连接:
| 情况 | 健康状态 |
|---|---|
| 已配置,自工作站打开以来一直没连上来 | 离线 |
| 已连上,还什么都没发 | 在线 |
| 已连上,正在发送 | 在线;它发来的点位有一部分读不出来时为部分在线 |
| 掉线了:停了、断电了或者和网络断开了 | 离线,直到它重新连上 |
| 中央系统没在监听 | 离线 |
| 已禁用 | 已禁用 |
充电桩连着的时候,一个还没报告过的充电接口不会拉低它的状态。充电桩的改动保存之后,或者 Connector 启动之后,最多十秒内它读作尚未可知:重新放入设备可能会让中央系统重启,充电桩要过一会儿才能重新连上。
点位
OCPP 的点位读的是这台充电桩的一个充电接口(OCPP 意义上的 connector:一个插枪位,从 1 开始编号)。在 OCPP 2.0、2.0.1 和 2.1 里,这个编号是 EVSE 的编号,因为那里的充电接口在每个 EVSE 内部又从 1 开始编号。存在三种点位,靠点位名称的后缀区分开,而这个后缀是要校验的:
| 点位名以什么结尾 | 读的是什么 | 合适的类型 |
|---|---|---|
Meter |
这个充电接口最近报告的那次采样电表值(OCPP MeterValues;在 OCPP 2.x 里,还包括充电过程中 TransactionEvent 带来的值)。单位是充电桩发来的那个,通常是 Wh。服务器保留最近 10 次采样,点位读的是最新那一次。从没报告过的充电接口读作一个空值,不是零。 | Float 或 Double |
Status |
最近一次 StatusNotification 里那个充电接口的状态文字(例如 Available、Faulted)。在 OCPP 2.x 里,有多个充电接口的 EVSE 读作其中最能说明情况的那个:Faulted 优先于 Occupied,Occupied 优先于 Reserved,Reserved 优先于 Available,Available 优先于 Unavailable。还没报告过状态的 EVSE 读作一个空值。 |
String |
Transaction |
这个充电接口上正在进行的事务的编号,也就是 RemoteStopTransaction 和 GetTransactionStatus 两个命令要的那个编号:OCPP 1.6 里是事务开始时本工作站给它的编号,OCPP 2.x 里是充电站自己的标识,照它发来的原样读出。事务开始时填上,结束时清空,所以没有事务在进行时读到的是空文本。充电桩连上之后、第一次有事务开始或结束之前,它读作空值,因为可能早已有事务在进行。 | String |
这几种后缀都没有的名字会被校验拒绝:请把点位命名成 Connector1Meter、Connector1Status 和 Connector1Transaction 这样。
| 字段 | 作用 | 取值 | 默认值 |
|---|---|---|---|
| Connector | 这个点位读的编号:OCPP 1.6 里是充电接口的编号,OCPP 2.x 里是 EVSE 的编号。 | 1 或更大 | 1 |
| 数据类型 | 这个值对外暴露成的那个 OPC UA 类型。 | Int32、Float、Double、String | Float |
OCPP 的点位是只读的:读写字段不提供可写的选项,一次写入会被拒绝而不是被假装成功。给充电桩下命令是它自己的一套命令,下面就讲,不是往点位里写一个值。
命令
充电桩不只是被读,也会被下命令。每一台 OCPP 设备都在本工作站自己的 OPC UA 地址空间里,把下面这些命令作为设备上的方法带着,所以连接到本工作站的 OPC UA 客户端调用该方法,就能下发一条命令。
每一条命令都以充电桩 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 | 设一个充电功率上限,单位是瓦。ConnectorId 为 0 时限制整台充电桩;其他编号为该充电接口所充的会话设默认上限。 |
| SetVariables | ComponentName、VariableName、AttributeType、AttributeValue | 设某个组件的某一个变量(OCPP 2.x)。 |
| GetVariables | ComponentName、VariableName、AttributeType | 读某个组件的某一个变量(OCPP 2.x)。 |
AttributeType 是 Actual、Target、MinSet、MaxSet 之一。
TransactionId 从哪里来。 RemoteStopTransaction 和 GetTransactionStatus 作用于一次事务,用它的编号来指明。这个编号从会话所在充电接口(OCPP 2.x 里是 EVSE)的 Transaction 点位读出来,比如 Connector1Transaction,读到什么就原样传什么。那里是空文本,就说明这个充电接口上没有事务在进行。
一份命令表,适用于每个版本。 不论充电桩讲的是哪个版本,这些命令都沿用上面的名字,工作站按该版本规定的格式发送每一条。在 OCPP 2.0、2.0.1 和 2.1 里,充电接口归在 EVSE 之下,作为 ConnectorId 传入的编号指的是 EVSE。
| 命令 | 在 OCPP 1.6 上 | 在 OCPP 2.0、2.0.1 和 2.1 上 |
|---|---|---|
| ChangeAvailability | 作用于给定的充电接口;0 表示整台充电桩。 | 作用于给定的 EVSE;0 表示整个充电站。 |
| RemoteStartTransaction | 发送 IdTag,由充电桩选择充电接口。 | 以 RequestStartTransaction 发出,IdTag 作为中心令牌,并带上自己的启动编号;由充电站选择 EVSE。 |
| RemoteStopTransaction | TransactionId 是会话开始时本工作站给这次会话的编号。 | 以 RequestStopTransaction 发出;TransactionId 是充电站自己的标识,原样以文本传过去。 |
| Reset | 硬重启。 | 立即重启。 |
| UnlockConnector | 解锁给定的充电接口。 | 解锁给定 EVSE 的第一个充电接口。 |
| SetChargingProfile | 0 设充电桩的最大配置文件;其他充电接口得到一个默认配置文件。 | 0 设充电站的最大配置文件;其他 EVSE 得到一个默认配置文件。 |
| ChangeConfiguration、GetConfiguration | 同上表。 | 不属于这些版本:充电站会回一个错误,命令失败。 |
| GetTransactionStatus、SetVariables、GetVariables | 不属于这个版本:充电桩会回一个错误,命令失败。 | 同上表。 |
等那个回答。 工作站把命令发出去,这条命令并不算完。工作站会把这次调用一直挂着,直到充电桩回答的正是它发出去的那一条为止,靠随命令一起走的关联标识符来配对,然后才报告成功并把答复交回来。有三件事会以别的方式把它结束掉,每一种都作为失败连同原因一起报告:
- 充电桩没有连上,或者它的连接没有打开。什么都不会被发出去。
- 充电桩答的是一个 OCPP 错误,例如一条它没有实现的命令。错误码就是原因。
- 过了 30 秒还完全没有回答。没有人回答的命令是一次失败,绝不是成功。
为一台某个设备并不代表的、或者没有连上的充电桩下发的命令,会当场被拒绝,而不是排队等着。
设备发现
OCPP 驱动上的发现设备列出此刻连在中央系统上的那些充电桩,而读取一个候选项的通道,会为这台充电桩到目前为止报告过的每一个充电接口各提议一个 Meter 点位、一个 Status 点位和一个 Transaction 点位。
第一台充电桩永远是手工配置的。 中央系统没在听之前什么都连不上,而它只有在这里存在一台 OCPP 设备之后才听,所以在一台充电桩都没配置的安装环境里做一次扫描,什么都找不到,而且它会这么说出来。请用充电桩将要连接时所用的那个 id 把第一台设备添加进来;此后,一台已经连上过的充电桩就能被发现了。一般的设备发现流程见 Connector 页面。
这个 id 在证书里、在连接路径里、以及和设备比对时都忽略大小写:一台以 cp-a 连上来、证书里写着 CP-A 的充电桩,和一台标识符写作 CP-A 的设备是同一台充电桩。
已经有的充电桩可以在自己的页面上重新读它的充电接口:“点位”卡片标题栏里的发现点位列出它连接期间报告过的每个充电接口的 Meter、Status 和 Transaction 点位中设备还没有的那些(见发现一台设备的点位)。