EV

作らなくていいEVドライバーアプリ:OCPP IDタグによるQRコード充電

OCPPのチュートリアルはたいてい、充電器とバックエンドの通信方法を説明する。だが、ドライバーがどうやってシステムに入るかを説明するものはほとんどない。

Flask、WebSocket、MongoDBを使ってOCPP 1.6中央システムを構築するという記事を読んだことがあれば、充電器とバックエンドの通信については馴染みがあるはずだ。本記事は、そこでよく見落とされるもう半分を補完する。

EVドライバー向けアプリを計画するチームの多くは「ネイティブアプリを作ろう」という発想から始める。しかしこれは静かにプロジェクト最大のコスト項目になっていく。二つのコードベース、アプリストアの審査サイクル、料金体系が変わるたびの強制アップデート、そして一度きりの利用のためにダウンロードすることを面倒に感じるドライバーの離脱——。

もっとシンプルなパターンがあり、私たちは実際にこれを本番環境で運用している。充電器のQRコードがモバイルWebページを開く方式だ。インストール不要、アカウント登録不要で、ドライバーは4タップ以内に充電を開始できる。この記事では、これがOCPP上でどう動くのか、バックエンドが実際に何を構築する必要があるのか、そして今すぐ本物のQRコードを生成できるライブデモを紹介する。


目次

  1. OCPPにおけるドライバー認証の位置づけ
  2. 2つの認証方式:RFID vs アプリ生成IDタグ
  3. QRコードフローの全体像
  4. バックエンドが構築すべきもの
  5. 実際に試す
  6. コンプライアンス上の注意点
  7. FAQ

OCPPにおけるドライバー認証の位置づけ

OCPP 1.6は、ドライバーがどのように認証されるかを気にしない。気にするのはidTagAuthorize.reqまたはStartTransaction.reqに添付されていることだけだ。仕様はタグの発行元について中立的で、以下のいずれでもよい。

  • 充電器自身のリーダーが読み取る物理RFIDカード
  • 充電器のローカルキーパッドに入力されたタグ
  • バックエンドがRemoteStartTransaction.req経由でリモートに渡すタグ

3番目の選択肢こそが、アプリ不要の充電を可能にする。バックエンドは充電器がカードを読み取るのを待たない。ドライバーがWebページで「開始」をタップした瞬間、生成したIDタグを添えて開始コマンドをプッシュする。充電器はこれをRFIDのタッチとまったく同じように受け取る。

CS→CP: RemoteStartTransaction.req(connectorId, idTag)
CP→CS: RemoteStartTransaction.conf(status=Accepted)
CP→CS: StatusNotification.req(status=Preparing)
CP→CS: StartTransaction.req(connectorId, idTag, meterStart, timestamp)
CS→CP: StartTransaction.conf(transactionId, idTagInfo.status=Accepted)

これは、運用者がダッシュボードで「Remote Start」をクリックしたときにバックエンドが使うのと同じメッセージシーケンスだ。ドライバーアプリは同じバックエンド関数を呼び出す二人目の呼び出し元にすぎず、対象を一つの充電器と一つのセッションに絞っているだけである。


2つの認証方式:RFID vs アプリ生成IDタグ

両方の方式は同じCSMS上で共存でき、実際、本番デプロイの多くがそうしている。

RFIDカード アプリ生成IDタグ
ユーザーごとの初期設定 物理カードを郵送または手渡し 不要 — 初回スキャン時に生成
認証が行われる場所 充電器自身のリーダー バックエンド、その後RemoteStartで送信
適した用途 フリート拠点、社員、既存カードを持つ常連ユーザー 公共充電器、ホテル宿泊客、一度きりの訪問者
失効方法 カードのid_tagレコードを無効化 セッション限定のため失効操作は不要
バックエンド要件 一致するid_tagを持つUserレコード URLと充電器のマッピング+RemoteStart呼び出し

RFID経路は、カードが送信する文字列と完全に一致するid_tagフィールドを持つUserレコードを必要とする。未登録のタグは即座に拒否される。一方、アプリ生成IDタグ経路は、一般的なドライバーについてはユーザーレコードの作成を完全にスキップする。Webページ自体がそのセッションに限定された使い捨てタグを生成し、自動的に登録する。

ホテル駐車場、小売店、マンションの来訪者向け充電など、公共・準公共の展開の多くでは、アプリ生成IDタグの方が適切なデフォルトだ。20分だけ充電する一度きりの訪問者に、カード発行プロセスを踏ませる必要はない。


QRコードフローの全体像

flowchart TD
    A["ドライバーが充電器のQRコードをスキャン"] --> B["モバイルWebページが開くインストール不要"]
    B --> C["コネクターが複数ある場合は選択"]
    C --> D["充電予算を設定または金額をカスタム入力"]
    D --> E["アプリがIDタグを生成しRemoteStartTransactionを呼び出す"]
    E --> F["充電器が認証しセッションを開始"]
    F --> G["ライブセッション画面で電力量 費用 経過時間を表示"]
    G --> H["ドライバーが停止をタップ"]
    H --> I["領収書が生成される"]

