OCPP 1.6 のCS を作った話

こんにちは
まちゃです!

今回はアルバイトでOCPP 1.6 のCentral Server を作ったときの話をしていこうと思います〜

# OCPP とは

まずOCPP とは何なのかを話していきます！
OCPP はOpen Charge Point Protcol と呼ばれる電気自動車の充電器を制御するためのプロトコルです.

ざっくりと話すとこれだけですが, もう少し詳しく話していきます〜

## CS とCP

OCPP にはCS (Central System) とCP (Charge Point) が定義されています.
簡単に説明するとCP が充電器で, CS がCPを制御するためのシステムです.

図に起こすとこんな感じです

![ocpp_image.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199251/8a15cbbf-f7d4-6291-4133-490755d5ffc1.jpeg)


## Message

CS とCP が何かざっくりとわかったところで, 一体どのように制御しているのかと言うとメッセージを送り合うことで制御しています.
1つのメッセージにつきreq とconf が定義されており, req に対してconf でレスポンスを返すフローになってます.

図に起こすとこんな感じです

![ocpp-message.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199251/d0fb6256-8abc-319d-082c-80f22d3f300e.jpeg)

# OCPP の仕様

OCPP についてざっくりと説明したのでもう少し深堀していこうと思います！

## OCPP の種類

OCPP のバージョンは色々とあるのですが, その他にメッセージのフォーマットにも以下の種類があります.

- OCPP via JSON over WebSocket
- OCPP via SOAP

要するにJSON とSOAP です
今回作成したのはJSON の方なのでこっちしか触れません

## 通信方法

OCPP via JSON over WebSocket と書いてある通り, WebSocket での通信を行います
WebSocket ってなんじゃ？って方の為に軽く説明します

### WebSocket って何じゃ？

WebSocket はサーバとクライアントがコネクションを確立すると, その後の通信を専用プロトコルで行い, 双方向の通信が可能になる
要するに電話と同じです

電話をかけて相手が取ったらコネクション(接続)が確立され, どちらかが切断するまで喋り続ける事ができますよね
これを人ではなくサーバとクライアントにしたものがWebSocket の概要です

このWebSocketを使うことでOCPP は通信をしています
WebSocket を使用してるのでエンドポイントは以下のようになります

```
ws://ocpp_endpoint.dev/IDENTIFICATION_NUM
wss://ocpp_endpoint.dev/IDENTIFICATION_NUM
```

IDENTIFICATION_NUM にはCP 固有の文字列を入れて接続してくるのでこれを使って識別できます

## メッセージのフォーマット

OCPP ではリクエストとレスポンスでフォーマットが決まっています
が, OCPP の仕様書はすごい分かりにくい書き方がされています

![221107_193250.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199251/9ed1f986-eec6-0e16-6329-1fbecb1e5d50.png)

Direction が書いてありますが, Server-to-Client のCALL もあります
ってことでこれは嘘つきですw
じゃあどうなってるかというと先程ちらっと言った通りCALL がリクエストでCALLRESULT がレスポンスです
ただし, CALL が仕様通りでなかった場合CALLERROR を使用します

メッセージのタイプがわかったところでそれぞれのフォーマットについて書いていきます

### CALL

CALL のフォーマットは

```json: CallFormat.req
[
    2,
    "UNIQUE_ID",
    "MESSAGE_NAME",
    {
        "PAYLOAD"
    }
]
```

となってます
ちなみにMESSAGE_NAME はOCPP 上ではAction と定義されてますがこっちの方がわかりやすいと思うので
これだけだとイメージがあまりつかめないと思うので実際に使用できる例を書いていきます

```json: BootNotifiction.req
[
    2,
    "12345678",
    "BootNotification",
    {
        "chargePointModel": "Sample",
        "chargePointVender": "Sample"
    }
]
```

今回の例はOCPP で必須とされている項目しか書いていません
また, ユニークID を数字で書いてますが一意であれば文字列でも問題ないので対応できるように開発する必要があります

### CALLRESULT

CALLRESULT のフォーマットは

```json: CallResultFormat.conf
[
    3,
    "UNIQUE_ID",
    {
        "PAYLOAD"
    }
]
```

となってます
注意すべきなのは, CALLRESULT はCALL の返答という意味があるのでユニークID はCALL で使用されたものを使用しなければいけません
そしてMESSAGE_NAME は付けてはいけません

フォーマットがわかったところでCALL の例として上げたBootNotification にレスポンスを返す形で例を書きます

```json: BootNotification.conf
[
    3,
    "12345678",
    {
        "currentTime": "2022-11-08T10:17:48:1234Z",
        "interval": "86400",
        "status": "Accepted"
    }
]
```

こんな感じで返すことでBootNotification のやり取りができます

### CALLERROR

正常な動作がわかったところで次はエラー時のレスポンスについて書いていきます
CALLERROR のフォーマットは

```json: CallErrorForat
[
    4,
    "UNIQUE_ID",
    "ERROR_CODE",
    "ERROR_DESCRIPTION",
    "ERROR_DETAILS"
]
```

となっています
例としてBootNotification にCS が対応していなかった場合のエラーを書いていきます

```json: CallError.conf
[
    4,
    "12345678",
    "NotSupported",
    "",
    {}
]
```

こんな感じになります
ERROR_DESCRIPTION とERROR_DETAILS に関してはこの状態でも問題はありませんが, 後々大変になるので何かしら入れてあげるとよいですね〜

## CS とCP の接続開始時

ここまでで接続方法とメッセージのやり取りがわかったと思うので最後に充電を始められる状態, いわゆる待機状態になるまでのフローを書いていきたいと思います

OCPP に定義されているものは2つのメッセージが必要となっています
- BootNotification
- StatusNotification

ただしCP の仕様によっては他のメッセージも送ってくる可能性があるので確認が必要です

この処理を図で起こすと
![ocpp-BootFlow.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199251/5477bb4d-2a5c-aa95-d966-5b153d379046.jpeg)

# さいごに

これでOCPP での接続〜待機状態までは終了です
この後にStartTransaction を送ると充電が開始されます (CS, CP の仕様によって変わるが)
各メッセージについては触れませんでしたが, BootNotification の例と同じように書いてあげればいけるので頑張って下さい！

**れっつ OCPP らいふ！！**

## 余談

OCPP の仕様書を読むと分かりにくいと思ったはずです
それもそのはず
聞いた話ですが, 原本はドイツ語なのだそう
それを英語に翻訳して読んでいるのですからそりゃ分かりづらいですよねw

# 文献

[Open Charge Alliance](https://www.openchargealliance.org/)
[今さら聞けないWebSocket~WebSocketとは~](https://qiita.com/chihiro/items/9d280704c6eff8603389)