0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【小型装置のWeb UI・第1回】2行LCDだけでは足りなかった ― BusyBox Linuxとlighttpdで操作画面を分ける

0
Last updated at Posted at 2026-08-08

装置の前まで歩かないと設定を変えられない

小型の組み込み機器には、2行程度のキャラクタLCDと数個の物理ボタンしかないものがあります。

装置の前に立ってIPアドレスを確認する。起動したかを見る。致命的な異常が出ていないか確かめる。その程度なら、2行LCDはとても頼りになります。ネットワークへ入れないときにも使えるため、最後の確認手段として残しておきたいUIです。

一方で、設定項目が増えてくると事情が変わります。階層の深いメニューを物理ボタンで行き来し、短い項目名を読み解きながら値を変更するのは、作る側にも使う側にも負担でした。

そこで当時の装置では、LCDをなくすのではなく、日常操作をWebブラウザへ逃がしました。

  • LCDではIPアドレス、起動状態、異常を確認する
  • ブラウザでは装置状態の監視、設定変更、通常操作を行う

全体の姿は次のとおりです。装置は箱にLCDと操作ボタンを持ち、背面のLANポートで社内LANへつながります。装置のIPアドレスはLCDに出るので、ブラウザにはそれを打ちます。離れた席のPCからは、ブラウザで同じ装置を触ります。操作の入口は2つですが、書き換わる状態はひとつです。

装置の前で触るか、離れた席から触るか

この2つの経路が同じ状態を見ているという前提が、以降の話の土台になります。画面へ「自分が送った値」ではなく「装置が返した値」を出す理由も、ここから来ています。

本記事では、LinuxカーネルとBusyBox中心のrootfsへlighttpdとPHPを載せ、ブラウザのjQuery/AjaxからC製コンソールプログラムを呼ぶ構成を、公開用の小さなサンプルで再構成します。

この記事で分かること

  • BusyBox中心の小型Linux装置へWeb UIを足すときの役割分担
  • jQuery、Ajax、lighttpd、php-cgi、PHP、C製プログラムのつながり
  • AjaxからCを直接呼ぶのではなく、PHPを境界にする理由
  • LCDとWeb UIを競合させず、同じ装置制御機能へつなぐ考え方
  • 公開サンプルを通常のLinux上で動かす手順

この記事の前提

  • 対象読者:C言語とLinuxの基礎が分かり、小型装置へ管理画面を載せたい方
  • 前提知識:Cのコンソールプログラム、HTTP、HTML/JavaScriptの基礎
  • 対象範囲:信頼できるローカルネットワーク内の教材用構成
  • 扱わない範囲:認証、TLS、CSRF対策、インターネット公開、ハードリアルタイム制御
  • 経験時点:Intel SoC向けのPoky系Linux、lighttpd、php-cgi、PHP 5.6.38を使った装置開発
  • 公開サンプル:特定製品のソースではなく、記事用に新規作成した模擬装置

公開サンプルには認証やTLSがありません。そのまま製品へ組み込んだり、インターネットへ公開したりしないでください。

BusyBoxは「小さなOS」そのものではない

会話では「BusyBox Linuxを入れる」と表現することがありますが、厳密にはBusyBoxだけでOSが完成するわけではありません。

今回の装置は、次のような組み合わせを想定しています。

  • Linuxカーネル
  • BusyBoxを中心にした小さなユーザーランド
  • 起動スクリプトと設定ファイル
  • lighttpd
  • php-cgi
  • 装置制御用のCプログラム
  • HTML、CSS、JavaScript、PHPからなるWeb UI

Yocto Projectなどでrootfsを作る場合も、これらを必要なパッケージとして組み込むことになります。

LCDとWeb UIは競合ではなく、役割分担

Web UIを載せたからといって、LCDが不要になるわけではありません。

状況 LCD Web UI
起動直後 起動段階を表示 Webサーバ起動前は使えない
IPアドレス確認 装置単体で確認できる 接続先が分からないと開けない
ネットワーク障害 最後の確認手段になる 接続できない
日常操作 複雑な操作には不向き 一覧表示、入力、説明を置きやすい
状態監視 2行に収まる範囲 複数の値や履歴をまとめられる
致命的な異常 装置の前で確認できる Web処理自体が止まる場合がある

