対象読者: freeBox 対応モジュールをゼロから開発・配布したいサードパーティ開発者
前提知識: Python の基本的な知識、GitHub の基本操作
freeBox Module の開発から配布までは以下の流れで進めます。
1. Plugin 実装(.py)
↓
2. インストールスクリプト実装(run.sh)
↓
3. .hbx パッケージのビルド(make_hbx.py)
↓
4. GitHub Release へのアップロード
↓
5. index.json への登録(freeBox 公式または自リポジトリ)
↓
6. Manager UI からインストール(Deploy)
各ステップの詳細は以下のドキュメントを参照してください。
| ドキュメント | 内容 |
|---|---|
docs/plugin_dev_guide.md |
Plugin クラスの実装方法・API リファレンス |
docs/run_sh_guide.md |
インストールスクリプトの実装方法 |
docs/hbx_build_tool_guide.md |
.hbx パッケージのビルド方法 |
docs/naming.md |
Plugin ID の命名規約 |
docs/specification.md |
freeBox Loader の仕様詳細 |
git clone https://github.com/hoscm/freebox.git
cd freebox
Plugin は hsBox 上でテストしますが、Python の単体テストをローカルで行う場合は以下のダミーを使います。
# テスト用スタブ(Python 3.10 以上)
from dataclasses import dataclass
@dataclass
class Response:
status: int = 200
body: bytes = b""
content_type: str = "text/plain"
class DummyRequest:
def __init__(self, method="GET", path="/", body=b""):
self.method = method
self.path = path
self.query = {}
self.headers = {}
self._body = body
def read_body(self):
return self._body
"""
hello.py - freeBox Plugin ミニマル実装例
"""
class Plugin:
def can_handle(self, path: str) -> bool:
return path.startswith("/hello")
def handle(self, req) -> "Response":
try:
from box_webserver import Response
except ImportError:
from dataclasses import dataclass
@dataclass
class Response:
status: int = 200
body: bytes = b""
content_type: str = "text/plain"
return Response(
200,
b"<h1>Hello from freeBox!</h1>",
"text/html; charset=utf-8",
)
#!/bin/bash
set -e
ZTMP="/home/hsbox/ztmp"
PLUGINS_DIR="/home/hsbox/freebox/plugins"
systemctl stop freebox 2>/dev/null || true
mkdir -p "${PLUGINS_DIR}"
cp -f "${ZTMP}/hello.py" "${PLUGINS_DIR}/hello.py"
chmod 644 "${PLUGINS_DIR}/hello.py"
systemctl start freebox
echo "[hello] インストール完了"
echo "[hello] アクセス URL: http://<hsBox の IP>/freebox/hello/"
python tools/make_hbx.py hello ./hello.py 1.0.0 ./dist/
注意: 本節の手順は 開発者の動作確認用 です。実運用での Plugin インストールは Manager UI からの Deploy が正規動線 です。
開発時の動作確認手順:
dist/hello.hbx を hsBox にコピーして展開 → bash run.sh でインストール(動作確認用)http://<hsBox の IP>/freebox/hello/ を開く実運用での配布手順:
dist/hello.hbx を GitHub Releases にアップロードdocs/index.json にエントリ追加Claude などの AI アシスタントを使うと、Plugin の実装を効率よく進められます。
AI に Plugin 実装を依頼する際は、以下の情報を提示してください。
以下の仕様で freeBox Plugin を実装してください。
## Plugin ID
<my_plugin>
## 処理するエンドポイント
- GET /my_plugin/ ← HTML ステータス画面
- GET /my_plugin/status ← JSON でステータスを返す
- POST /my_plugin/config ← 設定値を保存する
## 設定項目(freebox_config.ini 管理)
- [my_plugin]
- target_host = "" ← 対象ホスト名または IP
- interval_minutes = 10 ← 定期実行間隔(分)
## 定期実行
interval_minutes ごとに <処理内容> を実行する。
NAS 未接続時はスキップして status に skip_nas を記録する。
## 制約
- Python 3.10 以上で動作すること
- クラス名は Plugin
- 予約済みコンテキスト(/loader, /api, /status, /manager など)と衝突しないこと
- NAS アクセスは is_nas_available() でガードする
- ジョブ例外は必ずキャッチすること
予約済みコンテキストについて(v1.0.2 時点): freeBox Loader 内部で使用される コンテキスト(
/loader,/api,/status,/managerなど)は今後の機能追加で 拡張される可能性があります。Plugin ID 選定時は予約済みコンテキスト一覧の最新版 (docs/specification.md参照)を確認してください。 なお v1.1.0 で予約コンテキスト管理機構を整備予定 です(重複検証の自動化)。
AI が生成したコードを採用する前に以下を確認してください。
| チェック | 確認内容 |
|---|---|
can_handle |
予約済みコンテキスト(/loader, /api, /status, /manager など)を使っていないか |
handle |
ユーザー入力を HTML に直接埋め込んでいないか(XSS 対策) |
| ジョブ | 例外を try/except でキャッチしているか |
| 設定ファイルパス | __file__ を基点にパスを構築しているか |
Response |
from box_webserver import Response を使っているか |
Plugin 実装が完成したら、run.sh の生成も AI に依頼できます。
上記の Plugin のインストールスクリプト(run.sh)を実装してください。
## 条件
- 設定ファイルは /home/hsbox/freebox/plugins/my_plugin/ に配置
- 設定ファイルのテンプレートは my_plugin_config.ini.template として .hbx に含める
- 初回は template をコピー、更新時は merge_config.py でマージする
- run.sh は冪等に実装する(複数回実行しても同じ状態になる)
## 参照実装
freebox/modules/atomcam2/run.sh を参照してください。
実装前に以下を確認してください。
^[a-z0-9][a-z0-9\-]*[a-z0-9]$ に準拠している(単一文字は不可)loader / index / api / status / manager など)と衝突しないcan_handle が自 Plugin のパスのみを処理するhandle がすべてのパスに対して Response を返す(404 を含む)__file__ 基点でパスを構築しているrun.sh が冪等(複数回実行しても同じ状態)に実装されている.hbx のビルドが成功しているPlugin を公開するための GitHub リポジトリを作成します。構成例:
my-freebox-plugin/
my_plugin.py ← Plugin 実装
run.sh ← インストールスクリプト
my_plugin_config.ini.template ← 設定テンプレート
version.txt ← バージョン情報(ビルドツールが自動生成)
README.md ← 使い方の説明
# freebox リポジトリの tools/make_hbx.py を使用してビルド
python tools/make_hbx.py my_plugin ./my_plugin.py 1.0.0 ./dist/
# GitHub Release を作成してアセット添付
# タグ名: v1.0.0
# アセット: dist/my_plugin.hbx
補足:
make_hbx.pyは freeBox 公式リポジトリ(freebox/tools/)に同梱されて います。Plugin 開発時は freebox リポジトリをクローンしておくか、自リポジトリのtools/配下にコピーして使用してください。詳細はdocs/hbx_build_tool_guide.md§3 を参照してください。
freeBox の公式 docs/index.json に追加するか、自リポジトリの index.json を別途管理します。
{
"id": "my_plugin",
"name": "My Plugin",
"description": "プラグインの説明をここに書く",
"status": "restricted",
"version": "1.0.0",
"release_tag": "v1.0.0",
"author": "Your Name",
"repository": "https://github.com/YOUR_USER/my-freebox-plugin",
"plugin_file": "my_plugin.py"
}
status の選択基準:
| status | 使う場面 |
|---|---|
public |
誰でも安全に使えるモジュール |
restricted |
設定が必要・一部の環境向け・動作条件がある |
private |
配布しない・個人用・index.json には書かない |
status の運用詳細(公式リポジトリ配布時の選択基準・自前テスト用
index.jsonでのprivate利用可否・警告レベル等)についてはdocs/hbx_build_tool_guide.md§6 を参照してください。
任意フィールドについて(v1.0.2 時点):
上記の必須フィールドに加えて、Plugin 固有のメタ情報を任意フィールドとして 追加できます。例:
| 任意フィールド | 用途例 |
|---|---|
requires_ffmpeg |
ffmpeg コマンドの必要可否(boolean) |
hsbox_min_version |
動作対象 hsBox の最小バージョン |
任意フィールドの運用ルール整備予定: 任意フィールドの命名規則・推奨フィールド集 (依存パッケージ宣言・対応プラットフォーム等)の標準化は v1.1.0 で整備予定 です。v1.0.2 時点では Plugin 開発者が自由に追加できますが、Loader 側で解釈される ことは保証されません(あくまで Plugin 自身および UI 表示用のメタ情報として 利用してください)。
# バージョンを上げて再ビルド
python tools/make_hbx.py my_plugin ./my_plugin.py 1.1.0 ./dist/
新しいタグ(例: v1.1.0)で Release を作成し、dist/my_plugin.hbx を添付します。
version と release_tag を新しいバージョンに更新します。
{
"version": "1.1.0",
"release_tag": "v1.1.0"
}
バージョン番号の運用詳細(文字列大小比較で新旧判定される性質、桁数固定推奨等) については
docs/hbx_build_tool_guide.md§6 を参照してください。
my_plugin_config.ini.template に新しいキーを追加し、バージョンアップ時に merge_config.py が既存の設定を保持しながら新しいキーを追加します。run.sh に merge_config.py の呼び出しが実装されていれば自動的に対応します。
atomcam2 Plugin は設定画面・手動実行・定期実行・NAS チェックを網羅した参照実装です。
| ファイル | 内容 |
|---|---|
modules/atomcam2/atomcam2.py |
Plugin 実装(参照実装) |
modules/atomcam2/run.sh |
インストールスクリプト(参照実装) |
modules/atomcam2/atomcam2_config.ini.template |
設定テンプレート |
本ドキュメントは freeBox Loader v1.0.2 に基づきます。