各QRコードは単一のURLをエンコードする。充電器IDと任意でコネクター番号、例えばhttps://your-domain.com/ev?cp=CP_014&connector=2のような形だ。これが「アプリインストール」ステップのすべてになる。ドライバーのカメラアプリがこれを解決し、ブラウザタブを開く。App Storeへの掲載も、Play Storeの審査待ちも、次四半期に料金体系を変更したときの強制アップデートプッシュも必要ない。


バックエンドが構築すべきもの

すでにOCPPサーバーを持っている前提で、3つの要素が必要になる。

1. ステートレスなURLスキーム。 GET /ev?cp={charge_point_id}&connector={n} — ドライバーが実際に充電を開始するまでセッショントークンは不要。これがQRコードにエンコードされる内容であり、印刷して恒久的に使える理由でもある。URLは期限切れも回転もしないため、QRコードを再発行する必要がない。

2. 充電器単位に限定されたRemoteStartTransactionエンドポイント。 ドライバーが「開始」をタップすると、バックエンドは使い捨てのidTag(UUIDで十分)を生成し、短命なセッションレコードに登録した上で、URLから特定された充電器に対してRemoteStartTransactionを呼び出す。これはダッシュボードがすでに呼び出しているリモート開始ロジックをそのまま再利用するもので、新しいOCPP処理を構築する必要はない。

3. ライブセッション画面用のポーリングまたはWebSocketフィード。 アクティブなトランザクション中、MeterValues.reqメッセージは10〜60秒ごとに充電器から届く。Energy.Active.Import.Registerを累積kWhとして表示し、料金レートを掛けてリアルタイムの費用を示す。


実際に試す

抽象的に説明するのではなく、実際のフローを構築した。充電器IDを入力すると、実際のデモCSMSからライブで生成されたQRコードとドライバーアプリURLが得られる。

セットアップとQRジェネレーターを開く →

このページは日本語に対応しており、充電器の接続、WebSocket認証情報のリクエスト、IDタグの登録、そして——本記事に最も関連する部分として——任意の充電器IDに対するドライバーアプリURLとQRコードの生成、現在接続中のデモ充電器のライブビューまでを一通り確認できる。


コンプライアンス上の注意点

インストール不要のWebアプリであっても、セッション時間、供給電力量、(決済を行う場合は)取引記録といったデータを収集する。後付けではなく最初から組み込んでおくべき点がいくつかある。

  • APPIに基づくデータ最小化。 アプリ生成IDタグは単一セッションに限定し、ドライバーが明示的にアカウントを作成しない限り、永続的なドライバー識別情報と紐付けるべきではない。デバイスの紛失やセッションに関する紛争が生じた際の責任範囲を限定できる。
  • 領収書の保存。 電子帳簿保存法の観点から、決済を伴う取引記録は一定期間検索可能な形で保存する必要がある。アカウントがない場合でも、セッション終了時にメールまたはSMSで領収書を送付する設計を検討すべきだ。ブラウザ表示のみに頼らないこと。
  • 料金の透明性。 ドライバーが予算を確定する前に、kWh単価または分単価を表示する。セッション終了後の合計金額だけを示すのでは不十分だ。

FAQ

このパターンを使えばネイティブアプリはまったく不要になるか
一般的または公共の充電については不要だ。Webベースのフローは開始・ライブ監視・停止・領収書というセッションのライフサイクル全体をカバーする。オフラインキューイング、「充電完了」のプッシュ通知、ドライバーアカウントに紐づく永続的なロイヤルティ/ウォレットシステムが必要になった時点で、ネイティブアプリを構築する価値が出てくる。

セッション中にドライバーがブラウザタブを閉じたらどうなるか
充電セッション自体には影響しない。セッションは充電器上で実行され、トランザクションIDを通じてバックエンドが追跡しており、ブラウザタブの状態とは独立している。同じQRコードでエンコードされたURL(同じcpconnectorパラメータを持つリンク)を再度開けば、進行中のライブセッションに再接続できる。

登録済みフリートドライバー向けのネイティブアプリと共存できるか
できる。常設アカウントを持つ登録ユーザーにはRFIDまたはネイティブアプリを、公共充電や訪問者には同じ充電器・同じバックエンド上でQR/Webフローを使えばよい。両者の違いはidTagの生成・認証方法だけで、その下にあるOCPPメッセージフローは同一だ。

OCPP 1.6だけでなく2.0.1でも動作するか
動作する。ただし一点異なる。2.0.1ではRemoteStartTransaction.reqの代わりにRequestStartTransactionRequestを使い、IDトークンは単なる文字列ではなく明示的なtypeフィールド(Central、ISO14443など)を持つ。QRコードとWebページによるパターン自体はバージョンに依存しない。


OCPPデプロイのドライバー向け部分を構築中の方、あるいはこれが完全なCSMSにどう組み込まれるかを見てみたい方へ。私たちはこのスタックを実際に本番環境で運用している。

ライブデモを試す — 1分以内に本物のQRコードを生成できる。

hello@simplico.net — 通常1営業日以内にご返信します。

Simplico Co., Ltd. · バンコク、タイ · ASEANおよび日本にサービスを提供