LCDは保守用、Web UIは日常操作用。この分け方にすると、2行LCDへすべての設定画面を押し込まずに済みます。

LCDをなくさず、日常操作をWeb UIへ分ける

ブラウザから装置までの経路

ブラウザから見ると、ボタンを押して装置が動くだけです。しかし内部では、次の層を通ります。

  1. jQueryが画面操作を受ける
  2. AjaxがHTTPリクエストを送る
  3. lighttpdがPHPへ処理を渡す
  4. PHPが操作名と値を検証する
  5. PHPのexec()がC製コンソールプログラムを起動する
  6. Cプログラムが装置固有の処理を行う
  7. 終了コードとJSONをPHP経由でブラウザへ返す

AjaxやjQueryがCプログラムを直接起動するわけではありません。ブラウザには、装置上のプロセスを直接実行する権限がないためです。

本記事で示すコードは、当時の製品ソースではなく、記事用に新規設計した公開サンプルです。当時の記録から確認できているのは、Poky系Linux、lighttpd、php-cgi、PHP 5.6.38という土台と、AjaxでPHPへ要求を送っていたことまでで、PHPからC側を起動する部分の実装詳細は、この記事の設計として作り直しています。以降の説明は、すべて公開サンプルの実装に沿って読んでください。

AjaxがCを直接呼ぶのではなく、PHPが境界になる

公開サンプルで動きを確認する

公開用サンプルはGitHubに公開しています。→ embedded-web-control-demo

構成は次のとおりです。

  • native/device_ctl.c:装置制御を担当するC製コンソールプログラム
  • www/api/device.php:HTTPの値を検証してCを呼ぶPHP
  • www/index.htmlwww/app.jswww/style.css:jQueryとAjaxのWeb UI
  • deploy/lighttpd.conf.example:lighttpdとphp-cgiの設定例
  • Makefile:ビルドと単体確認

実ハードウェアの代わりに、/tmp配下の状態ファイルを模擬装置として使います。ブラウザからSTART、STOP、0~100のレベル設定を行えます。

通常のLinuxで試す

必要なのは、C11コンパイラ、make、PHP、curlまたはwgetです。

make setup
make test
php -S 127.0.0.1:8080 -t www

ブラウザでhttp://127.0.0.1:8080/を開きます。

最初はPHP内蔵サーバで構いません。C、PHP、Ajaxの経路が動くことを確認してから、lighttpdへ切り替えます。これなら「lighttpd設定の問題」と「アプリケーションの問題」を分けて確認できます。

C製コマンドを単体で試す

Web UIより先に、装置制御プログラムを単体で確認します。

./bin/device_ctl status
./bin/device_ctl set-level 42
./bin/device_ctl start
./bin/device_ctl stop

正常時はJSONを標準出力へ返します。

{"ok":true,"running":false,"level":42,"updated_at":1785945600}

単体で動かないCプログラムをPHPから呼んでも、原因の切り分けが難しくなるだけです。下から順に確認するのが、この構成では一番早い方法です。

PHPは装置操作の翻訳役に限定する

公開サンプルのPHPは、次の4操作しか受け付けません。

  • status
  • start
  • stop
  • set_level

set_levelの値は0~100の整数へ制限します。Ajaxから受け取った文字列を、そのままシェルコマンドへ連結する入口は作りません。

HTTPのaction名はset_level、C側のサブコマンドはset-levelで、表記が異なります。誤記ではなく、PHPが「HTTPの語彙」を「装置制御コマンドの語彙」へ翻訳していることを示しています。PHPは検証済みの整数をset-levelという固定の文字列へ組み立て直してから渡します。

if ($action === 'status') {
    $command .= ' status';
} elseif ($action === 'start') {
    $command .= ' start';
} elseif ($action === 'stop') {
    $command .= ' stop';
} elseif ($action === 'set_level') {
    /* 0~100の整数を検証してから固定コマンドへ追加 */
} else {
    fail_response(400, 'unknown action');
}

PHPへ装置固有のレジスタ操作を書き始めると、Web UIとハードウェアが密結合になります。PHPはHTTPの値を検証し、C側が理解する装置機能へ翻訳するところまでにします。

公開サンプルでは、状態取得のstatusだけをGET、状態を変更するstartstopset_levelをPOSTに制限しています。JavaScript側でメソッドを使い分けるだけでなく、PHP側でも一致しない要求を405 Method Not Allowedとして拒否します。

