Custom driver installation on the Remote
Starting with firmware v1.9.0, custom installation drivers can be installed on the Remote.
‼️ Custom integration drivers is a developer preview and not all features are implemented yet. See missing features.
Installation archive format
Integration driver archive requirements:
- TAR GZip archive (either .tgz or .tar.gz file suffix) with a maximum size of 100 MB.
- In the root of the archive, there must be a
driver.jsonmetadata file describing the custom integration driver. - The driver binary must be in the
./binsubdirectory.- Either a statically linked aarch64 executable named
driver. - Or a Node.js file named
driver.js.
- Either a statically linked aarch64 executable named
- All application files must be in one of the following subdirectories, other locations are not accessible at runtime:
./bin: application binary folder../config: optional configuration data. Path is accessible withUC_CONFIG_HOMEenvironment variable../data: optional application data. Path is accessible withUC_DATA_HOMEenvironment variable.
Metadata file
The driver.json metadata file in the root of the archive describes the integration driver.
‼️ The data schema is not yet included in the Core-API, the full object is shown below.
It is a reduced version of the IntegrationDriver object, without driver connection fields like driver_url, token etc.
{
"driver_id": "foobar",
"version": "1.0.0",
"min_core_api": "0.20.0",
"name": {
"en": "Foobar special"
},
"icon": "custom:foobar.png",
"description": {
"en": "Control Foobar products",
"de": "Steuere Foobar Produkte"
},
"features": [
{
"name": "auth.external_tokens",
"required": true
}
],
"developer": {
"name": "Unfolded Circle ApS",
"email": "hello@unfoldedcircle.com",
"url": "https://www.unfoldedcircle.com"
},
"home_page": "https://www.unfoldedcircle.com",
"setup_data_schema": {
"title": {
"en": "Integration setup",
"de": "Integrationssetup"
},
"settings": [
{
"id": "info",
"label": {
"en": "Setup process",
"de": "Setup Fortschritt"
},
"field": {
"label": {
"value": {
"en": "The integration will discover your Foobar products on your network. This process is automatic and can take a few minutes.",
"de": "Diese Integration wird Foobar Produkte im Netzwerk finden. Dies ist ein Automatischer Prozess der ein paar Minuten dauern kann."
}
}
}
}
]
},
"release_date": "2024-07-21"
}
driver_idmust be at least 5 characters long and start with a lower-case letter.- Only lower-case letters, digits and
-,_are allowed. - Common system identifiers are not allowed and will be rejected (e.g.
daemon,backup, etc.). - The
uc_prefix should not be used. This is reserved for pre-installed integrations. Any custom integrations using this prefix might get removed during a future firmware update.
- Only lower-case letters, digits and
- Multiple language fields are not required, but recommended.
- If only a single language is provided, it should use the
enkey.
- If only a single language is provided, it should use the
setup_data_schemais optional if the driver provides a setup flow.- This is the first screen of the setup, all further screens are dynamically provided by the driver.
- ⚠️
min_core_apiis not yet used.
Driver icon
A driver icon can either use a predefined icon or a custom icon. Predefined icons are prefixed with uc:, followed by
the icon identifier in lowercase.
A custom driver icon can be installed automatically as a custom icon resource.
- In
driver.jsonset the icon field tocustom:$ICON_FILENAME - Include
$ICON_FILENAMEin the root of the archive.
Example driver.json (other fields omitted for simplicity):
{
"icon": "custom:foobar.png"
}
The icon file called foobar.png must be added to the root of the archive.
Icon requirements and restrictions:
- Size must be 90x90 pixels.
- Supported image formats: PNG and JPG.
- Maximum size: 16 KB.
Installation archive example
Example of a Node.js based integration driver archive (contents of bin/node_modules are not shown for a clearer overview):
.
├── bin
│ ├── driver.js
│ ├── node_modules
│ │ ├── ...
│ │ ├── foobar
│ │ ├── uc-integration-api
│ │ ├── ws
│ │ └── ...
│ └── foobar.js
├── config
├── data
├── driver.json
└── foobar.png
- If the driver doesn’t require any data or configuration files, the
./dataand./configdirectories can be omitted from the archive.- During the installation, the data and config directories are automatically created and can be accessed by the driver at runtime, no matter if they were provided in the installation archive or not.
- The
driver.jsonfile in the root folder is automatically copied to the./binfolder during installation if it is missing.- If the driver requires a different
driver.jsonfile, simply include a file in the./binfolder.
The one in the root folder won’t be copied anymore.
- If the driver requires a different
Restrictions
- Maximum 10 custom integrations can be installed.
- Only Node.js is supported beside a statically linked binary. Other runtimes are not supported at the moment.
- Python integrations must pack the Python runtime into the archive.
- The integration driver runs in a sandbox. Access to devices and the filesystem is restricted.
- No symlinks are allowed. They are automatically removed during the installation.
- Executable files are only allowed in the
./bindirectory.- No other tools are provided in the runtime environment. E.g., there is no shell available and no other tools
like
cpormv.
- No other tools are provided in the runtime environment. E.g., there is no shell available and no other tools
like
Missing features
- Resource usage: provide memory and CPU usage per integration.
- Only the overall resource usage can be monitored with
GET /api/pub/status.
- Only the overall resource usage can be monitored with
Runtime environment
The driver runs in a sandbox with limited access to the host system.
- Environment variables for the Websocket integration-API server:
UC_INTEGRATION_INTERFACE: network interface to bind to.UC_INTEGRATION_HTTP_PORT: port number.
- The working directory is set to the binary directory.
- The binary directory is read-only.
- Node.js version: v22.22 (firmware release 2.9.2 and newer, v22.13 in firmware 2.8.2, v20.16 in firmware 1.9.3).
- There are no pre-installed node modules.
- An integration driver must include all required modules in the installation archive, including
uc-integration-api(if used).
- File access with relative paths between
bin,config, anddatais not possible.- Environment variables must be used to retrieve the full path of these directories.
UC_CONFIG_HOMEandHOME: configuration directory.UC_DATA_HOME: data directory.
- The returned path may not be stored, it may change with future software updates.
- Environment variables must be used to retrieve the full path of these directories.
- Only the
$UC_CONFIG_HOMEand$UC_DATA_HOMEdirectories are writeable and persisted between restarts.- The
/tmpdirectory can be used for small temporary files.- This is a RAM file system and limited by the available free memory.
- Temporary files are not persisted between restarts.
- The
- A dynamic user and group is allocated when the driver is started.
- The user and group IDs may change between driver restarts.
- Write access to the
$UC_CONFIG_HOME,$UC_DATA_HOMEand/tmpdirectories is ensured.
Resource restrictions
A single custom integration should not use more than 100 MB of memory and conserve CPU usage.
- All custom integrations (max 10) share a common memory pool of 1 GB and are limited to 200% CPU usage (2 cores).
- If the memory pool is exceeded, custom integrations will be terminated. Integrations using the most memory will be terminated first.
- A single custom integration will be throttled if it uses more than 250 MB and terminated if it uses more than 350 MB.
Network
The integration runs on the same network environment as the Remote. There is no network bridge or firewall.
- Binding ports below 1024 is not possible.
⚠️ A port-binding filter might be added in the future to prevent integrations to steal away ports of other integrations. The port range 8000-9200 and port 13333 are not allowed to be used!
Native integration drivers
TODO sysroot, available dynamic libraries
The Remote Two Cross Compile Toolchain can be used to cross-compile a native binary for the Remote.
- The driver must be compiled as a static binary for libc.
- Most dynamic libraries in the cross-compile sysroot are NOT available in the custom integration runtime environment!
Driver installation
The easiest way to manage custom integration drivers is to use the web-configurator.
Upload a new driver
In the web-configurator open the integration view and chose Add new, Install custom.
REST API
curl --location 'http://$IP/api/intg/install' \
--user 'web-configurator:$PIN' \
--form 'file=@"custom-intg.tar.gz"'
See REST Core API for more details.
Update driver
ℹ️ The driver update feature requires firmware release v2.9.3 or newer.
In the web-configurator open the integration view and chose Add new, Install custom and check the
Update existing driver option.
REST API
curl --location 'http://$IP/api/intg/install?update=true' \
--user 'web-configurator:$PIN' \
--form 'file=@"custom-intg.tar.gz"'
Delete driver
The integration instance and driver can be deleted in the web-configurator within the main integration view. If there’s an active instance of the custom integration driver, the instance needs to be deleted first, then the driver.
REST API
To delete a custom integration, use the regular endpoints to delete an integration instance and driver. These are the same endpoints as for an external network integration driver:
- Delete integration instance
DELETE /api/intg/instances/:intgId. - Delete driver and installation files:
DELETE /api/intg/drivers/:driverId.
Log access
Output to stdout and stderr are automatically stored with a timestamp and accessible as the other system logs:
- Get log services:
GET /api/system/logs/services. - Query logs:
GET /api/system/logs?....
See REST Core API for more details.
Log files can also be downloaded in the web-configurator: Settings, Development: Logs
Web-app log viewer
ℹ️️ Available from firmware release v2.1.0
The Logdy web application is installed on the device to monitor integration driver log events in near real time.
- URL:
http://$IP/log/ - This function is deactivated by default and the endpoint returns 503.
- The log viewer must be started using the REST Core API
with the
/api/system/logs/webendpoint:GETrequest returns the current state.PUTrequest allows to start, stop or to permanently enable the log app. A password can be set to restrict access to the web app.
- Available logs:
- Remote core service
- All pre-installed and custom integrations
- Custom remote-ui service if installed
- ❗️The log processing and logdy daemon require around 170 MB of the custom integration memory pool.
Using curl to start the app:
curl --request PUT 'http://$IP/api/system/logs/web' \
--header 'Content-Type: application/json' \
--user web-configurator:$PIN \
--data '{"enabled": true}'
Start and permanently enable the app, even after a reboot:
curl --request PUT 'http://$IP/api/system/logs/web' \
--header 'Content-Type: application/json' \
--user web-configurator:$PIN \
--data '{"enabled": true; "autostart": true}'
Recommendations
- Node.js should be preferred for writing integration drivers.
- If using Python:
- Use PyInstaller to create a binary distribution.
- Use the default one-folder bundle containing an executable (
--onedir). Avoid the one-file bundled executable, since it will easily use an additional 100 MB of memory! - See Android TV integration or Apple TV integration as an example.
- An integration driver should be limited to one process and not launch other processes.
- Use ports above 10000 if the integration needs to create an IPv4 or IPv6 server socket (besides the required WebSocket server for the integration-API).
- Preserve resources, use as little memory and CPU as possible.
- Use stdout & stderr for logging.
- Only use
/tmpfor small, temporary files since it is a RAM file system.
Example integrations
The following integration drivers create a custom integration installation archive during build with a GitHub action:
- Node.js based:
- Python based: