Skip to content

Install the OTA-Pulse Agent

The OTA-Pulse agent (soc-ota-agent) is the device-side component that polls the backend for pending deployments, downloads firmware artifacts, writes them to the inactive A/B partition, and reboots into the new image. It runs as a systemd service and is written in Go.

Three installation paths are supported:

MethodWhen to use
Yocto layer (meta-otapulse)Greenfield or existing Yocto builds — the recommended production path
Buildroot external tree (buildroot-otapulse)Buildroot-based boards
Manual binary installQuick device tests, development VMs, or any Linux device

The meta-otapulse layer bakes the agent, its config directory, systemd unit, and identity/inventory scripts directly into your image.

Supported releases: Kirkstone (LTS) · Langdale · Mickledore · Nanbield · Scarthgap

  1. Clone and add the layer

    Terminal window
    cd /path/to/yocto/sources
    git clone https://github.com/binaryblack/OTA-Pulse.git ota-pulse
    # Add to your build
    bitbake-layers add-layer /path/to/ota-pulse/meta-otapulse

    Or add the path directly to conf/bblayers.conf:

    BBLAYERS += "${BSPDIR}/sources/ota-pulse/meta-otapulse"
  2. Inherit the integration class in your image recipe

    For standard images (rootfs < 1 GB):

    # In your image recipe (e.g., my-image.bb)
    inherit otapulse

    For large images (Qt, multimedia — rootfs > 1 GB):

    inherit otapulse-large

    What inherit otapulse does automatically:

    • Adds soc-ota-agent to the image
    • Enables .otapulse artifact generation
    • Adds ext4 to IMAGE_FSTYPES
    • Includes partition tools (gptfdisk)
  3. Set the OTA server URL and a provisioning token in conf/local.conf

    # Required: your OTA-Pulse backend URL. It must be https://.
    # By default the build fails on plain http://. OTAPULSE_ALLOW_INSECURE_URL = "1"
    # overrides that for isolated dev setups only.
    OTA_SERVER_URL = "https://<your-server>"
    # Recommended: a fleet provisioning token (spt_...) from Provisioning in the console.
    # Here it satisfies the build-time credential check.
    OTAPULSE_PROVISIONING_TOKEN = "spt_..."
    # Optional: enable artifact signature verification for production
    SOC_OTA_SIGNATURE_VERIFICATION = "1"
    SOC_OTA_VERIFY_KEY_FILES = "production-rsa-public.pem production-ecdsa-public.pem"

    The device registers itself on first boot with the same token. Place it on the device in /etc/otapulse/provision.env (mode 0600):

    Terminal window
    OTAPULSE_PROVISIONING_TOKEN=spt_...

    No recipe writes provision.env for you, so your image or provisioning process must place it. See Register your first device for what happens next.

  4. Build the image

    Terminal window
    bitbake your-image
    # Output: tmp/deploy/images/<MACHINE>/your-image-<MACHINE>.otapulse
  5. Flash and verify

    Terminal window
    # Flash the WIC image
    sudo dd if=your-image-<MACHINE>.wic of=/dev/sdX bs=4M status=progress
    # After first boot, verify on the device
    systemctl status soc-ota-agent
    soc-ota-agent show-artifact

The layer ships with placeholder development keys. For production you must supply your own keys.

Option A — Replace the example keys:

Terminal window
cp your-production-rsa-public.pem \
meta-otapulse/recipes-core/signing-keys/files/example-rsa-public.pem

Option B — Point to your keys in local.conf:

SOC_OTA_VERIFICATION_KEYS = "/absolute/path/to/production-rsa-public.pem"

Supported algorithms: RSA-4096 PSS/SHA-256 and ECDSA-P384 SHA-384.


After installation, the agent uses the following paths regardless of install method:

PathDescription
/usr/bin/soc-ota-agentAgent binary
/etc/otapulse/otapulse.confMain configuration (JSON). On image-based devices this file belongs to the root filesystem.
/var/lib/otapulse/otapulse.confSecond configuration file, read first. See Configuration files. On Yocto images the agent service sets OTAPULSE_DATASTORE_DIR=/data/otapulse, so the file is /data/otapulse/otapulse.conf on the data partition.
/etc/otapulse/scripts/State scripts (update lifecycle hooks)
/var/lib/otapulse/Runtime state and deployment log
/usr/share/otapulse/identity/Device identity scripts
/usr/share/otapulse/inventory/Inventory collection scripts

The agent reads two configuration files. It loads the persistent file first and /etc/otapulse/otapulse.conf second. When both set the same field, the /etc file wins.

On a device built from a Yocto or Buildroot image, /etc/otapulse/otapulse.conf is part of the root filesystem. Each image carries its own copy, with the ServerURL that was set when the image was built. An A/B update boots the other slot, so after the switch the agent reads the new image’s copy. An edit you make to /etc/otapulse/otapulse.conf on a running device is lost at the next slot switch. A ServerURL in the persistent file cannot override the /etc value either, because the image’s /etc file sets it. To change the server for good, build the image and the update artifacts with the new server URL (OTA_SERVER_URL in Yocto).

On Yocto images, first-boot provisioning writes the device credentials (SoCAPIKey and SoCDeviceID) to the persistent file. It lives on the data partition, which survives updates. A SoCAPIKey in the /etc file would take precedence over it.

SymptomCheck
Service won’t startsudo journalctl -u soc-ota-agent --no-pager — look for config parse errors
Cannot reach backendcurl https://<your-server>/health from the device
Authentication failuresCheck UseSoCMonitoring, SoCDeviceID and the ServerURL in the config files (see Agent registers but never appears); check system clock (NTP)
State stuckcat /var/lib/otapulse/deployment.log

With the agent installed and running, register it in the console.

Register your first device →