
最初の2つの記事では、GD6 を製品として、またそのハードウェア設計について取り上げました。今回は開発者が最も気にする内容、つまりコードの使い方について説明します。
GD6 のファームウェアと Web 設定システムは GitHub でオープンソース公開されています(github.com/ManThink/gd6-open)。本記事では、リポジトリ構成、開発環境のセットアップ、ファームウェアのコンパイル、マルチリージョンビルド、書き込み、Web インターフェースのカスタマイズ、REST API の使用方法、リモート MQTT 設定チャネルについて順に説明します。
| 項目 | 詳細 |
|---|---|
| リポジトリ | https://github.com/ManThink/gd6-open |
| 説明 | ESP32 をベースとした LoRaWAN ゲートウェイ |
| 主要言語 | C(ESP-IDF フレームワーク) |
| ビルドシステム | PlatformIO + ESP-IDF |
| ライセンス | リポジトリ内の LICENSE ファイルを参照 |
| 現在のバージョン | 1.0.2(参照: version.txt) |
| 初回リリース | 2026-07-23 |
gd6-open/
├── src/ # Main application code
│ ├── main.c # Entry point, 6-phase boot
│ ├── ethernet_w5500.c # W5500 Ethernet driver
│ ├── cellular_4g.c # 4G PPP dial-up
│ ├── net_route_mgr.c # Triple-link failover manager
│ ├── wifi_ap.c # Wi-Fi AP + STA
│ ├── web_server.c # HTTP REST API + static files
│ ├── config_rpc.c # Config core (parse → validate → persist → apply)
│ ├── auth.c # Login password + Token auth
│ ├── mqtt_bridge.c # UDP↔MQTT bridge
│ ├── remote_config.c # Remote MQTT config channel
│ ├── ota_update.c # A/B dual-partition OTA
│ ├── sys_log.c # In-memory ring buffer log
│ ├── uplink_driver.c # pktfwd / station driver selection
│ ├── periph_power.c # Peripheral power management
│ ├── status_led.c # Status LED + watchdog
│ └── factory_reset.c # Factory reset
├── components/ # Third-party components
│ ├── packet_forwarder/ # Semtech lora_pkt_fwd
│ ├── sx1302_hal/ # SX1302 HAL (Semtech v2.1.0 port)
│ ├── basicstation/ # Semtech BasicStation 2.0.6
│ └── esp_modem/ # 4G PPP modem component
├── frontend/ # Web UI source (Vite build)
├── data/ # SPIFFS filesystem image
│ ├── web/ # Web UI static files (build output)
│ ├── global_conf.json # Active radio + gateway config
│ ├── regions/ # LoRaWAN regional config templates
│ ├── eth_config.json # Ethernet config
│ ├── wifi_ap.json # Wi-Fi AP/STA config
│ ├── cellular_config.json # 4G config
│ ├── mqtt_bridge_config.json # MQTT bridge config
│ └── remote_config.json # Remote config channel settings
├── scripts/ # Build scripts
│ ├── build_regions.py # Per-region batch build
│ └── embed_defaults_copy.py # Default config sync
├── tools/ # Flasher + crypto scripts
├── hardware/ # Hardware project files
├── partitions.csv # Dual-OTA partition table
├── platformio.ini # PlatformIO configuration
├── sdkconfig.defaults # SDK configuration
└── CMakeLists.txt # Top-level CMake
主要なディレクトリ:
src/ メインのアプリケーションコードが含まれます。各 .c ファイルが機能モジュールに対応しています。コードは厳格な -Wall 警告付きでコンパイルされます。components/ サードパーティ製コンポーネントを格納します。SX1302 の HAL と Packet Forwarder は Semtech の公式ソースから移植されており、元の参照コードは .upstream/ に保持され、変更前の差分確認に使用できます。frontend/ Web インターフェースの Vue/Vite ソースが含まれます。ビルド出力は data/web/に出力されます。data/ は SPIFFS ファイルシステムイメージです。ゲートウェイの設定ストレージパーティションに書き込まれます。ManThink は GitHub 上で他にもオープンソースリポジトリを公開しています:
| リポジトリ | 目的 |
|---|---|
| ThinkLink | ThinkLink IoT プラットフォーム |
| TKL-EB-SDK | エッジデバイス開発向け EdgeBus SDK |
| ThinkLink-docker | ThinkLink プラットフォームの Docker デプロイ |
GD6 リポジトリはゲートウェイハードウェアのオープンソースプロジェクトです。ThinkLink はプラットフォームのオープンソースプロジェクトです。両者は組み合わせて使用できますが、GD6 は ChirpStack、TTN、その他のサードパーティ製ネットワークサーバーと単独でも動作します。
GD6 のビルドスタックは PlatformIO + ESP-IDFです。ESP-IDF を別途インストールする必要はありません。PlatformIO がフレームワークのバージョンを自動的に管理します。
必要なもの:
frontend/)を変更する場合に必要です。platformio.ini プラットフォームのバージョンを明示的に固定しています:
platform = espressif32 @ 6.13.0
このバージョンは ESP-IDF 5.5.3 に対応しています。コメントでは特に警告しています:素の espressif32を使用しないでください。最新バージョン(7.0.x / IDF 6.0)に変動してしまいます。IDF 6.0 では組み込みの mqtt コンポーネントが削除されており、コンパイルエラーの原因になります。
これが最初の落とし穴です:PlatformIO を更新してコンパイルが壊れた場合は、 espressif32 のバージョンが変わっていないか確認してください。
git clone https://github.com/ManThink/gd6-open.git
cd gd6-open
pio run # Build firmware
コンパイルが成功して firmware.binが生成されれば、環境は準備完了です。初回ビルドでは ESP-IDF フレームワークと依存関係をダウンロードするため、時間がかかります。
ManThink(門思科技)は、デバイス接続、ネットワーク、データ活用に向けたIoT製品を提供しています。この記事の技術情報とあわせて、以下の製品情報をご覧ください。
pio run # Build firmware
pio run --target upload # Flash firmware (via USB)
pio run --target uploadfs # Flash SPIFFS image
pio device monitor # Serial monitor (115200 baud)
pio run --target menuconfig # SX1302 pin / SPI configuration
pio run --target clean # Clean build/
シリアルボーレートは 115200 に固定されています。 platformio.ini のコメントで説明されています:ESP-IDF コンソールのデフォルトは 115200 です。この設定がない場合、 pio run -t monitor は 9600 を使用し、文字化けが発生します。
GD6 のアプリケーションコードは周波数に依存しません。リージョンごとの違いはすべて global_conf.jsonにあります。リージョンテンプレートは data/regions/ にあります(AS923 / EU868 / US915 / AU915 / CN470 / KR920 / IN865)。
その scripts/build_regions.py スクリプトはワンコマンドビルドを提供します:
# List available regions and center frequencies
python scripts/build_regions.py --list
# Set a region as development default (overwrites data/global_conf.json)
python scripts/build_regions.py --activate EU868
pio run && pio run -t uploadfs
# Build firmware + SPIFFS for all regions (output in dist/<REGION>/)
python scripts/build_regions.py
# Build specific regions only
python scripts/build_regions.py EU868 US915 AS923
# Rebuild SPIFFS only (faster when only config changed)
python scripts/build_regions.py --fs-only AS923
ビルド成果物の命名(バージョンは次から取得: version.txt):
| ファイル | 説明 | フラッシュオフセット |
|---|---|---|
GD6-<ver>-<REGION>-full.bin |
完全な8 MiBフラッシュイメージ | 0x0 |
GD6-<ver>-<REGION>-firmware.bin |
アプリファームウェア | 0x20000 |
GD6-<ver>-<REGION>-spiffs.bin |
SPIFFSイメージ | 0x5A0000 |
GD6-<ver>-<REGION>-global_conf.json |
ビルド時に使用される設定のコピー | — |
build_info.json |
ビルドメタデータとオフセットテーブル | — |
注記:RFフロントエンドハードウェアは対象バンドと一致している必要があります。868 / 915 / 470モジュールは互換性がありません — これは物理的な制約であり、ソフトウェアの制限ではありません(記事2で詳しく説明しています)。
初回書き込みまたは開発デバッグの場合:
# Regular flash (firmware + SPIFFS)
pio run --target upload
pio run --target uploadfs
# Erase entire flash and write full image (initial flash or recovery)
python -m esptool --chip esp32s3 erase_flash
python -m esptool --chip esp32s3 write_flash 0x0 GD6-1.0.2-EU868-full.bin
完全消去はすべてのパーティションとデバイスデータ(Gateway EUIを含む)を上書きします。保持が必要なデータは事前にバックアップしてください。
運用中のゲートウェイのオンラインアップグレードの場合:
.bin ゲートウェイモデル、ハードウェアバージョン、対象リージョンに適合するファームウェアを選択するOTAはA/Bデュアルパーティション機構を使用します。新しいファームウェアは非アクティブパーティションに書き込まれ、検証された後、ブートパーティションが切り替えられます。アップグレード中はページを更新したり、ネットワークを切断したり、電源を切ったりしないでください。
リポジトリの tools/flasher/ ディレクトリにはブラウザベースのフラッシャー(ESP Web Serial API上に構築)が含まれており、Chrome/EdgeでUSB経由で直接ファームウェアを書き込むことができます。このツールはESP32-S3外部ウォッチドッグ(TPL5010)のフィード制御に加え、中断および例外リセット保護も統合しています。
マニュアルには明示的に警告されています: 完全なフラッシュ製造イメージ(-full.bin)をWeb OTAファームウェアとしてアップロードしないでください。Web OTAはアプリファームウェア(-firmware.bin)のみを受け付けます。OTAはフラッシュ全体ではなく非アクティブパーティションに書き込むためです。
GD6はカスタムパーティションテーブル(partitions.csv)を使用します。8 MBフラッシュは次のように分割されます:
| パーティション | タイプ | オフセット | サイズ | 説明 |
|---|---|---|---|---|
| nvs | data/nvs | 0x9000 | 24 KB | 不揮発性ストレージ(パスワードなど) |
| otadata | data/ota | 0xF000 | 8 KB | OTAブートスロットレコード |
| phy_init | data/phy | 0x11000 | 4 KB | RF PHY初期化 |
| ota_0 | app | 0x20000 | 2.75 MB | ファームウェアスロットA |
| ota_1 | app | 0x2E0000 | 2.75 MB | ファームウェアスロットB |
| storage | data/spiffs | 0x5A0000 | 2.375 MB | Web UI + 設定ファイル |
このテーブルはちょうど8 MBを埋めます。2つのOTAパーティションはそれぞれ2.75 MBです。SPIFFSパーティションは2.375 MBです。ファームウェアが2.75 MBを超える場合、パーティションテーブルを調整する必要があります。
Webインターフェースのソースは frontend/にあり、Viteでビルドされます:
cd frontend && npm install # First-time dependency install
cd frontend && npm run build # Build to data/web/
pio run --target uploadfs # Flash to SPIFFS
cd frontend && npm run dev # Local dev server
ビルド出力は次に出力されます: data/web/ (index.html、 app.js、 style.css)、その後SPIFFSイメージの一部として書き込まれます。
README には明示的に警告されています: 変更しないでください data/web/* 直接 — これらはビルド成果物です。正しい方法は、ソースを変更することです frontend/、その後実行します npm run build。
Web インターフェースのテキスト、スタイル、またはレイアウトを変更する必要がある場合:
frontend/npm run build 新しいものを生成するには data/web/ ファイルpio run --target uploadfs ゲートウェイに書き込むにはnpm run dev Vite ローカル開発サーバーを起動します。 /api/* リクエストは Vite プロキシ経由で対象ゲートウェイにプロキシされます。これにより、書き込みを行わずにフロントエンドコードを変更し、変更をリアルタイムでプレビューできます。
上書き web/ オンラインでファイルを上書きするとコンソールにアクセスできなくなる可能性があり、工場出荷時リセットでは ありません 破損した Web ファイルを復元します。Web インターフェースをオンラインで更新する必要がある場合は、フォールバック復旧方法としてシリアルアクセスを確保してください。
GD6 REST API はトークン認証を使用します:
POST /api/login パスワードを指定してトークンを取得しますデフォルトのログインパスワード: wifi!0804 (初回ログイン後すぐに変更してください)。
| メソッド | パス | 説明 |
|---|---|---|
| GET | /api/status |
システム/ネットワーク/LoRa/SPIFFS ステータス |
| POST | /api/login · /api/logout |
ログイン / ログアウト |
| PUT | /api/password |
パスワード変更 |
| GET | /api/auth_state |
認証状態クエリ |
| GET/PUT | /api/ethernet |
イーサネット設定 |
| POST | /api/ethernet/power |
イーサネット電源制御 |
| GET/PUT | /api/wifi |
Wi-Fi 設定 |
| GET | /api/wifi/scan |
Wi-Fi スキャン |
| GET/PUT | /api/lora |
LoRa ゲートウェイ設定 |
| GET/PUT | /api/cellular |
4G 設定 |
| GET | /api/cellular/status |
4G リアルタイムステータス |
| GET/PUT | /api/mqtt_bridge |
MQTT ブリッジ設定 |
| GET | /api/mqtt_bridge/status |
MQTT ブリッジステータス |
| POST/DELETE | /api/mqtt_bridge/cert |
MQTT ブリッジ証明書 |
| GET/PUT | /api/remote_config |
リモート設定チャネル設定 |
| GET | /api/remote_config/status |
リモート設定ステータス |
| POST/DELETE | /api/remote_config/cert |
リモート設定証明書 |
| GET | /api/station |
BasicStation ステータス |
| GET | /api/logs |
ログ(増分) |
| DELETE | /api/logs |
ログをクリア |
| GET | /api/logs/download |
ログをダウンロード |
| GET | /api/fs |
ファイル一覧 |
| POST | /api/fs/upload |
ファイルをアップロード |
| GET | /api/firmware |
ファームウェア情報 |
| POST | /api/firmware/upload |
OTA アップロード |
| POST | /api/restart |
LoRa サービスまたはシステムを再起動 |
システムステータスを取得:
# Login to get Token
TOKEN=$(curl -s -X POST http://192.168.4.1/api/login \
-H "Content-Type: application/json" \
-d '{"password":"wifi!0804"}' | jq -r '.token')
# Query system status
curl -s http://192.168.4.1/api/status \
-H "Authorization: Bearer $TOKEN" | jq
イーサネットを静的IPに設定:
curl -s -X PUT http://192.168.4.1/api/ethernet \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"mode": "static",
"ip": "192.168.1.200",
"netmask": "255.255.255.0",
"gateway": "192.168.1.1",
"dns1": "8.8.8.8"
}'
複数ゲートウェイ向けの一括管理スクリプト:
#!/bin/bash
# Batch query gateway status
GATEWAYS=("192.168.1.101" "192.168.1.102" "192.168.1.103")
PASSWORD="your_password"
for GW in "${GATEWAYS[@]}"; do
TOKEN=$(curl -s -X POST "http://$GW/api/login" \
-H "Content-Type: application/json" \
-d "{\"password\":\"$PASSWORD\"}" | jq -r '.token')
echo "=== $GW ==="
curl -s "http://$GW/api/status" \
-H "Authorization: Bearer $TOKEN" | jq '{firmware: .firmware_ver, uptime: .uptime, lora: .lora_status}'
done
GD6には独立した2つのMQTT接続があります — 混同しないでください:
| MQTTブリッジ | リモートMQTT設定チャネル | |
|---|---|---|
| 目的 | LoRaWANデータ転送 | リモートデバイス設定の読み書き |
| 設定ファイル | mqtt_bridge_config.json |
remote_config.json |
| コードモジュール | src/mqtt_bridge.c |
src/remote_config.c |
| 接続 | 独立したTLS接続 | 独立したTLS接続 |
| 認証 | ブローカーの認証情報 | デバイスログインパスワード(RPC認証) |
2つの接続は完全に分離されています — Topicや認証情報を混在させないでください。
リモートチャネルには重要なセキュリティ設計があります: リモートチャネルは自身のブローカー設定を変更できません。
これにより、リモートの設定ミスがデバイスの切断を引き起こすのを防ぎます。リモートチャネルが自身のブローカーアドレスや認証情報を変更できた場合、1回の誤った設定でデバイスのリモート管理機能が恒久的に失われる可能性があります。
Webコンソール →「リモート設定」ページから設定します:
設定後、MQTTメッセージ経由で許可されたデバイス設定項目をリモートで読み書きし、再起動をトリガーできます。
| ファイル | 説明 |
|---|---|
/spiffs/global_conf.json |
SX1302無線パラメータ + ゲートウェイ全体設定( uplink_driver の選択を含む) |
/spiffs/eth_config.json |
イーサネットのDHCP / 静的IP |
/spiffs/wifi_ap.json |
Wi-Fi AP/STA設定 |
/spiffs/cellular_config.json |
4GのAPN / 認証 / 優先度 |
/spiffs/mqtt_bridge_config.json |
MQTTブリッジのブローカー / アカウント / TLS / トピック |
/spiffs/remote_config.json |
リモート設定チャネルのブローカー / アカウント / TLS / トピック |
これらのJSONファイルは工場出荷時リセットの対象としても機能します — ファームウェアに埋め込まれています。工場出荷時リセットはファームウェアからデフォルト値を抽出し、SPIFFSのコピーを上書きします。
設定JSONの変更を反映するには ゲートウェイの再起動 が必要です。SPIFFSがFlashに書き込むと、データは永続化されRAMに依存しません — 電源断でも保持されますが、新しい設定を読み込むには再起動が必要です。
Webコンソールの「ファイルシステム」ページでは /spiffs ファイルを直接管理でき、設定JSONの表示と編集をサポートします。これにより深いカスタマイズへの道が開けます — Webインターフェースで公開されているオプションを超えて、設定フィールドを直接変更できます。
その uplink_driver のフィールドで global_conf.json SX1302を占有するドライバを選択します。両者は排他的です:
| ドライバ | 値 | 説明 |
|---|---|---|
| Packet Forwarder | pktfwd |
Semtech UDPパケットフォワーダー(デフォルト) |
| Basic Station | station |
Semtech BasicStation 2.0.6、LNSへのwss/TLS |
ドライバの切り替えにはゲートウェイの再起動が必要です。Basic Stationモードでは、チャネルプランはLNSによってプロビジョニングされ、認証情報/設定は別のSPIFFSファイル(tc.* / cups.*)に保存されます。
起動プロセスを理解することはトラブルシューティングに役立ちます。 app_main() (src/main.c)は6のフェーズで起動します:
| フェーズ | 動作 |
|---|---|
| フェーズ0 | NVS初期化 + イベントループ(ステータスLEDと工場出荷時リセットボタンは早期に準備完了) |
| フェーズ1 | SPIFFSをマウント — マウント失敗時はWebサーバーとパケットフォワーダーが無効化 |
| フェーズ2 | Wi-Fi Soft-APを起動(非同期、ノンブロッキング) |
| フェーズ3 | ルートマネージャーがW5500イーサネット → 4G PPP、プライマリ/バックアップのフェイルオーバーを開始 |
| フェーズ4 | HTTPD(REST API + 静的ファイル)+ リモートMQTT設定チャネルを起動 |
| フェーズ5 | SX1302セルフテスト → パケットフォワーダーまたはBasicStationを uplink_driver |
設計原則: 後のフェーズは前のフェーズの致命的でない障害を許容し、デバイスが常にWi-Fi AP経由でリカバリモードに入れることを保証します。SPIFFSのマウントが失敗したりSX1302のセルフテストが失敗しても、Webコンソールは引き続きアクセス可能です。
非標準のチャネル設定(例:カスタム中心周波数)が必要な場合は、次を直接変更してください: data/global_conf.json 直接変更:
python scripts/build_regions.py --activate EU868
# Then edit radio_0 / radio_1 center frequencies in data/global_conf.json
pio run --target uploadfs
REST API を使用して GD6 ゲートウェイを独自の運用システムに統合します:
/api/status ゲートウェイの実行時ステータスを収集します/api/logs ログを取得します/api/remote_config 設定変更を一括プッシュします/api/restart リモート再起動を行います次にある Vue ソースを変更して frontend/ カスタムページを追加するか既存のインターフェースを変更し、その後 npm run build + pio run --target uploadfs。
Q: mqtt コンポーネントが見つからないというコンパイルエラーが発生しますか?
A: 次を確認してください: platform = espressif32 @ 6.13.0 次にある platformio.ini が変更されていないこと。IDF 6.0 は組み込みの mqtt コンポーネントを削除したため、6.13.0(IDF 5.5.3)に固定する必要があります。
Q: 書き込み後のシリアル出力が文字化けしますか?
A: ボーレートが 115200 であることを確認してください。 platformio.ini 次を設定します: monitor_speed = 115200。
Q: Web OTA ファームウェアのアップロード後に起動に失敗しますか?
A: アプリファームウェア(-firmware.bin)をアップロードしたのか、フルイメージ(-full.bin)をアップロードしたのかを確認してください。Web OTA はアプリファームウェアのみを受け付けます。フルイメージをアップロードした場合は、自動再起動を待ってください。それでもアクセスできない場合は、Wi-Fi AP または制御されたシリアル復旧を使用してください。電源の再投入を繰り返さないでください。
Q: 工場出荷時リセット後に Web コンソールが開きませんか?
A: 工場出荷時リセットでは次を復元しません: web/ ディレクトリ。次を復元しません: web/ ファイルが以前に上書きされ破損している場合は、シリアル経由で SPIFFS イメージを再書き込みしてください(pio run --target uploadfs)。
Q: 変更した data/ 設定が反映されませんか?
A: 次にあるファイルを変更した後は data/、必ず次を実行してください: pio run --target uploadfs SPIFFS に書き込むため。SPIFFS ファイルをオンラインで変更した後は、変更を反映するためにゲートウェイの再起動が必要です。
GD6 オープンソースリポジトリはシェルではありません。完全なファームウェアソース、Web インターフェースソース、ビルドツールチェーン、ハードウェアプロジェクトファイルが含まれています。コードのクローンから使用可能なファームウェアのコンパイルまで、プロセス全体を 30 分以内に完了できます。
主なポイント:
build_regions.py マルチリージョンビルド用 — 手動で編集しないでください: global_conf.json リージョンフィールドfrontend/、次ではなく: data/web/ — 後者はビルド成果物です次の記事ではデプロイに移ります。開梱から ThinkLink / ChirpStack / TTN への接続まで、デプロイプロセス全体を段階的に説明します。
ManThink — IoT 開発をより効率的に。