# OCPP 协议网关

[OCPP](https://www.openchargealliance.org/)（开放充电点协议）是一种开放的通信协议，用于连接充电站与中央管理系统，旨在为电动汽车充电基础设施提供统一的通信标准。OCPP 网关作为协议转换器，桥接 OCPP 与 MQTT 协议，让使用这两种协议的客户端能够互相通信。

EMQX Cloud 提供了对 [OCPP 1.6-J](https://www.openchargealliance.org/protocols/ocpp-16/) 的协议网关支持，可连接符合 OCPP 规范的各品牌充电桩设备。它通过规则引擎、数据集成、REST API 等方式与中央管理系统（Central System）集成，帮助用户快速构建电动汽车充电基础设施。

本页面介绍如何在 EMQX Cloud 中配置和使用 OCPP 网关。

## 基本设置

要配置 OCPP 网关的基本参数，请点击**操作**栏中的**设置**按钮。

- **挂载点**：添加到所有 MQTT 发布/订阅主题前缀的字符串，用于实现不同协议之间的消息路由隔离。默认值：`ocpp/`。
- **默认心跳间隔**：充电桩发送心跳消息的默认时间间隔。默认值：`60s`。
- **心跳定时器检查退避**：心跳超时检测的退避倍数。默认值：`1`。
- **消息格式检查**：是否启用上传和下行消息的 JSON Schema 格式校验。当消息格式不符合规范时，EMQX 将回复对应的应答消息。选项包括：
  - `all`：校验所有消息；
  - `upstream_only`：仅校验上行（上传）消息；
  - `dnstream_only`：仅校验下行（下载）消息；
  - `disable`：不校验任何消息。
- **JSON Schema ID 前缀**：用于标识 OCPP JSON Schema 文档的前缀。默认值：`urn:OCPP:1.6:2019:12:`。
- **空闲超时时间**：网关在连接空闲多少秒后关闭连接。
- **上行数据流**（充电桩 -> EMQX）配置：
  - **主题**：上行 Call Request 消息的主题，默认：`cp/${cid}`；
  - **回复主题**：上行回复消息的主题，默认：`cp/${cid}/Reply`；
  - **错误主题**：上行错误消息的主题，默认：`cp/${cid}/Reply`；
  - **主题映射**：根据消息名称设置的上行主题覆盖映射。
- **下行数据流**（EMQX -> 充电桩）配置：
  - **主题**：接收来自 EMQX 的控制/请求消息的下行主题。该值为通配符主题，所有已连接充电桩都会订阅。默认值：`cs/${cid}`；
  - **最大消息队列长度**：下行消息传递的最大队列长度。默认值：`100`。

## 认证机制

虽然 OCPP 1.6-J 本身未定义内置的认证机制，但在 WebSocket 握手阶段使用 HTTP 基本认证进行客户端认证已成为常见实践。EMQX OCPP 网关采用此方式，在充电桩连接时提取客户端认证信息。

网关会从连接请求中提取以下信息：

- **客户端 ID**：从 WebSocket 连接路径中提取，位于固定路径前缀之后（例如：`/ocpp/chargePointSim` -> `chargePointSim`）。
- **用户名**和**密码**：从 HTTP 基本认证的 `Authorization` 请求头中解码获得。

提取后的认证信息将与 EMQX Cloud 控制台中 **OCPP -> 认证**页面中配置的认证信息进行匹配。

> 若要允许客户端连接，需先在该页面添加对应的用户名和密码。

## 使用 OCPP 客户端工具测试网关

在 OCPP 网关启动后，你可以使用 OCPP 客户端工具进行连接测试，以验证配置是否正确。本节以开源工具 [ocpp-js](https://github.com/0721Betty/ocpp-js) 为例，演示如何模拟一个充电桩并测试连接。

1. 启动一个 MQTT 客户端（如 [MQTTX](https://mqttx.app/zh/downloads)）以监控通过 OCPP 网关交换的消息。

   - 将 MQTTX 连接到你的 EMQX 部署；
   - 订阅通配符主题：`ocpp/#`。

   这样你就可以观察所有 OCPP 相关的 MQTT 消息了。

   <img src="./_assets/ocpp-mqttx-create-conn.png" alt="ocpp-mqttx-create-conn" style="zoom:67%;" />

2. 克隆并安装 `ocpp-js` 客户端：

   ```shell
   git clone https://github.com/0721Betty/ocpp-js.git
   cd ocpp-js
   npm install
   ```

3. 配置环境变量。复制模板并填写实际配置信息：

   ```shell
   cp env.template .env.local
   ```

   编辑 `.env.local` 文件：

   ```bash
   OCPP_USERNAME=your_username
   OCPP_PASSWORD=your_password
   OCPP_CLIENT_ID=chargePointSim
   EMQX_CLOUD_DEPLOYMENT_ADDRESS=your_deployment_address
   ```

   ::: tip 提示

   - 部署地址可在控制台的部署**概览**页面查看；
   - 用户名与密码需与 **OCPP -> 认证**页面中配置的认证信息保持一致。

   :::

4. 启动 OCPP 客户端连接网关：

   ```shell
   npm start
   ```

   或使用 Node.js 直接运行：

   ```shell
   node client.js
   ```

   如果连接成功，将看到如下日志输出：

   ```bash
   Connected to Central System
   Client ID: chargePointSim
   Username: your_username
   Sending: ......
   ```

5. 在 MQTTX 中，你将收到如下消息，主题为 `ocpp/cp/chargePointSim`：

   ```json
   Topic: ocpp/cp/chargePointSim
   {
     "UniqueId": "1200012677",
     "Payload": {
       "chargePointVendor": "vendor1",
       "chargePointModel": "model1"
     },
     "Action": "BootNotification"
   }
   ```

   这表明模拟的充电桩已连接并发送了 `BootNotification` 启动消息。

6. 使用 MQTTX 向主题 `ocpp/cs/chargePointSim` 发送响应消息。请将 `UniqueId` 替换为上一步中收到的 ID：

   ::: tip

   `UniqueId` 必须与前一条 `BootNotification` 消息中的值一致。

   :::

   ```json
   {
     "MessageTypeId": 3,
     "UniqueId": "***",
     "Payload": {
       "currentTime": "2023-12-01T14:20:39+00:00",
       "interval": 300,
       "status": "Accepted"
     },
     "Action": "BootNotification"
   }
   ```

7. 成功响应后，你将会在 MQTTX 中收到如下 `StatusNotification` 状态上报消息：

   ```json
   Topic: ocpp/cp/chargePointSim
   Payload:
   {
     "UniqueId": "3062609974",
     "Payload": {
       "status": "Available",
       "errorCode": "NoError",
       "connectorId": 0
     },
     "MessageTypeId": 2,
     "Action": "StatusNotification"
   }
   ```

   这表明 OCPP 客户端已成功与网关建立通信并完成状态上报。

## 客户端管理

在 OCPP 页面中的**客户端**标签页下，你可以查看当前所有已连接的 OCPP 客户端的基本信息。在**操作**栏中，你可以选择断开某个客户端的连接。

![ocpp_client](./_assets/ocpp_client.png)