| name | webui-plugin |
| description | Create a Thingino WebUI plugin that adds pages, navigation items, and scripts to the camera web interface when an optional package is installed. |
| license | MIT |
webui-plugin
Use this skill when you need to add web UI pages, navigation items, scripts, or CGI endpoints that only appear when a specific optional package is installed.
When to use
- You are creating or modifying a Buildroot package that needs web UI configuration pages (e.g. motors, doorbell, daynightd, go2rtc, nino).
- You want the web UI to show a new Settings/Tools/Services menu item only when the package is enabled in the build config.
- You need to inject scripts or HTML into the preview page, or load a global script on every page.
- You are migrating an existing package's web UI integration away from hardcoded core webui logic.
How it works
The plugin system is build-time only — no runtime scanning overhead. Each plugin ships a JSON manifest (<name>.webui.json) and its own web files (HTML, JS, CGI) inside its package directory. A Python assembly script (assemble_plugins.py) runs as a Buildroot TARGET_FINALIZE_HOOKS after all packages are installed. It:
- Scans
$(TARGET_DIR)/var/www/a/plugins/*.webui.json
- Validates for duplicate names / page conflicts
- Generates
/var/www/a/plugins.js with merged nav config and feature flags
- Injects plugin scripts/styles into HTML pages
- Injects preview HTML/scripts into
preview.html / preview-raptor.html
At runtime, navigation.js reads window.thinginoUIConfig.plugins and splices the declared items into the navigation menu with positional control.
Plugin manifest format
Create a file package/<name>/files/<name>.webui.json:
{
"name": "myplugin",
"label": "My Plugin",
"apiVersion": 1,
"nav": [
{
"section": "ddSettings",
"position": "after:GPIO pins",
"items": [
{ "label": "My Config", "href": "/config-myplugin.html" }
]
Package wiring checklist
-
Place web files in your package directory:
package/<name>/files/
├── <name>.webui.json ← manifest
└── www/
├── config-<name>.html ← HTML page(s)
├── a/
│ ├── config-<name>.js ← page-specific JS
│ └── preview-<name>.js ← preview script (if needed)
└── x/
├── json-<name>.cgi ← CGI endpoint(s)
└── ...
-
Add dependency and conditionally define web install commands.
The INSTALL_WWW_CMDS variable is only defined when the webui is
built, then referenced inside the main install define. This avoids
ifeq inside a define block (which would be passed to the shell).
ifeq ($(BR2_PACKAGE_THINGINO_WEBUI),y)
MYPLUGIN_DEPENDENCIES += thingino-webui
define MYPLUGIN_INSTALL_WWW_CMDS
$(INSTALL) -d $(TARGET_DIR)/var/www/a
$(INSTALL) -d $(TARGET_DIR)/var/www/x
$(INSTALL) -d $(TARGET_DIR)/var/www/a/plugins
$(INSTALL) -D -m 0644 $(@D)/files/www/config-myplugin.html \
$(TARGET_DIR)/var/www/config-myplugin.html
$(INSTALL) -D -m 0644 $(@D)/files/www/a/config-myplugin.js \
$(TARGET_DIR)/var/www/a/config-myplugin.js
$(INSTALL) -D -m 0755 $(@D)/files/www/x/json-myplugin.cgi \
$(TARGET_DIR)/var/www/x/json-myplugin.cgi
$(INSTALL) -D -m 0644 $(@D)/files/myplugin.webui.json \
$(TARGET_DIR)/var/www/a/plugins/myplugin.webui.json
endef
endif
-
Reference it inside your main install define:
define MYPLUGIN_INSTALL_TARGET_CMDS
$(MYPLUGIN_INSTALL_WWW_CMDS)
endef
Important: Always add $(INSTALL) -d for /var/www/a, ,
and before installing files there. Per-package
Buildroot builds use isolated target directories that don't inherit
from .
If you are migrating an existing package
Checklist for pulling an existing web UI integration out of core webui:
- Create the manifest (
<name>.webui.json) following the schema above.
- Move web files from
package/thingino-webui/files/www/ to your
package's files/www/.
- Remove from
navigation.js — delete any hardcoded nav items in
buildDefaultMenu() that belong to this plugin.
- Remove from
thingino-webui.mk — delete the $(INSTALL) lines
for the moved files. If they were gated by a BR2_PACKAGE_* check,
remove the entire conditional block.
- Remove runtime probing from
S48webui-config — if the package had
a runtime feature-flag probe (e.g. checking for a CGI file or
thingino.json key), delete it. Feature flags now come from the
manifest.
- Add
DEPENDENCIES += thingino-webui to your package's .mk.
Reference: existing plugins
| Plugin | Package | Manifest location |
|---|
| motors | thingino-motors | package/thingino-motors/files/motors.webui.json |
| doorbell | wyze-accessory | package/wyze-accessory/files/doorbell.webui.json |
| daynightd | thingino-daynightd | package/thingino-daynightd/files/daynightd.webui.json |
Validation
After completing the wiring:
scripts/check-plugins.sh
CAMERA=<camera> make
Check the generated output on the camera:
/var/www/a/plugins.js should contain your plugin's nav and feature flags.
- Your pages should appear in the navigation menu at the declared position.
- Feature flags should be accessible as
uiConfig.device.<key> in JS.