π‘ This page provides context and development guidance for Extensions. For installing and using Extensions please refer to the Extensions Manager section of the Advanced Usage page.
One of the primary aims of BlueOS is to be a platform that is readily extendable to the needs of each user. For maximum utility it should be easy to add support for custom hardware, add components to the user interface, and share developments with other BlueOS users, without compromising the base BlueOS experience.
Accordingly, BlueOS has been designed with a containerised architecture, so the core functionality is kept separate from Extensions, and each can be distributed and updated independently of the other. The built in Extension system allows developers and users to find and install add-on software packages to BlueOS, and manage updates, permissions, and resource limits of those Extensions through the Extensions Manager.
β οΈ The BlueOS Extensions system is currently still in a
beta
stage of development, so some implementation changes are expected in the near future.
The BlueOS Extensions system consists of three major components:
π‘ In future there will also be support for file-based Plugins, which will extend the functionality of a running Docker Container (e.g. themes or 3D models for BlueOS-core, or extra components and/or documentation for a particular Extension). These will also be shareable and installable through the Bazaar.
At heart, a BlueOS Extension is some functionality (optionally with a web interface) packaged into a Docker Image, and combined with some metadata that allows it to be found, shared, and managed. Extensions may interface with existing services provided by BlueOS (or other Extensions), and some Extensions may create persistent logs and/or make use of data or files provided by the user.
Once installed, an Extension Package can be run as a Docker Container, which normally occurs automatically when the vehicle turns on, but can also be manually disabled/enabled via the Extensions Manager. When running, Extensions can have custom permissions assigned, which can limit resource-usage and/or allow access to parts of the host computer's hardware.
To integrate well within BlueOS, extensions typically include a backend service that runs on the onboard computer (in the vehicle), which provides some functionality, and is often accessed by a frontend interface that runs in the control station computer's browser.
A common usage process would follow:
You can use programs like simple-http-server to serve static files for an Extension.
Every Extension has a backend, whereby:
Frontend interfaces are optional, but well-supported:
The process of packaging a set of programs and files into a Docker Image requires a Dockerfile, which can be thought of as recipe for building the Image.
For an Extension to be properly managed and shareable, the Dockerfile it's created from should include relevant metadata2 via the following labels:
LABEL permissions='{}'
docker inspect <container_name>
permissions
label include:
"HostConfig": {\
"Binds":[\
"/usr/blueos/extensions/data-logger:/app",\
]\
}
/dev/tty*
)"HostConfig": {\
"Privileged": true,\
"Binds":[\
"/usr/blueos/extensions/data-logger:/app",\
"/dev:/dev"\
]\
}
host.docker.internal
(i.e. instead of localhost
/127.0.0.1
) to access BlueOS APIs from inside the Extension, because the Extension is not sharing the BlueOS-core networkLABEL permissions='\
{\
"ExposedPorts": {\
"80/tcp": {}\
},\
"HostConfig": {\
"ExtraHosts": ["host.docker.internal:host-gateway"],\
"PortBindings": {\
"80/tcp": [\
{\
"HostPort": ""\
}\
]\
}\
}\
}'
{
"HostConfig":{
"CpuPeriod":100000,
"CpuQuota":20000,
"Memory":209715200,
}
}
LABEL version="1.0.0"
1.0.1-beta.16
)LABEL authors
LABEL authors='[\
{\
"name": "Me",\
"email": "me@email.com"\
},\
{\
"name": "Me Too",\
"email": "me2@email.com"\
}\
]'
LABEL company
(becoming maintainer
)
{
"about": "brief description",
"name": "Company/Person Name",
"email": "email@company.com"
}
LABEL readme
{tag}
to find versioned readme files without manually updating the URLs"https://https://raw.githubusercontent.com/BlueOS-Community/BlueOS-examples/{tag}/example4-vue-backend/Readme.md"
LABEL links
{
"website": "https://...",
"github": "https://github.com/...",
"support": "mailto:support@company.com",
"documentation": "https://docs.company.com/cool-extension/",
"phone": "tel:+1234567890"
}
LABEL requirements
repo/extension-name >= version
LABEL type
"device-integration"
"other"
"tool"
"example"
(for Extension examples)LABEL tags
"positioning"
"navigation"
"mapping"
"data-collection"
(e.g. scientific sensor integrations)"communication"
(e.g. integration of an acoustic modem)"interaction"
(e.g. integration of a gripper / robot arm / brush)The metadata from the Docker labels is used to populate the Repository Manifest, which is used to include Extensions in the Extensions Manager.
If the Extension needs a visual interface3, the recommended approach is to provide a webpage that's accessible via the existing BlueOS web interface.
To do so requires the Extension to run a HTTP server1, at which it must serve a register_service
endpoint in the format of a JSON dict with the following keys:
"name"
My Software 9000!
-> http://blueos.local/extension/mysoftware9000
"description"
"icon"
"mdi-icon-name"
(e.g. "mdi-lightbulb"
)(New in 1.2)
"<svg role=\"img\" viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\">...</svg>"
"company"
"version"
"webpage"
"api"
"extra_query"
(optional)
"avoid_iframes"
(optional)
true
/false
) specifying whether to avoid embedding the extension interface in an iframe."new_page"
(optional)
true
/false
) specifying whether to open the extension in a new page instead of in a BlueOS frame"works_in_relative_paths"
(optional)
true
/false
) specifying whether the extension can be served at an arbitrary base URL
(i.e. it does not access its resources using absolute paths)/extensionv2/<sanitized_name>/
name
field in lowercase, with all non alphanumeric characters removed"extras"
(optional)
As an example:
{
"name": "BlinkLED",
"description": "An intuitive application that blinks a LED.",
"icon": "mdi-led-on",
"company": "Lights End Darkness",
"version": "1.0.1",
"new_page": false,
"webpage": "https://github.com/octocat/blink-led-BlueOS-extension",
"api": "https://github.com/octocat/blink-led-BlueOS-extension/wiki/api"
}
Each Extension service with a register_service
endpoint will have an entry in the BlueOS web interface sidebar menu:
You can choose to not provide a web interface if your extension operates with no user input. The VirtualHere Extension is a relevant example.
Different types of Extensions have different functionality, and there are often a variety of tools available to provide that. When starting to develop extensions, we would generally recommend:
metadata.json
file and an icon
gh-pages
branchOnce installed on the Onboard Computer, Extensions are stored at /var/lib/docker
in the file-system, but should be managed through the BlueOS Extensions Manager.
If you're starting your Extension from scratch, there are a variety of development tools available within BlueOS and in existing Extensions which can enable implementing and testing your key functionality before you start to package it up for easy installation and sharing. Having the backend functionality tested before trying to package it into an Extension can help to minimise unexpected issues and troubleshooting.
Basic functionality can be tested from within the core BlueOS Docker container using the provided Terminal, and if you store files that you create in the /usr/blueos/userdata/
directory they will be persistent across BlueOS restarts, and accessible through the File Browser. For a more interactive development experience, you may wish to use an Extension like Jupyter or VS Code.
Extensions are Docker images, so the packaging process involves
Depending on your starting points and preferred development process/environment, the building and uploading parts can either be performed automatically as part of a CI/CD pipeline, or locally on your development machine. We recommend trying out a QuickStart GitHub repository to familiarise yourself with the process, then deciding how you would like to perform your own development from there.
QuickStart repositories serve as a way to get an example Extension up and running as quickly as possible, while also forming a solid basis for continued development of your own Extension functionalities from that point.
Use this template
" from the top right of a QuickStart GitHub repository
blueos-extension-image-name
(e.g. blueos-quickstart
)DOCKER_USERNAME
: your Docker Hub usernameDOCKER_PASSWORD
: a Docker Hub access token (Read & Write), to allow your GitHub repository actions to upload Docker images to your Docker Hub accountIMAGE_NAME
: the name you chose for your Docker repositoryMY_EMAIL
: the developer's email addressMY_NAME
: the developer's nameORG_EMAIL
: a support email for the maintaining organisationORG_NAME
: the name of the maintaining organisationThe QuickStart repositories make use of our BlueOS Extension Deployment Action, which is available for use in any GitHub workflow, in case you would prefer to use a custom one.
While we generally recommend automated builds for convenience and consistency, it is also possible to develop, build, and upload Docker images directly from your development computer.
We recommend using buildx for cross-platform building, and qemu for emulating arm/v7
on x86
-based developer hardware. Our deployment action provides our best-practice steps for Extension packaging, so is a useful starting point.
There is also a basic extension template for Extensions that are intended to be built manually.
β οΈ Each supported hardware architecture requires its own Docker Image to be built, which our deployment action helps with.
Multi-hardware support allows your Extension to be run/tested on different hardware, but can make development and maintenance more challenging. In particular, different hardwares have different build requirements, which may have different library compatibilities.
For reference:
arm/v7
architecturearm64/v8
architecture, but can typically also run arm/v7
images and softwareTesting each Extension release before making it available to install from the online store is strongly recommended.
Extension Identifier
: dockerusername.base-extension-name
esalexander.quickstart
Extension Name
: A human-readable name for the Extension
QuickStart Test
Docker image
: dockerusername/extension-name
esalexander/blueos-quickstart
Docker tag
: the branch or tag/version the image was generated from
main
Custom settings
: the contents of your Dockerfile's permissions
LABEL, but with relevant variable substitutions (e.g. $IMAGE_NAME
β blueos-quickstart
) and without the backslash line continuation characters
It is possible to enter running Docker containers via the Terminal, by
red-pill
to drop down to the base operating system (from the BlueOS-core container)docker container ls
to list the currently running Docker containersdocker exec -it container-name /bin/bash
to enter the container for modification
/bin/sh
instead, or whatever shell the base image supportsdocker logs -f container-name
insteadregister_service
endpoint, to make it easy to tell
the interfaces apart in the BlueOS sidebarexit
commandπ‘ It is also possible to remotely attach to a container, using a computer running VS Code. This is generally a friendlier interface to work with, but is more involved to set up, and may require installing dependencies inside the container before the connection is successful.
π‘ If you want to make changes to files that are mounted to the computer's filesystem (via
binds
in thepermissions
metadata LABEL) then that is simpler to do via the File Browser; restarting the Extension afterwards if necessary. In that case the changes will be persistent once the modified file has been saved.
For normal files in a docker container, to make changes persistent across future restarts it is necessary to commit
a new Docker image from
the container, and potentially overwrite the old one with it if you want it to operate in place of the original Extension.
docker commit container-name maintainer/image-name:unique-tag
maintainer/image-name
, to avoid being overwritten by downloadsscp
or by copying them
to a mounted location after which they can be accessed through the BlueOS File Browser.π‘ While this can be useful for testing minor changes during development (e.g. fixing a small bug, changing an IP address, or adjusting some logging outputs), it is not recommended to upload commit-modified images as new Extension versions, because there's then no record in the source code repository of the change(s).
The Bazaar is available through the BlueOS Extensions Manager. Once an Extension has been accepted into the Bazaar it should appear automatically, within a few minutes.
Most programming projects are never fully "complete", so it is expected that Extensions will be modified and improved over time. Extension approval only needs to occur when the Extension is first added to the store, so updated releases should become available within 24 hours from when the new version is uploaded to Docker Hub.
The expected iteration process is: