| 文書名 | シェアサイクル ポート共有 MQTT接続仕様書 |
| 用途 | 連携事業者(eMoBi ほか)⇔ GOGOシェア間の在庫(貸出可能台数)・返却可能ポートのリアルタイム同期(M15-IF-120) |
| 準拠標準 | 国土交通省 COMmmmONS「シェアサイクルポート共有API標準仕様書_MQTT(ポート情報リアルタイム連携)」v1.1.0(AsyncAPI 3.0.0、commmmons_doc_002-07-02_ver01.yaml) |
| 版 | v1.5(2026-09-28)reason_code に拡張値 VEHICLE_RENTED を追加・未知値の扱いを明記(§4.2・§5.4) / v1.4(2026-08-19)event_id採番規約(§4.3)を追加 / v1.3 原本定義・イベント型説明 / v1.2 全体像 / v1.1 受信側仕様 / v1.0 初版 |
0.インターフェース全体像(最初に読む)
本インターフェースは、1種類のイベント(JSON)を一方向に流すだけの構成。
- 各事業者は「自社ポートの状態」を自社トピックへ publish する
- 各受信者は「全事業者のポートの状態」を subscribe で受け取る
- 送信と受信でデータ構造は完全に同一(§4の
station.status_updated イベント1種類)。違いは「トピック」と「立場」だけ
eMoBi
自社ポート状態をpublish
Lovedrive
Jテック
──jp/events/{自社id}/…──▶
QoS1 / retain
MQTTブローカー
──jp/events/#──▶
全事業者分を配信
GOGOシェア
在庫保持サーバー
※各事業者も相互受信可
送信と受信の対比
| 送信(publish)する側 | 受信(subscribe)する側 |
| 役割 | 自社ポートの状態変化を通知する | 全事業者のポート状態を把握する |
| トピック | jp/events/{自社partner_id}/stations/{station_id}/status(ACLにより自社prefixのみ) | jp/events/#(全体)または jp/events/{partner_id}/#(事業者単位) |
| データ構造 | §4の共通イベント(JSON) | 同一(他社が送った同じ形のJSONがそのまま届く) |
| QoS / retain / セッション | QoS 1 / retain true(§3) | QoS 1 / clean session(§5.1) |
| タイミング | 状態変化時に即時送信(定期再送不要) | 即時配信+接続直後にretainedで全ポートの最新状態(§5.2) |
| 受信側の必須処理 | —(event_idを一意に採番) | event_id重複排除・timestamp新旧判定(§5.3) |
| サンプル実装 | examples/node-publisher/publish.js | examples/node-publisher/subscribe.js |
例: eMoBiの実装は「自社ポートの変化を§4のJSONにして自社トピックにpublish」だけで完結します(受信は任意)。gogoshareが全事業者分をsubscribeして在庫を保持します。
0.1 役割・目的と適用範囲(標準原本の定義)
本IFの目的は、標準原本(002-07-02 info.description)で次のとおり定義されている:
ポート状態(貸出可能台数・返却可能台数)のリアルタイム連携を目的とした AsyncAPI 定義。各イベント定義は、MQTTプロトコルを用いて事業者間で即座に状態変化を同期し、特に公有地ポート等における車両溢れや在庫不足を防止するための厳格なキャパシティ管理を実現することを意図して設計。利用者の貸出・返却操作に伴う在庫変動を、高いリアルタイム性(数秒以内)で事業者間に共有するイベント駆動アーキテクチャを前提とする。
| 項目 | 内容 | 原本箇所 |
| 扱う情報 | ポート単位の集計状態のみ(貸出可能台数・返却可能ドック数) | 002-07-02 components.schemas.stationStatusUpdatePayload(payload配下は station_id / num_vehicles_available / num_docks_available / reason_code の4項目のみ) |
| スコープ外 | 1台毎の車両状態(車両ID・バッテリー残量・車種等)。payloadに車両単位のフィールドは存在しない | 同上(vehicle_id 等の定義なし) |
| 車両単位の扱い | 車両の特定・予約・解錠はREST標準API側の担当(vehicle_id / vehicle_ids を使用) | 002-07-01(REST標準)の各エンドポイント定義 |
| 補足 | REST標準にもバッテリー残量等の車両詳細フィールドはない。アプリで残量表示等を要件化する場合は標準外の拡張(事業者個別API)が必要 | — |
1.接続情報
| 項目 | ステージング | 本番 |
| ホスト | gogo-cycle-mqtt-stg.fly.dev | gogo-cycle-mqtt.fly.dev |
| ポート | 8883 | 8883 |
| プロトコル | MQTT 3.1.1 / 5.0 over TLS(mqtts) | 同左 |
| TLS | TLS 1.2以上、SNI必須。サーバ証明書はパブリックCA発行(証明書ピンニング不要) | 同左 |
| 平文接続 | 不可(1883は非公開) | 同左 |
| WebSocket(ダッシュボード用) | wss://gogo-cycle-mqtt-stg.fly.dev:8443 | wss://gogo-cycle-mqtt.fly.dev:8443 |
- まずステージングで結合し、動作確認後に本番の資格情報を発行する
- ブローカーは Eclipse Mosquitto 2.x。トピック/ペイロードは標準準拠のため、将来のブローカー変更(AWS IoT Core等)があっても接続先・資格情報の変更のみでクライアント実装に影響しない
2.認証・認可
| 認証方式 | ユーザー名+パスワード(MQTT CONNECT)。事業者ごとに個別発行し、別経路(セキュアな手段)で共有する。本書には記載しない |
| クライアントID | {partner_id}-{env}-{連番} 形式を推奨(例: emobi-stg-01)。同一IDの同時接続は後勝ちで切断されるため、プロセスごとに一意にすること |
| 認可(ACL) | 各事業者は自社プレフィックス jp/events/{partner_id}/# にのみ publish 可。subscribe は相互同期のため jp/events/# 全体に対して可 |
partner_id 採番(仮・要合意)
| 事業者 | partner_id |
| GOGOシェア(Future) | gogoshare |
| eMoBi | emobi |
| Lovedrive | lovedrive |
| Jテック | jtech |
3.トピック設計(標準準拠)
jp/events/{source_partner_id}/stations/{station_id}/status
source_partner_id: 発生源の事業者コード(§2の採番)
station_id: 発生源事業者システムにおけるポートID(m_station.station_id)
- 例:
jp/events/emobi/stations/1234/status
QoS・Retain 規約(本事業の取り決め。標準は未規定)
| 項目 | 値 | 理由 |
| publish QoS | 1(At least once) | 在庫欠落を防ぐ。event_id で重複排除可能 |
| retain | true | ポート状態は「最新値が正」のステート。subscriber が再接続時に最新状態を即取得できる |
| 送信頻度 | 状態変化時に即時(数秒以内)。変化がない場合の定期再送は不要 | 標準のイベント駆動前提 |
4.ペイロード(標準スキーマ準拠・JSON UTF-8)
{
"event_id": "emobi-017f22e2-79b0-8cc3-98c4-dc0c0c07398f",
"event_type": "station.status_updated",
"source_partner_id": "emobi",
"timestamp": "2026-08-10T10:30:00Z",
"payload": {
"station_id": "1234",
"num_vehicles_available": 5,
"num_docks_available": 10,
"reason_code": "VEHICLE_RETURNED"
}
}
| フィールド | 必須 | 型 | 内容 | 原本のデータ項目 |
event_id | ○ | string | 通知の一意ID(重複排除に使用)。形式: {自社partner_id}-{UUID v8}(下記 4.3) | — |
event_type | ○ | string | 通知の種類(下記 4.1)。初版の同期対象は station.status_updated(ride系は任意) | — |
source_partner_id | ○ | string | 発生源事業者(§2採番。トピックと一致させること) | m_company.system_id |
timestamp | ○ | string | イベント発生時刻(UTC、RFC3339 date-time) | t_station_status.updated_at |
payload.station_id | ○ | string | ポートID(トピックと一致させること) | m_station.station_id |
payload.num_vehicles_available | ○ | integer | 貸出可能台数 | t_station_status.num_vehicles_available |
payload.num_docks_available | ○ | integer | 返却可能ドック数 | t_station_status.num_docks_available |
payload.reason_code | — | string | イベント発生の理由(下記 4.2) | — |
4.1 event_type の種類(原本定義の日本語説明)
| 値 | 発生タイミング(原本 002-07-02 の定義) | 初版の扱い |
station.status_updated | ポートの駐輪台数や返却可能台数など、ステータスが変更された場合に発生する | 必須(本IFの同期対象) |
ride.started | ユーザーが車両の解錠に成功し、ライドが開始された場合に発生する | 任意 |
ride.updated | ライド中に何らかの状態変化(特定エリアへの進入・退出など)が発生した場合に使用する | 任意 |
ride.terminated | 車両を施錠し、ライドが正常に終了した場合に発生する | 任意 |
4.2 reason_code の種類
reason_code は任意項目で、台数が変化した理由を表します。台数の正は num_vehicles_available / num_docks_available であり、reason_code は分析用の付加情報です。
標準の値(原本定義の日本語説明)
| 値 | 意味(原本 002-07-02 の定義) | 台数 |
VEHICLE_RETURNED | ユーザーによる車両返却 | 増 |
REBALANCE_DROP_OFF | 再配置による入庫(車両配置) | 増 |
REBALANCE_PICK_UP | 再配置による出庫(車両回収) | 減 |
MAINTENANCE_OUT | 故障対応等による回収 | 減 |
本事業の拡張値(標準原本には無い。v1.5で追加)
| 値 | 意味 | 台数 |
VEHICLE_RENTED | ユーザーによる車両貸出 | 減 |
なぜ拡張するか: 標準の4値では「台数が減った理由」のうちユーザーの貸出だけが表現できません(VEHICLE_RETURNED の対になる値が無い)。貸出を担うはずの ride.started は event_type に宣言があるだけで payload が未定義のため、実証の OD 分析や在庫変動の原因分析で貸出と再配置・回収を区別できません。国土交通省へは標準仕様への改善提案として申し送りますが、標準改訂を待たずに本事業では拡張値として先行運用します(標準は「準拠したうえでの拡張」を妨げません)。
送信側(車両を貸し出した連携事業者): 貸出で台数が減ったときは reason_code: "VEHICLE_RENTED" を付けてください。任意項目なので、対応が間に合わない場合は従来どおり省略して構いません(台数の同期には影響しません)。
受信側: 知らない値を受け取っても捨てずに、台数の値だけで状態を更新してください(§5.4)。この拡張値を知らない既存実装があっても壊れません。
4.3 event_id の採番規約(v1.4で追加)
{自社partner_id}-{UUID v8}
例: emobi-017f22e2-79b0-8cc3-98c4-dc0c0c07398f
| 接頭辞 | 自社の partner_id(§2採番)+ハイフン。source_partner_id と一致させること |
| UUID部 | RFC 9562 の UUID v8(バージョンビット=8)。内部レイアウトは事業者の自由 — 自社システムのタイムスタンプや内部IDなどトレーサビリティ情報を埋め込んでよい |
| 推奨 | 時刻順に単調増加するレイアウト(先頭48bitにUnixミリ秒等。ログ調査・順序確認が容易) |
| 一意性 | 事業者内で一意を保証すれば、接頭辞により全体で一意になる |
| 受信側の扱い | 形式には依存せず不透明なIDとして重複排除にのみ使用(形式不一致を理由に破棄しない。§5.4の頑健性原則) |
5.受信(subscribe)側仕様
在庫イベントを受信・利用する側(gogoshare の在庫保持サーバー、および他事業者の在庫を参照する各社システム)の実装規約。
5.1 購読
| 購読トピック | 全事業者分: jp/events/# / 特定事業者のみ: jp/events/{partner_id}/#。必要な範囲だけの購読でよい |
| subscribe QoS | 1(At least once)。ブローカーは publish 時の QoS 1 を維持して配送する |
| セッション | clean session(clean_start=true)を推奨。ポート状態は retain で初期同期できるため永続セッションは不要。永続セッションはオフライン中のキュー溢れ(ブローカー上限 1,000件/クライアント)のリスクがあり非推奨 |
| keepalive | 60秒を推奨 |
5.2 初期同期(retained メッセージ)
- 接続・購読直後に、各ステーションの最新状態が retained メッセージとして即時に届く(§3の retain=true 規約による)。これが初期同期を兼ねる
- retained かライブ配信かは MQTT の retain フラグで判別できるが、両者を同一ロジックで処理してよい(ポート状態は「最新値が正」のステートであるため)
- 初期同期の完了検知が必要な場合は、購読応答(SUBACK)後の一定時間(目安1〜2秒)受信が途切れた時点を同期完了とみなす
5.3 重複排除・新旧判定
| 重複排除 | QoS 1 は再配送があり得るため、event_id による重複排除を必須とする。ステーションごとに最後に処理した event_id を保持すれば十分 |
| 新旧判定 | ステーションごとに最後に適用した timestamp を保持し、それより古い timestamp のイベントは破棄する(再接続時の並び替わり対策)。同一 timestamp は event_id が異なれば適用してよい |
| 順序 | MQTT は同一トピック内では概ね順序どおり配送されるが、順序保証には依存しないこと(上記の timestamp 判定で吸収する) |
5.4 受信データの取り扱い
- 未知の
event_type は無視する(前方互換。初版で処理必須なのは station.status_updated のみ)
- 未知のフィールドは無視する(スキーマ拡張に備える)
- 未知の
reason_code は無視し、台数の値でそのまま状態を更新する。reason_code は分析用の付加情報であり、状態更新の条件にしてはならない(§4.2。将来値が追加されても在庫の同期が止まらないようにするため)
- JSON として解釈できない、または必須フィールドが欠落したメッセージは破棄してログに記録し、処理は継続する(1件の不正データで購読を止めない)
- 自社が publish したイベントも購読条件に合致すれば届く(エコーバック)。不要な場合は
source_partner_id が自社のものを読み飛ばす
5.5 再接続・鮮度
- 自動再接続を必須とする(推奨: 5秒間隔)。clean session のため再接続後は再 subscribe が必要。再接続すれば retained により状態は自動回復する
- 本仕様は「状態変化時のみ送信」(§3)のため、受信が無いこと自体は異常ではない。ただし長時間(目安: 24時間)更新のないステーションは、表示上「最終更新時刻」を併記するなど鮮度が分かる形で扱うことを推奨
- ブローカー側の障害・メンテナンスによる切断があり得る前提で、切断中に UI 等へ表示する場合は「最終受信時刻時点の情報」であることを明示する
6.接続確認手順(mosquitto クライアント例)
# subscribe(発行された資格情報で置き換え)
mosquitto_sub -h gogo-cycle-mqtt-stg.fly.dev -p 8883 \
--capath /etc/ssl/certs -u <username> -P <password> \
-i emobi-stg-test -t 'jp/events/#' -v
# publish(在庫更新イベント)
mosquitto_pub -h gogo-cycle-mqtt-stg.fly.dev -p 8883 \
--capath /etc/ssl/certs -u <username> -P <password> \
-i emobi-stg-pub -q 1 -r \
-t 'jp/events/emobi/stations/1234/status' \
-m '{"event_id":"emobi-017f22e2-79b0-8cc3-98c4-dc0c0c073001","event_type":"station.status_updated","source_partner_id":"emobi","timestamp":"2026-08-10T10:30:00Z","payload":{"station_id":"1234","num_vehicles_available":5,"num_docks_available":10,"reason_code":"VEHICLE_RETURNED"}}'
publish後、
ダッシュボードにログインすると受信状態を目視確認できます(retainにより接続直後に最新状態が表示されます)。
7.運用
- 稼働監視: ブローカーは常時稼働(自動停止なし)。障害時の連絡先は別途共有
- 資格情報のローテーション: 漏えい時は即時再発行(接続断→新パスワードで再接続)
- メッセージ上限: 64KB / メッセージ(在庫イベントは通常1KB未満)
- 切断時の復旧: retain により再接続後すぐ最新状態を受信可能。publisher 側は QoS 1 + 自動再接続を推奨
8.今後(参考)
- gogoshare 側は本ブローカーを subscribe して在庫を保持し、アプリへは REST で配信する(在庫保持サーバー。8月後半〜)
- Lovedrive / Jテック の接続は準備が整い次第、同一仕様で資格情報を発行