OpenWrtアプリケーション開発 LuCI用カスタムページの作成と追加(難易度Lv1)
この記事で紹介するソースコードは自由に使っていただいて構いません。 アプリケーションの開発や自己学習にお役立て下さい。ただし、当ブログでは掲載するソースコードを流用・利用したことによる損害等につきましては 一切の責任を負いません。自己責任で利用お願いします。
今回はOpenWrtアプリケーション開発として、自作のカスタムページをWebUIのLuCIに追加する方法を紹介します。
あくまでOpenWrtの既存機能やアプリケーションはそのままで、LuCIを通してユーザーに提供するページ(HTMLファイルやLuaスクリプト)を新たに作成・追加します。
このようなことから、この記事で紹介するカスタムページの実装難易度は最も簡単なLv1と定義します。
この記事を読んで恩恵がある読者は以下のような方です。
- これからOpenWrtのアプリケーション開発を学びたい人
- 自分にとって使いやすいユーザーインタフェース(設定画面)を作りたい人
- バグや機種未対応で正常に動作しないサービスに対して、適切にサービスを有効化できる設定画面を追加したい人
※3番目の方は、サービスが動作しない問題が設定パターンである場合に限ります。設定パターン以外の場合、標準アプリ自体のバグ (または、それに準ずるバグ)と考えられるため、ここで紹介する情報だけでは解決できません。
興味があれば、ご参考ください。
作成中の関連記事について
現在、本記事の関連として以下の記事を作成中です。この記事も合わせ、実装難易度を3段階に分けて紹介します。
- OpenWrtアプリケーション開発 自作スクリプトと連携するLuCI用プラグインの作成と追加(難易度Lv2)
- OpenWrtアプリケーション開発 自作UBUS対応アプリと連携するLuCI用プラグインの作成と追加(難易度Lv3)(作成中)
目次
- 実施環境と補足事項について
- サンプルプログラムのダウンロード案内
- 今回作成するLuCIカスタムページの概要
- カスタムページ作成の流れ
- 本題:開発準備
- 本題:カスタムページの作成
- 配布方法①:セットアップスクリプトの作成と実行
- 配布方法②:カスタムページのパッケージ作成とインストール
- LuCIがシステム内部で利用するUCI操作プロセス(/sbin/rpcd)について
- 【おまけ】Luaスクリプト用UBUSモジュールでカントリコード一覧を取得する方法
- おわりに
- 参考文献
実施環境と補足事項について
この記事は以下の環境で実施した結果を元に作成しています。
- #開発用PCの実行環境OS
- ubuntu 22.04 LTS 64bit ※今回はUbuntuで開発しましたが、Windows(WSL2)上でもOKです。
- #OpenWrtデバイス
- 名称:Raspberry Pi3 Model B
- CPU:ARM Cortex-A53 (1.2GHz)
- SOC:Broadcom BCM2837
- RAM:1GB
- ストレージ(media):MicroSDカード
- #OpenWrt
- OpenWrt 22.03
- パッケージ
- luci - git-24.078.77116-81496b8
- luci-compat - git-24.078.77116-81496b8
- luci-lua-runtime - git-24.078.77116-81496b8
この記事で紹介するカスタムページの作成と追加方法に関して、機種依存はありません。 この記事ではRaspberry Pi3BをOpenWrtデバイスとしていますが、どんなデバイスでもOKです。(※LuCIがインストールされていることが前提です。)
[補足事項]
記事内で紹介するコンソール表記は次の通りです。
- 開発用PCのコンソール表記
- ユーザー名とカレントディレクトリを色付けして表記します。
- OpenWrtのコンソール表記
- ユーザー名はroot@OpenWrtです。
user:~/openwrt$ command
root@OpenWrt:~# command
この記事が想定するOpenWrtデバイスの初期状態
この記事で想定するOpenWrtデバイスの状態は、OpenWrtがインストールされた直後の初期状態です。
IPアドレスに着目すれば、OpenWrtデバイス自身は192.168.1.1/24のIPアドレスを持ち、192.168.1.0/24のネットワークを管理しています。
サンプルプログラムのダウンロード紹介
この記事で作成するカスタムページのデータは以下の2通りの方法で入手できます。
セットアップスクリプトで自分のOpenWrtデバイスにインストールする
本記事のこちらを参照してください。
Gitリポジトリをクローンする
今回取り上げるLuCIのカスタムページ一式は私のGitHubリポジトリにあります。 パッケージ作成に必要なMakefileも揃った完全版です。
一応、この記事の内容に沿って1つずつ作業をしていけば、このリポジトリにあるものと同じものが作成できます。
記述ミスなどで躓いたら、以下のリポジトリをダウンロードして手っ取り早く動作を確認してみてください。
今回作成するLuCIカスタムページの概要
この記事で作成するLuCIのカスタムページは以下の動画で紹介するものです。例として、OpenWrt開発入門の第3回 と第4回の両方で紹介したアクセスポイント設定をカスタムページ経由で実施しています。
内部構成としては、既存のOpenWrtのLuCI環境にカスタムページを追加しただけです。
ネットワーク設定とWi-Fi設定のカスタムページを作りますので、ネットワーク・Wi-Fi制御用アプリケーションのnetifdが 管理する/etc/config/networkと/etc/config/wirelessの各オプションの値を変更・適用できます。
カスタムページ作成の流れ
この記事では、流れに沿って前節で紹介したLuCIのカスタムページを作成・追加します。
先ず開発準備として、OpnWrtデバイスに対してファイル転送する環境を整えた後、カスタムページ用のHTMLファイルやLuaスクリプトを 流し込んで動作を確認します。
全ての動作確認が取れたら他のユーザーに配布できるように、それらのファイルをセットアップスクリプトやアプリケーションパッケージにまとめます。
このように、本筋のカスタムページの作成と追加を一番簡単な方法で先に説明し、最後にセットアップスクリプトとパッケージの作成方法を紹介することで 一通りの開発方法が分かる構成になっています。
それでは、次節から本題に入ります。
本題:開発準備
LuCIのカスタムページを作成する前に開発準備をしましょう。
準備1:OpenWrtのインストール
当然ですが、まずはOpenWrtデバイスを用意しましょう。一応、私の記事にはRaspberry Pi1~5を対象にOpenWrtファームウェア をインストールする方法を紹介していますので、良ければ参考にしてみてください。
なお今回、LuCI(WebUI)は依存モジュールとしてluci-compatとluci-lua-runtimeを利用しますので、メニューコンフィグの該当項目に チェックを入れてください。
既にOpenWrtをデバイスにインストールした方
LuCIまたはコンソール上でluci-compatとluci-lua-runtimeを追加インストールしてください。 次はコンソール上でのインストール例です。
root@OpenWrt:~# opkg update
root@OpenWrt:~# opkg install luci-compat
root@OpenWrt:~# opkg install luci-lua-runtime <--- 正直、こちらは既にインストールされていると思います。
注意
OpenWrtデバイスのネットワーク接続が正常なのに上記のコマンド実行が失敗する場合、そのOpenWrtデバイス用のリポジトリに
そもそもluci-compatやluci-lua-runtimeパッケージが存在しない可能性があります。その場合はluci-compatとluci-lua-runtimeをプリインストールしたOpenWrtファームウェアイメージを
作成する必要があります。
準備2:OpenWrtデバイスと開発用PCを接続してコンソールにログインする
OpenWrtデバイスを用意できたら、次の図のようにLANケーブルでOpenWrtデバイスと開発用PCを繋いでください。
※図ではRaspberry PiがOpenWrtデバイスです。読者の方は、ご自身が持つOpenWrtデバイスとして考えてみてください。
OpenWrtデバイス(192.168.1.1/24)が管理するデフォルトのLANネットワークは192.168.1.0/24であり、SSHサーバーのdropbearが起動するようになっています。
また、SSHログインに必要な初期パスワード設定は無しのため、以下のコマンドを実行することでログインが成功します。
kamo@kamo:~$ ssh 192.168.1.1 -l root
準備3:SCPコマンドによるファイル転送方法を理解する
次に、UbuntuやWindowsで利用可能なSCPコマンドについて使い方を押さえましょう。
SCPコマンドは作成したカスタムページ(HTMLファイルやLuaスクリプト)をOpenWrtデバイスに転送するために使用します。
OpenWrtをインストールしたばかりのデバイス条件では、次のようにSCPコマンドを実行することでファイル転送が可能です。
kamo@kamo:~$ touch test-file kamo@kamo:~$ echo helloworld > test-file kamo@kamo:~$ scp ./test-file root@192.168.1.1:/root
上記は、開発用PCのカレントディレクトリ内のtest-fileをOpenWrtデバイス(192.168.1.1/24)の/rootディレクトリに転送した例です
これだけ押さえておけば、ひとまず大丈夫かと思います。もっと知りたい方はこちらを参照してみてください。
準備4:LuCIの変数キャッシュ機能をOFFにする
カスタムページをファイル転送して動作確認をする際に、LuCIのキャッシュ機能が最新Webページの表示を邪魔します。
そのため、LuCIのキャッシュ機能を表すUCIオプション(luci.ccache.enable)の値をOFFを示す0に変更してください。
root@OpenWrt:~# uci set luci.ccache.enable=0 root@OpenWrt:~# uci commit luci root@OpenWrt:~# reboot
本題:カスタムページの作成
その1:説明ページの作成と追加
最初に、静的なHTMLページを作成しましょう。
今回作成するHTMLページはこの記事で作成するカスタムページの説明文を掲載したものです。 そのため、先ずは開発PC上で、次のHTMLファイル(desc.htm)を作成してください。
※LuCI内の既存HTMLファイルに倣い拡張子を「.htm」としています。
-- desc.htm <%+header%> <!-- themeのheader部が紐付きます。 ThemeとはUIデザインのことです。--> <h1>[Desc] luci-app-sample01</h1> <p> This is the description page for luci-app-sample01.<br> luci-app-sample01 combines the wi-fi, router and access point configuration interfaces introduced in <a href="https://utakamo.com/article/openwrt/beginner/intro03.html">my blog article</a> into a single page. </p> <p> <strong>[Implementation difficulty Lv.1]</strong><br> This section allows you to modify the parameters in the OpenWrt network and wireless configuration files (/etc/config/network and /etc/config/wireless). In other words, it is a LuCI plugin that only manipulates the configuration files managed by the standard OpenWrt application. </p> <h2>What this app can do</h2> <ul> <li>Wi-Fi Settings</li> <li>Router Settings</li> <li>AP Settings</li> </ul> <h2>Page Link</h2> <ul> <li>[Desc] luci-app-sample01 /cgi-bin/luci/my/luci-app-sample01/desc (this page)</li> <li>Wi-Fi Setting (kamo custom) <a href="../../../../cgi-bin/luci/admin/network/custom-page/wireless"><device ip address>/cgi-bin/luci/admin/network/custom-page/wireless"</a></li> <li>Network Setting (kamo custom) <a href="../../../../cgi-bin/luci/admin/network/custom-page/network"><device ip address>/cgi-bin/luci/admin/network/custom-page/network"</a></li> </ul> <h2>Reference</h2> <p> The following references provide an implementation; developers familiar with OpenWrt should look here. </p> <ul> <li>luci Wiki: <a href="https://github.com/openwrt/luci/wiki">https://github.com/openwrt/luci/wiki</a></li> </ul> <%+footer%> <!-- themeのfooter部が紐付きます。 -->
HTMLファイルの作成が完了したら、次にカスタムページのルーティング設定を管理するコントローラースクリプトをLua言語で書いていきます。
Webサービスのルーティング設定とは?
昔ながらの方法で作成されたWebサイトは、ドキュメントルートのサーバー内ディレクトリを基点として、 そのディレクトリ内に配置した各ページの絶対パスがそのページにアクセスするためのURLになります。
しかし、それではURLを決定するために常にファイル(コンテンツ)の配置関係を意識しなくてはならず、コンテンツ管理の自由度が低いです。
そのため、近年ではルーティング設定を管理するスクリプトを通して、URLとコンテンツ配置の関係を分離した方法が取られています。
OpenWrtのLuCIでもルーティング設定が存在し、それが以下のLuaスクリプト(module.lua)になります。
desc.htmと同様に、開発PC上に次のmodule.luaを作成してください。
-- module.lua module("luci.controller.luci-app-sample01.module", package.seeall) function index() -- 以下の記述で、次のURLでアクセスできるようになります。<ip address ex) 192.168.1.1>/cgi-bin/luci/utakamo/luci-app-sample01/desc entry({"utakamo", "luci-app-sample01", "desc"}, template("luci-app-sample01/desc"), "desc", 20).dependent=false end
上記に掲載した2つのファイル(desc.htmとmodule.lua)を開発PC上で作成できたら、OpenWrtデバイス環境にアップロードします。
アップロードの準備として、OpenWrt環境上にアップロード先のディレクトリを作成する必要があります。
今回、ルーティング設定を管理するLuaスクリプトはmodule("luci.controller.luci-app-sample01", package.seeall) という文でLuCIにモジュールを公開しています。
そのため、OpenWrtデバイスのコンソール上で次のコマンドを実行することで、module.luaを管理するディレクトリ(/usr/lib/lua/luci/controller/luci-app-sample01)を作成します。
root@OpenWrt:~# mkdir -p /usr/lib/lua/luci/controller/luci-app-sample01 root@OpenWrt:~# mkdir -p /usr/lib/lua/luci/view/luci-app-sample01
作成できたら、今度は開発用PCのコンソール上で次のSCPコマンドを実行して、desc.htmとmodule.luaをOpenWrtデバイスの以下にアップロードします。
kamo@kamo:~$ scp ./module.lua root@192.168.1.1:/usr/lib/lua/luci/controller/luci-app-sample01 kamo@kamo:~$ scp ./desc.htm root@192.168.1.1:/usr/lib/lua/luci/view/luci-app-sample01
アップロード完了後、開発PCのWebブラウザーを開いてURL入力欄に「http://192.168.1.1/cgi-bin/luci/utakamo/luci-app-sample01/desc」と打ち込んでみてください。 すると、次のカスタムページ(desc.htm)が表示されます。
カスタムページ(desc.htm)がLuCIに反映されない場合
desc.htmとmodule.luaが以下のOpenWrtのディレクトリパスに格納されているか確認してください。
- /usr/lib/lua/luci/view/luci-app-sample01/desc.htm
- /usr/lib/lua/luci/controller/luci-app-sample01/module.lua
上記パス通りであれば、原因はキャッシュかもしれません。OpenWrtデバイスを再起動してください。
それでも表示されない場合、依存モジュールのluci-compatとluci-lua-runtimeがインストールされているか確認してください。
その2:ネットワーク設定ページの作成と追加
次はネットワーク設定用のページを追加します。
先ず最初に、上記で作成したmodule.luaに対して、ネットワーク設定用ページ(network.lua)のルーティング設定を追記します。
-- module.lua module("luci.controller.luci-app-sample01.module", package.seeall) function index() entry({"utakamo", "luci-app-sample01", "desc"}, template("luci-app-sample01/desc"), "desc", 20).dependent=false -- 以下を追記する entry({"admin", "network", "custom-page", "network"}, cbi("luci-app-sample01/network"), "Network Setting (kamo custom)", 30).dependent=false end
追記できたら、前回と同様に開発PCからOpenWrtデバイスに対してSCPコマンドを使用してmodule.luaをアップロードします。 ※OpenWrtデバイスに入っていた前回のmodule.luaは最新のmodule.luaに更新されます。
kamo@kamo:~$ scp ./module.lua root@192.168.1.1:/usr/lib/lua/luci/controller/luci-app-sample01
module.luaを更新できたら、次は肝心のネットワーク設定ページであるnetwork.luaを以下の内容で作成します。
-- network.lua -- [execut_cmd function] https://utakamo.com/article/lua/execute-cmd-from-lua/index.html execute_cmd = function(cmd) local handle = io.popen(cmd) local result = handle:read('*a') handle:close() return result end split = function(inputString, delimiter) local result = {} local pattern = string.format("([^%s]+)", delimiter) for match in inputString:gmatch(pattern) do table.insert(result, match) end return result end m = Map("network", "Network Setting (kamo custom)") s = m:section(TypedSection, "interface") s.addremove = true function s:filter(value) return value ~= "loopback" and value end s:depends("proto", "static") s:depends("proto", "dhcp") p = s:option(ListValue, "proto", "Protocol") p:value("static", "static") p:value("dhcp", "dhcp") p.default = "static" d = s:option(ListValue, "device", "Device") active_ifs = execute_cmd("ip link show up | awk '/^[0-9]+: / {print substr($2, 1, length($2)-1)}'") active_iflist = split(active_ifs, '\n') for _, v in ipairs(active_iflist) do d:value(v, v) end s:option(Value, "ipaddr", "ip"):depends("proto", "static") s:option(Value, "netmask", "Netmask"):depends("proto", "static") return m
ソースコードの内容について
上記のnetwork.luaはLuCI用のCBI(Configuration Bind Interface)関数を利用して、 UCI(Unified Configuration Interface)とWebUIのインタフェースをバインドしています。
詳細については、表示される設定画面の各インタフェースの対応を比較するか、ChatGPTや Microsoft Copilotにでも聞いてみてください。
なお、システムが認識している優先・無線インタフェースを取得するために、以下の記事で紹介した 方法(execute_cmd関数)を使用しています。
Luaプログラミング Luaから外部ソフトウェアを実行して結果を取得する方法
興味があれば、参照してみてください。
network.luaを作成できたら、OpenWrtデバイスにアップロードします。
前回同様に、予めOpenWrtデバイス側でnetwork.luaを格納する以下のディレクトリを作成します。
root@OpenWrt:~# mkdir -p /usr/lib/lua/luci/model/cbi/luci-app-sample01
ディレクトリを作成できたら、開発PC上で作成したnetwork.luaをOpenWrtデバイス環境にアップロードします。
kamo@kamo:~$ scp ./network.lua root@192.168.1.1:/usr/lib/lua/luci/model/cbi/luci-app-sample01
アップロード完了後、開発PCのWebブラウザーを開いてURL入力欄に「http://192.168.1.1/cgi-bin/luci/admin/network/custom-page/network」と打ち込んでみてください。 すると、ログイン画面が表示されますので、必要であればUsernameとPasswordを入力します。(OpenWrtインストール直後はUsernameは「root」、パスワードは無し(入力しない)です。)
ログインが成功すると、自作のネットワーク設定ページ(network.lua)が表示されます。
その3:Wi-Fi設定ページの作成と追加
次はWi-Fi設定用のページを追加します。
先ず最初に、上記で作成したmodule.luaに対して、ネットワーク設定用ページ(wireless.lua)のルーティング設定を追記します。
-- module.lua module("luci.controller.luci-app-sample01.module", package.seeall) function index() entry({"utakamo", "luci-app-sample01", "desc"}, template("luci-app-sample01/desc"), "desc", 20).dependent=false -- 以下を2行を追記する entry({"admin", "network", "custom-page"}, firstchild(), "CUSTOM PAGE", 30).dependent=false entry({"admin", "network", "custom-page", "wireless"}, cbi("luci-app-sample01/wireless"), "Wi-Fi Setting (kamo custom)", 30).dependent=false entry({"admin", "network", "custom-page", "network"}, cbi("luci-app-sample01/network"), "Network Setting (kamo custom)", 30).dependent=false end
追記できたら、前回と同様に開発PCからOpenWrtデバイスに対してSCPコマンドを使用してmodule.luaをアップロードします。 ※OpenWrtデバイスに入っていた前回のmodule.luaは最新のmodule.luaに更新されます。
kamo@kamo:~$ scp ./module.lua root@192.168.1.1:/usr/lib/lua/luci/controller/luci-app-sample01
module.luaを更新できたら、次は肝心のWi-Fi設定ページであるwireless.luaを以下の内容で作成します。
-- wireless.lua ubus = require("ubus") -- [References] https://openwrt.org/docs/techref/ubus#lua_module_for_ubus ubus_call = function(path, method, json_param) local conn = ubus.connect() if not conn then return end local result = conn:call(path, method, json_param) return result end m = Map("wireless", "Wi-Fi Setting (kamo custom)") radio = m:section(TypedSection, "wifi-device") radio.addremove = true function radio:filter(value) return value end wave = radio:option(ListValue, "disabled", "Wi-Fi Carrier Wave") wave:value("1", "OFF") wave:value("0", "ON") country_code = radio:option(ListValue, "country", "COUNTRY") wlan = ubus_call("iwinfo", "devices", {}) if #wlan.devices >= 1 then countrylist = ubus_call("iwinfo", "countrylist", {device = wlan.devices[1]}) for _, item in ipairs(countrylist.results) do country_code:value(item.code, item.country) end end txpower = radio:option(ListValue, "txpower", "TXPOWER") if #wlan.devices >= 1 then txpowerlist = ubus_call("iwinfo", "txpowerlist", {device = wlan.devices[1]}) for _, result in ipairs(txpowerlist.results) do if (result.dbm >= 6) and (result.dbm <= 10) then txpower:value(result.mw, result.dbm .. "dBm") end end end default_radio = m:section(TypedSection, "wifi-iface") default_radio.addremove = true function default_radio:filter(value) return value end -- [References] https://openwrt.org/docs/guide-user/network/wifi/basic#common_options encryption = default_radio:option(ListValue, "encryption", "ENCRYPTION") encryption:value('none', 'no authentication') encryption:value('psk+tkip+ccmp', 'WPA Personal (PSK)') encryption:value('psk2', 'WPA2 Personal (PSK)') encryption:value('sae', 'WPA3 Personal (SAE)') default_radio:option(Value, "ssid", "SSID") key = default_radio:option(Value, "key", "KEY") key:depends("encryption", 'psk+tkip+ccmp') key:depends("encryption", 'psk2') key:depends("encryption", 'sae') key.password = true return m
wireless.luaを作成できたら、OpenWrtデバイスにアップロードします。
格納先であるOpenWrtデバイスのディレクトリは上記で既に作っていますので、次のSCPコマンドで開発PC上のwireless.luaをOpenWrtデバイスにアップロードします。
kamo@kamo:~$ scp ./wireless.lua root@192.168.1.1:/usr/lib/lua/luci/model/cbi/luci-app-sample01
これで、今回のカスタムページの作成と追加は完了です。
一連の動作を見てみます。
先ず、開発PCのWebブラウザーのURL入力覧に「http://192.168.1.1」と打ち込んでみてください。 ログイン画面が表示されますので、必要であればUsernameとPasswordを入力します。(OpenWrtインストール直後はUsernameは「root」、パスワードは無し(入力しない)です。)
すると、LuCIの管理画面トップが表示されますので、「Network」プルダウンメニューの中から「CUSTOM PAGE」をクリックします。
これで、今回作成したネットワーク設定ページが表示されます。
また、ネットワーク設定ページのタブからWi-Fi設定ページにも遷移できることが分かります。
これら設定ページの各項目は対象のUCIコンフィグレーションファイル(/etc/config/network、 /etc/config/wireless)と紐づいているため、UI上の項目を通した設定変更が反映されます。
配布方法①:セットアップスクリプトの作成と実行
今回作成したカスタムページは、特定のハードウェアに依存したものではありません。
そのため、配布方法②で紹介するようなインストールパッケージを用意しなくてもOpenWrtデバイスに適用することができます。
ハードウェアに依存しないモジュールを配布する場合はここで紹介する方法も便利です。
それでは作成していきましょう。
Webサーバーの配布用URL(リポジトリ)を決定する
前節で作成したカスタムページを配布するために、まずはサーバーを用意します。
私の場合、GitHubでソース管理をしていますので、GitHubをサーバー代わりにします。
GitHubのリポジトリを作成し、カスタムページ一式を収録したアーカイブファイルと それをダウンロードするスクリプト(セットアップスクリプト)をアップロードします。
今回、私は次のURLで示すGitHubリポジトリを用意しました。
https://github.com/utakamo/UtakamoStudyApps/raw/main/luci-plugin/luci-app-sample01/setup
このリポジトリに対して、次に説明するアーカイブファイルとセットアップスクリプトをアップロードしていきます。
アーカイブファイルの作成
最初に、前節で作成した各カスタムページ用のLuaスクリプトとHTMLファイルを次のディレクトリ・ファイル構成になるように整理します。
上記の構成からアーカイブファイルを作成します。親のディレクトリであるluci-app-sample01を指定して次のコマンドを実行します。
kamo@kamo:~$ tar zcvf luci-app-sample01.tar.gz ./luci-app-sample01 ./luci-app-sample01/ ./luci-app-sample01/files/luasrc/ ./luci-app-sample01/files/luasrc/controller/ ./luci-app-sample01/files/luasrc/controller/module.lua ./luci-app-sample01/files/luasrc/model/ ./luci-app-sample01/files/luasrc/model/cbi/ ./luci-app-sample01/files/luasrc/model/cbi/network.lua ./luci-app-sample01/files/luasrc/model/cbi/wireless.lua ./luci-app-sample01/files/luasrc/view/ ./luci-app-sample01/files/luasrc/view/cbi/ ./luci-app-sample01/files/luasrc/view/cbi/desc.htm
作成できたアーカイブファイル(luci-sample01-app.tar.gz)は次で説明するセットアップスクリプトを使って展開し、 その中のファイルとスクリプトをOpenWrtデバイスの環境に配置します。
このアーカイブファイルは上記で説明したGitHubリポジトリにアップロードします。
これによって、このアーカイブは以下のURLでダウンロードが可能になりました。
https://github.com/utakamo/UtakamoStudyApps/raw/main/luci-plugin/luci-app-sample01/setup/luci-app-sample01.tar.gz
セットアップスクリプト(setup-sample01)の作成
最後にセットアップスクリプトを作成します。
上記で作成したアーカイブファイルをOpenWrtデバイスのローカル環境にダウンロードして、 展開をした後に適切なディレクトリに各ファイルをコピーするだけの簡単なスクリプトです。
#/bin/sh #setup-sample01 DOWNLOAD_URL="https://github.com/utakamo/UtakamoStudyApps/raw/main/luci-plugin/luci-app-sample01/setup/luci-app-sample01.tar.gz" TEMP_ARCHIVE_1="/tmp/luci-app-sample01.tar.gz" TEMP_ARCHIVE_2="/tmp/luci-app-sample01.tar" EXTRACT_DIR="/tmp/luci-app-sample01" SRC_DIR="$EXTRACT_DIR/files/luasrc" DST_DIR="/usr/lib/lua/luci" help() { echo "setup-sample01 install ... install luci-app-sample01" echo "setup-sample01 remove ... remove luci-app-sample01" } delete_archive_file() { rm -rf "$TEMP_ARCHIVE_1" rm -rf "$TEMP_ARCHIVE_2" rm -rf "$EXTRACT_DIR" } remove_install_file() { rm -rf "$DST_DIR/view/luci-app-sample01/" rm -rf "$DST_DIR/model/cbi/luci-app-sample01" rm -rf "$DST_DIR/controller/luci-app-sample01/" } install() { if ! opkg list-installed luci-compat | grep -q "luci-compat"; then echo -n "Do you want to install the luci-compat package? (Y/N) :" read reply if [ "$reply" = "Y" ]; then opkg update if ! opkg install luci-compat; then exit 1 fi else echo "luci-app-sample01 install cancelled." exit 1 fi fi # download wget --no-check-certificate -O "$TEMP_ARCHIVE_1" "$DOWNLOAD_URL" if [ "$?" -ne 0 ]; then echo "Failed to download $DOWNLOAD_URL" >&2 exit 1 fi # expands mkdir -p "$EXTRACT_DIR" gunzip -c "$TEMP_ARCHIVE_1" | tar -x -C /tmp if [ "$?" -ne 0 ]; then echo "Failed to extract $TEMP_ARCHIVE_1" >&2 delete_archive_file exit 1 fi # remove previous file for reinstall remove_install_file # create dir and copy mkdir -p "$DST_DIR/view/luci-app-sample01" mkdir -p "$DST_DIR/model/cbi/luci-app-sample01" mkdir -p "$DST_DIR/controller/luci-app-sample01" cp -a "$SRC_DIR/view/cbi/desc.htm" "$DST_DIR/view/luci-app-sample01/" cp -a "$SRC_DIR/model/cbi/network.lua" "$DST_DIR/model/cbi/luci-app-sample01/" cp -a "$SRC_DIR/model/cbi/wireless.lua" "$DST_DIR/model/cbi/luci-app-sample01/" cp -a "$SRC_DIR/controller/module.lua" "$DST_DIR/controller/luci-app-sample01/" delete_archive_file echo "Setup completed successfully" echo -n "System Reboot? (Y/N) :" read reboot if [ "$reboot" = Y ]; then reboot fi } remove() { remove_install_file echo "Remove completed successfully" } if [ "$1" = "install" ]; then install elif [ "$1" = "remove" ]; then remove else help fi
このセットアップスクリプトも作成後は、リポジトリにアップロードします。
そして、アップロードすると今回は以下のURLでダウンロードできるようになりました。
https://raw.githubusercontent.com/utakamo/UtakamoStudyApps/main/luci-plugin/luci-app-sample01/setup/setup-sample01
後はユーザーに、このセットアップスクリプトの使用方法をアナウンスすればいいだけです。
ということで、次はこのスクリプトを使ってOpenWrtデバイスにカスタムページを適用してみます。
セットアップスクリプトを利用してOpenWrtデバイスにカスタムページを適用する
それでは、実際にセットアップスクリプトをリポジトリから入手してカスタムページを OpenWrtデバイスに適用してみます。
カスタムページを適用したいOpenWrtデバイスのコンソール上で次のコマンドを実行して、 セットアップスクリプト(setup-sample01)をダウンロードします。
root@OpenWrt~:# wget https://raw.githubusercontent.com/utakamo/UtakamoStudyApps/main/luci-plugin/luci-app-sample01/setup/setup-sample01
時刻情報の不一致で、SSL認証エラーが発生してダウンロードできない場合の対処
OpenWrtデバイス側でwgetコマンドを実行すると、SSL認証に失敗してダウンロードができない場合があります。 大体の原因は時刻情報なので、dateコマンドを実行して現在時刻が正しいか確認してください。
root@OpenWrt:~# date
システムが認識している現在時刻が正しくない場合は、次のコマンドでNTPサーバーから時刻を取得してください。
/etc/init.d/sysntpd restart
これでも、wgetコマンドでダウンロードできない場合は-no-check-certificateオプションを付けて実行してください。
wget --no-check-certificate https://raw.githubusercontent.com/utakamo/UtakamoStudyApps/main/luci-plugin/luci-app-sample01/setup/setup-sample01
次に、このセットアップスクリプトを実行します。
root@OpenWrt:~# chmod +x setup-sample01 root@OpenWrt~:# ./setup-sample01 install Setup completed successfully System Reboot? (Y/N) :Y
これでカスタムページの適用が完了しました。
システムブート後にカスタムページのURLにアクセスしてみると、正常にページが表示されることが確認できます。
注意:セットアップスクリプトが失敗する場合
次のエラーが発生する場合、今回のプラグインの依存パッケージである luci-compatパッケージがお使いのデバイス用リポジトリに存在しないことが考えられます。
Unknown package 'luci-compat'. Collected errors: * opkg_install_cmd: Cannot install package luci-compat.
OpenWrtは様々なデバイス上で動作するOSですが、ハードウェア依存のあるアプリケーションパッケージはそのハードウェア用にビルドしなければなりません。 お使いのデバイスによっては、パッケージのビルドとリポジトリの更新が間に合っていない、そもそも止まっているなどの理由で欲しいパッケージ の情報がopkg updateで入手できない場合があります。
そのため、どうしてもインストールしたいパッケージがある場合は、ユーザーご自身が用意したPC(Linux)にOpenWrtのbuildrootを 構築し、インストールしたいパッケージを指定してビルドする必要があります。
配布方法②:カスタムページのパッケージ作成とインストール
ここでは、作成したカスタムページ(LuaスクリプトとHTMLファイル)を配布するために、 luci-app-sample01という名前でパッケージを作成してみます。
この方法では、パッケージ自体が特定のハードウェア用(今回の場合はターゲットのRaspberry Pi3B)のものになるので、
配布のしにくさがデメリットです。
逆にパッケージマネージャーソフトのopkgで管理できることがメリットになりますが、
今回はハードウェアに依存するようなバイナリファイルはありませんので、そのメリットは薄いです。
※全てのターゲットシステム(ハードウェア)をインストール対象にするパッケージが作成できましたので 上記の説明は取り消します。
それでは行ってみます。
この記事の内容で作成したluci-app-sample01パッケージ
ちなみに、この記事の内容で作成したパッケージは私のGitHub上で管理されていますので、 次のコマンド実行でインストール可能です。
root@OpenWrt:~# wget --no-check-certificate https://github.com/utakamo/UtakamoStudyApps/raw/refs/heads/main/luci-plugin/luci-app-sample01/setup/luci-app-sample01_1.0-r1_all.ipk root@OpenWrt:~# opkg update root@OpenWrt:~# opkg install luci-app-sample01_1.0-r1_all.ipk
インストール完了後に再起動すれば、プラグインが利用可能になります。
手順1:パッケージ作成のためのディレクトリ管理
最初に、前節で作成した各カスタムページ用のLuaスクリプトとHTMLファイルを次のディレクトリ・ファイル構成になるように整理します。 ※以下の図にあるMakefileは次節で作成します。
上図のディレクトリ構成で各カスタムページが管理されているものとして、 パッケージ作成用のMakefileを記述します。
手順2:パッケージ用Makefileの作成
手順1で作成したUtakamoStudyApps/luci-plugin/luci-app-sample01直下に次のMakefileを作成します。
#~/UtakamoStudyApps/luci-plugin/luci-app-sample01/Makefile
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-sample01
PKG_VERSION:=1.0
PKG_RELEASE:=1
SOURCE_DIR:=./files/luasrc
LUA_LIBRARYDIR = /usr/lib/lua
LUCI_LIBRARYDIR = $(LUA_LIBRARYDIR)/luci
LUCI_MODULEDIR = $(LUCI_LIBRARYDIR)/controller
LUCI_MODELDIR = $(LUCI_LIBRARYDIR)/model/cbi
LUCI_VIEWDIR = $(LUCI_LIBRARYDIR)/view
include $(INCLUDE_DIR)/package.mk
define Package/luci-app-sample01
CATEGORY:=utakamo
SECTION:=utakamo
TITLE:=luci sample application
DEPENDS:=+luci-compat
PKGARCH:=all
endef
define Build/Compile
endef
define Package/luci-app-sample01/install
$(INSTALL_DIR) $(1)$(LUCI_MODULEDIR)/luci-app-sample01
$(INSTALL_DATA) $(SOURCE_DIR)/controller/module.lua $(1)$(LUCI_MODULEDIR)/luci-app-sample01
$(INSTALL_DIR) $(1)$(LUCI_MODELDIR)/luci-app-sample01
$(INSTALL_DATA) $(SOURCE_DIR)/model/cbi/network.lua $(1)$(LUCI_MODELDIR)/luci-app-sample01
$(INSTALL_DATA) $(SOURCE_DIR)/model/cbi/wireless.lua $(1)$(LUCI_MODELDIR)/luci-app-sample01
$(INSTALL_DIR) $(1)$(LUCI_VIEWDIR)/luci-app-sample01
$(INSTALL_DATA) $(SOURCE_DIR)/view/cbi/desc.htm $(1)$(LUCI_VIEWDIR)/luci-app-sample01
endef
$(eval $(call BuildPackage,luci-app-sample01))
今回のMakefileはコンパイルが必要なソースファイルは含みませんので、define Build/Compileの文は空の状態です。 (もし、コンパイルしなければ行けないC言語ソースファイルがある場合はターゲットシステムを全て(all)にしてパッケージを作成することは得策ではありません。)
define Package/luci-app-sample01/installの文は、各ファイルをインストール先のOpenWrtデバイス環境と対になったパッケージ環境($(1) にコピーする処理です。
これで手順1で各ディレクトリの中に格納したHTMLファイルやLuaスクリプトが、$(1)で示されるパッケージ環境 の各ディレクトリ階層に配置されるようになります。
パッケージのターゲットシステム(ハードウェア)を全て(all)にするには?
今回作成するパッケージの中身はスクリプトのため、特定のアーキテクチャやシステム、ハードウェアに依存したものではありません。 そのため、パッケージのターゲットシステムをallにしておいた方が便利です。
パッケージのターゲットシステムをallにするには、上記Makefileに記載されている通り、PKGARCH:=all の文を記述します。
パッケージのビルド
次は、上記で作成したパッケージ作成用のMakefileをOpenWrtのbuildrootにfeed情報としてインストールしてビルドします。
まず、カスタムページ(Luaスクリプト・HTMLファイル)とMakefileを格納したディレクトリの親ディレクトリである UtakamoStudyAppsまでのフルパスを~/openwrt/feeds.confの内容として以下のように記述します。
kamo@kamo:~/openwrt$ nano feeds.conf # feeds.confの記載例 # パッケージパスはご自身の環境を確認の上、記述してください # src-link [フィード名] [パッケージパス] src-link utakamo /home/kamo/UtakamoStudyApps
次に、以下のコマンドでbuildrootでカスタムページのMakefileを読み込ませ、utakamo feed情報としてインストールします。
kamo@kamo:~/openwrt$./scripts/feeds update -a kamo@kamo:~/openwrt$./scripts/feeds install -a -p utakamo
正常にfeed情報がインストールできたら、make menuconfigで設定画面を表示します。
kamo@kamo:~/openwrt$ make menuconfig
一覧の中に「utakamo」という項目がありますので、これを選択します。
すると、「utakamo」の中に今回作成したLuCIのカスタムページ用パッケージの「luci-app-sample01」がありますので、これにチェックを入れます。
その後、変更を保存して設定画面(メニューコンフィグ)を終了します。※Exitを選択すると、終了する前に変更内容を保存するか聞かれますので「YES」を選んでください。
コンソールに操作が戻ってきますので、次のMakeコマンドでluci-app-sample01パッケージを作成してください。
kamo@kamo:~/openwrt$ make package/luci-app-sample01/compile
正常にパッケージ作成が完了すると、openwrt/bin/packages/<chip name>/utakamoに作成されたパッケージ本体(.ipk)があります。 ※今回は全ターゲットシステム向けのパッケージを作成しましたので、luci-app-sample01_1.0-r1_all.ipkという名前でパッケージが出来上がりました。
kamo@kamo:~/openwrt/bin/packages/aarch64_cortex-a53/utakamo$ ls Packages Packages.gz Packages.manifest Packages.sig index.json luci-app-sample01_1.0-r1_all.ipk
これでパッケージ作成は完了です。
パッケージのインストール
上記で作成したパッケージをOpenWrtデバイスに転送してインストールします。
SCPコマンドを次のように使用することで、はOpenWrtデバイスに転送できます。 ※もちろん、いろいろなファイル転送のいづれかで作成したパッケージをOpenWrtデバイス環境に転送することができればOKです。
kamo@kamo:~/openwrt/bin/packages/aarch64_cortex-a53/utakamo$ scp ./luci-app-sample01_1.0-r1_all.ipk root@192.168.1.1:/root
OpenWrtデバイスにパッケージを転送後、OpenWrtのコンソール上で次のコマンドを実行することでインストールします。
root@OpenWrt~:# opkg update <--- luci-app-sample01はluci-compatを依存パッケージとするので、その情報を確実にシステム認識させるためにupdateを実行します。
root@OpenWrt~:# opkg install luci-app-sample01_1.0-r1_all.ipk
以上で、LuCI用カスタムページの作成と追加からパッケージ作成について紹介しました。
注意:luci-app-sample01パッケージのインストールに失敗する場合
次のエラーが発生する場合、今回のサンプルパッケージ(luci-app-sample01)の依存パッケージである luci-compatパッケージがお使いのデバイス用リポジトリに存在しないことが考えられます。
root@OpenWrt:~# opkg install luci-app-sample01_1.0-r1_all.ipk Unknown package 'luci-app-sample01'. Collected errors: * pkg_hash_check_unresolved: cannot find dependency luci-compat for luci-app-sample01 * pkg_hash_fetch_best_installation_candidate: Packages for luci-app-sample01 found, but incompatible with the architectures configured * opkg_install_cmd: Cannot install package luci-app-sample01.
OpenWrtは様々なデバイス上で動作するOSですが、ハードウェア依存のあるアプリケーションパッケージはそのハードウェア用にビルドしなければなりません。 お使いのデバイスによっては、パッケージのビルドとリポジトリの更新が間に合っていない、そもそも止まっているなどの理由で欲しいパッケージ の情報がopkg updateで入手できない場合があります。
そのため、どうしてもインストールしたいパッケージがある場合は、ユーザーご自身が用意したPC(Linux)にOpenWrtのbuildrootを 構築し、インストールしたいパッケージを指定してビルドする必要があります。
LuCIがシステム内部で利用するUCI操作プロセス(/sbin/rpcd)について
LuCIのページ上でユーザーに提供する設定項目の大半は、OpenWrtアプリケーションの環境変数であるUCIコンフィグレーションファイルと紐づいています。
例えば、ユーザーがLuCIのネットワーク設定ページからIPアドレスなどを変更すると、対応するUCIコンフィグレーションファイル(例:/etc/config/network)に変更内容が書き込まれ、 そのコンフィグレーションファイルを環境変数とするOpenWrtアプリケーション(例:netifd)が現在の設定を読み込み直し、ユーザーによる設定変更がシステムに適用されます。
UCIコンフィグレーションファイルに対する直接的な操作はUCIコマンド(/usr/bin/uci)がサポートします。ユーザー自身がOpenWrtデバイスの コンソール画面からroot@OpenWrt:~# uci set network.lan.ipaddr=192.168.2.1などのように実行することでも 設定に変更を加えることが可能です。
UCIコマンド(/usr/bin/uci)の詳細について
以下の記事で、内部の仕組みや使い方について紹介しています。この節の説明についてより深い理解を得たい方、興味がある方は参考にしていただければと思います。
そのため、コンソール上でUCIコマンドを利用して設定内容を頻繁に変更している人から見ると、 「LuCIもユーザーによる設定変更を受けたら、内部でUCIコマンド(/usr/bin/uci)を使ってUCIコンフィグレーションファイルを操作している」と思うかもしれません。
しかし実際には、LuCIはこのUCIコマンド(/usr/bin/uci)をシステム内部で利用していません。
LuCIがシステム内部で利用しているのは、UCIコマンド(/usr/bin/uci)と同等な機能を持ち、UBUSによるプロセス間通信とセッション 管理機能を持つRPC対応版のUCIコマンド(/sbin/rpcd)です。
このRPC対応版のUCIコマンド(/sbin/rpcd)は、いつ来るか分からないUCI操作リクエストのためにシステムブート時から稼働しているUBUS対応アプリケーション(daemon)でもあります。
RPC対応版UCIコマンドのクライアントはネットワークを通して繋がり、LuCIによってUI提供されているユーザーPC(ホスト)です。そのため、同時に複数台のクライアントがLuCIによる設定ページを 通してUCI操作をすることを想定して、セッション管理をサポートしています。
詳細な動作については以下の通りです。
LuCIが使用するRPC対応版UCIコマンドの仕組み(処理の流れ)
ここでは、2台のクライアントデバイス(PC)がLuCIのWebUIにアクセスして、それぞれがIPの設定変更をしたと仮定します。
このとき、それぞれのクライアントデバイスからIPアドレスの設定変更要求を受けたLuCIは、UCI操作プロセスの/sbin/rpcd に対して、UBUS経由で設定変更を通知します。
※LuCIは内部でubus call uci set '{"config":"network","section":"wan","type":"interface","match":"","values":{"ipaddr":"192.168.3.1"},"ubus_rpc_session":<session>}' などのUBUSコマンドを実行しています。
このとき、各デバイスのIP設定の変更は、それらデバイスのセッション番号に紐づいたステージング領域(RAM)に一時保存されます。
セッション番号に紐づいたステージング領域は、/sbin/rpcdによって割り当てられたメモリ領域(/tmp/run/rpcd/uci-<ubus_rpc_session>)です。
上図では、2台のクライアントデバイスの各セッション(Session A、Session B)ごとにステージング領域(①、②)が 動的に作成され、その中に変更内容である192.168.3.1と 192.168.2.1が格納されています。
ステージング領域にある任意のIP設定はUCIオブジェクトのapplyメソッドを利用することでコンフィグ(今回では/etc/config/network)にマージすることができます。 これにより、対応アプリケーションの環境変数として使用できます。
上図では、Session Aの変更内容である192.168.3.1をapplyメソッドの実行によって適用しています。 applyメソッドは、タイムアウト時間内にネットワーク通信が確認できない場合、元の設定状態にロールバックできます。
ネットワーク通信が確認できた場合は、設定変更を確定します。
これにより、設定変更がフラッシュ領域のコンフィグ(今回の場合は/etc/config/network)に書き込まれます。
このように、LuCI経由で実施される設定変更はUBUSとUCI操作プロセスにより、実現されます。
【おまけ】ユーザーPCとLuCIのUBUS通信を見てみる
上記で説明したLuCIとユーザーPCのやり取りの一部はUBUSのmonitorコマンドで見ることができます。
確認するには、OpenWrtデバイス側のコンソールで次のUBUSコマンドを実行します。
root@OpenWrt:~# ubus monitor
後は、LuCIを通して何らかの設定を変更すれば、その時の通信内容(UBUSへのリクエスト含む)がログとして出力されます。
次はネットワークのIPアドレス設定を192.168.1.1から192.168.2.1に変更したときのUBUS monitorコマンドのログ出力の抜粋です。 (IPアドレスの設定項目に192.168.2.1を入力して、SAVEボタンを押した時の内容になります。)
root@OpenWrt:~# ubus monitor
...省略...
: {"objpath":"uci"}
-> ce806aa2 #00000000 data: {"objpath":"uci","objid":2098094064,"objtype":208355174,"signature":{"configs":{},"get":{"config":3,"section":3,"option":3,"type":3,"match":2,"ubus_rpc_session":3},"state":{"config":3,"section":3,"option":3,"type":3,"match":2,"ubus_rpc_session":3},"add":{"config":3,"type":3,"name":3,"values":2,"ubus_rpc_session":3},"set":{"config":3,"section":3,"type":3,"match":2,"values":2,"ubus_rpc_session":3},"delete":{"config":3,"section":3,"type":3,"match":2,"option":3,"options":1,"ubus_rpc_session":3},"rename":{"config":3,"section":3,"option":3,"name":3,"ubus_rpc_session":3},"order":{"config":3,"sections":1,"ubus_rpc_session":3},"changes":{"config":3,"ubus_rpc_session":3},"revert":{"config":3,"ubus_rpc_session":3},"commit":{"config":3,"ubus_rpc_session":3},"apply":{"rollback":7,"timeout":5,"ubus_rpc_session":3},"confirm":{"ubus_rpc_session":3},"rollback":{"ubus_rpc_session":3},"reload_config":{}}}
-> ce806aa2 #00000000 status: {"status":0}
#以下のログからUCIオブジェクトのsetメソッドがセッション番号[12f8439dc10ee9d90a81180472116bfa]に使用されたことが分かる
<- ce806aa2 #7d0e5ff0 invoke: {"objid":2098094064,"method":"set","data":{"ubus_rpc_session":"12f8439dc10ee9d90a81180472116bfa","config":"network","values":{"ipaddr":"192.168.2.1"},"section":"lan"}}
-> b7d95343 #ce806aa2 invoke: {"objid":2098094064,"method":"set","data":{"ubus_rpc_session":"12f8439dc10ee9d90a81180472116bfa","config":"network","values":{"ipaddr":"192.168.2.1"},"section":"lan"},"user":"root","group":"root"}
<- b7d95343 #ce806aa2 status: {"status":0,"objid":2098094064}
-> ce806aa2 #7d0e5ff0 status: {"status":0,"objid":2098094064}
...省略...
このログを見ると、LuCIがUCI操作プロセス(/sbin/rpcd)を利用してUCIコンフィグレーションファイルに対する操作をしていることが分かります。
上記の内容では、セッション番号[12f8439dc10ee9d90a81180472116bfa]によるnetworkコンフィグへの変更(192.168.2.1)がUCIオブジェクトのsetメソッドによって実施されたことが分かります。
setメソッドはステージング領域に変更情報を書き込む機能なので、セッション番号に紐づいた動的メモリ内に変更差分が記録されたことが推測できます。
このことを裏付けるために、ステージング領域の内容を見るchangesメソッドを実行してみます。
root@OpenWrt:~# ubus call uci changes '{"config":"network", "ubus_rpc_session":"12f8439dc10ee9d90a81180472116bfa"}' { "changes": [ [ "set", "lan", "ipaddr", "192.168.2.1" ] ] }
上記から、セッション番号に紐づいたステージング領域にIPアドレスの変更が入っていることが確認できます。
【おまけ】Luaスクリプト用UBUSモジュールでカントリコード一覧を取得する方法
UBUSによるプロセス間通信を利用して、iwinfoオブジェクトからカントリーコードを取得するLuaスクリプトを掲載します。
これは、カスタムページのWi-Fi設定画面(wireless.lua)を作る際にできたテストコードです。もったいないので掲載することにしました。
この処理はカントリコード用のプルダウンメニューに各コードに対応する国名を表示するために利用しています。
OpenWrtデバイス上のどこでも良いので、以下のスクリプトを置いて実行してみると国情報の一覧が取得できます。
-- country.lua
ubus = require("ubus")
ubus_call = function(path, method, json_param)
local conn = ubus.connect()
if not conn then
return
end
local result = conn:call(path, method, json_param)
return result
end
wlan = ubus_call("iwinfo", "devices", {})
for _, value in ipairs(wlan.devices) do
print("--->" .. value)
end
countrylist = {}
if #wlan.devices >= 1 then
countrylist = ubus_call("iwinfo", "countrylist", {device = wlan.devices[1]})
else
return
end
print("wlan.devices length = " .. #wlan.devices)
print("wlan.devies[1] = " .. wlan.devices[1])
print("countrylist length = " .. #countrylist)
for _, item in ipairs(countrylist.results) do
print(item.country .. ' ---> ' .. item.code)
end
上記のLuaスクリプトは、OpenWrtのコンソール上で次のUBUSコマンドを実行したときと同等の結果になります。
# 例)interface : wlan0で国情報を取得する例 root@OpenWrt:~# ubus call iwinfo countrylist '{"device":"wlan0"}' # 引数のWLANインタフェースはシステムが認識しているものである必要があります。 # 次のUBUSコマンドでWLANインタフェースの一覧が取得できます。 # root@OpenWrt:~# ubus call iwinfo devices
このように、UBUSを使用してWi-Fiドライバーにカントリーコードとして解釈できる設定値の組を教えてもらうことにより、 Wi-Fiチップ&ドライバーの差異をLuCIのWebUI層で抽象化することができます。
ただし、このような情報を提供してくれるかはハードウェア・ドライバーのサポートに依存します。
おわりに
今回は、LuCI用のカスタムページを作成して追加する方法を紹介しました。
この記事の内容で、UIを自分好みのものにカスタマイズできるようになります。
しかし、より深くアプリケーション開発をしたいと考えると、今回の知識では物足りません。
自作ソフトウェア(スクリプト含む)とLuCIとのプロセス間通信(IPC/RPC)も押さえておく必要があります。
さらに深い知識を理解して、OpenWrtのアプリケーション開発をしたい方は以下の記事をご参考ください。
- OpenWrtアプリケーション開発 自作スクリプトと連携するLuCI用プラグインの作成と追加(難易度Lv2)
- OpenWrtアプリケーション開発 自作UBUS対応アプリと連携するLuCI用プラグインの作成と追加(難易度Lv3)(作成中)
参考文献
- GitHub luci wiki https://github.com/openwrt/luci/wiki
- projects / project / luci.git / summary: https://git.openwrt.org/?p=project/luci.git