C製コマンドを残した理由

C側をコンソールプログラムとして作っておくと、Web UIがなくてもSSHやシリアルコンソールから動作確認できます。

  • 単体試験しやすい
  • 終了コードで成功と失敗を返せる
  • 標準出力をPHPから取得できる
  • Web UI以外の保守ツールからも利用できる
  • PHPを変更せず、装置固有処理だけを差し替えられる

反面、Ajax要求のたびにプロセスを起動します。1秒程度の状態ポーリングや、人がボタンを押す頻度なら構成が単純という利点がありますが、高頻度の取得や長時間かかる制御には向きません。

その境界を越えたら、Cプログラムを常駐デーモンにし、PHPとはUnixドメインソケットなどで通信する構成を検討します。最初から常駐化するのではなく、必要になった時点で変える方が、小型装置では扱いやすい場合もあります。

Ajaxでリアルタイムっぽく見せる

公開サンプルでは、1秒ごとにstatusを取得します。STARTやレベル変更を送った直後は、応答を画面へ反映し、続けて状態を再取得します。

これは厳密なリアルタイム制御ではありません。

ブラウザ、PHPプロセス、Cプログラム、ドライバ、専用ハードウェアは、それぞれ異なる速度で動きます。短い周期で状態を確認し、操作中と失敗を明示することで、ユーザーから見た一貫性を作っています。

LCDの記事で扱った「異なる速度で動くものを、ユーザーから見て一貫しているように見せる」という考え方は、Web UIでも同じです。

詳しいポーリング周期、古い値の扱い、操作中表示は第2回で扱います。

実機へ置き換える場所

サンプルでは、Cプログラムが状態ファイルを読み書きします。実機へ移すときは、この部分だけを次の処理へ置き換えます。

  • デバイスファイルのreadwrite
  • ioctl
  • FPGA/ASICのレジスタ操作
  • 別CPUや制御プロセスとの通信

Web側へレジスタアドレスを見せるのではなく、startstopset-levelのような装置機能の言葉を保ちます。

これは以前のLCD記事で扱ったDeviceControlPortと同じ考え方です。LCDとWeb UIが別々に専用ハードウェアを触るのではなく、同じ装置制御境界を利用します。

この構成をそのまま製品へ載せない

教材サンプルは、層のつながりを確認することへ絞っています。製品へ載せるなら、少なくとも次が必要です。

  • 認証とセッション管理
  • TLSまたは信頼できる管理ネットワークへの限定
  • CSRF対策
  • 操作権限
  • 監査ログ
  • C処理のタイムアウト
  • 複数ブラウザとLCD操作の排他
  • Webサーバ実行ユーザーの最小権限化
  • エラー内容をそのままブラウザへ返さない処理

また、sudoersへ広い権限を与えて解決するのは避けます。必要なデバイスだけを専用グループへ許可する、あるいは権限を持つ常駐デーモンへ操作を限定する方が、境界を説明しやすくなります。

確認した範囲

確認日は2026-08-06です。環境はLinux(Ubuntu 24.04ベース)、PHP 8.4.21の内蔵サーバ、Chromium 141.0.7390.37のヘッドレスモード、gcc 13.3.0です。

lighttpd+php-cgi構成、組み込み実機(BusyBox中心のrootfs)、jQuery 3.7.1本体は未確認です。ブラウザ側の確認には最小のjQuery互換シムを使っています。

まとめ

  • LCDはIPアドレス、起動、異常を確認する保守用UIとして残します。
  • 日常的な監視と操作はWeb UIへ分けます。
  • jQuery/AjaxはPHPへHTTP要求を送り、PHPが許可済みのC製コマンドを呼びます。
  • PHPは入力検証と翻訳、Cは装置固有処理を担当します。
  • Ajaxポーリングはリアルタイム制御ではなく、ユーザーへ一貫した操作感を返すための仕組みです。
  • 公開サンプルは通常のLinuxで確認してから、BusyBox中心のrootfsへ持ち込めます。

次回は、状態取得を繰り返す周期、操作直後の表示、通信失敗時の古い値など、「リアルタイムではないものをリアルタイムに感じさせる」部分へ踏み込みます。

関連記事

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?