Asset OTA (available in Device OS 5.5.0 and later), makes it easy to include bundled assets that can be delivered to other processors and components in your system, such as:
- Graphics and fonts for external displays
- Sound samples for device with audio output capabilities
Including assets is as easy as including an directory in your project, specifying it in the
project.properties and building and flashing using Particle Workbench, the Particle CLI, or fleet-wide OTA for a product. Bundled assets can be up to 1 MB to 1.5 MB in size, after compression, depending on the platform, and do not use additional data operations.
The compression algorithm is similar to gzip, so using a gzip program on the assets folder on your computer will yield the approximate size after compression.
- Particle Workbench and the Particle CLI will automatically generated bundled assets when the
project.propertiesfile contains an
assetOtaDirkey and a value containing a valid directory.
- When using Particle: Compile Application or
particle compileprojects with bundled assets are built into a .zip file. This file contains both the firmware binary (.bin) as well as the assets.
- The asset bundle .zip can be uploaded to the console as product firmware binary.
- When using Particle: Flash application or
particle flashthe same process is followed, except the device is flashed.
- When flashing OTA, the asset bundle is transmitted using resumable OTA and compression for efficient data use.
- You will need to include code in your application firmware to process the additional assets, such as sending them to a coprocessor or saving them to the file system.
- Creating bundled assets will not be not possible in the Web IDE. Particle Workbench is recommended.
The application can register a callback using
System.onAssetOta() that will be called by Device OS when the device has received all the bundled assets. For more information, see the Asset OTA Device OS API.
|Total asset storage
|Maximum single asset size
|tracker, b5som, esomx
|boron, bsom, argon
|p2 (and Photon 2)
There isn't a strict limit on the number of assets in your bundle, however each asset file is stored as a separate file in a flash file system, and each file takes a minimum of 4K bytes, even if the file is smaller than that. Thus if you have a large number of very small assets, you may want to consider concatenating them into a single larger asset.
Note that the asset storage file system is separate from the user file system and does not count against the 2 MB (4 MB on Tracker) available for your use.
The rest of this document shows how to add OTA assets to your project. This example just saves the files to the flash file system so you can run it without any additional hardware beyond a compatible Particle cellular or Wi-Fi device. Additional examples of using Asset OTA can be found on the GitHub repository asset-ota-examples.
Instead of saving the assets to the flash file system, you could:
- Directly flash an external coprocessor, such as by UART serial.
- Directly write to an external display connected by SPI.
If you call
System.assetsHandled(false) the assets will be presented on every boot, which is often more space-efficient than storing a separate copy in the file system. You still may want to store it in a file if you need random access to the asset, or need it later, after boot. For example, if you have multiple sound file assets and you want to be able to choose one to play, the file system would be a good choice.
This example stores assets in the user portion of flash file system, but this done for illustration only because it does not require external hardware and the example is easy to follow. Because assets are stored by the system even after you mark them as handled, you can always start reading the assets again using
System.assetsAvailable() and reading the assets again. This is often more efficient.
There are two ways to handle assets. A common way is to use
This example uses a call from
System.assetsAvailable() instead, otherwise the debug log messages may occur so early at boot that you don't see them.
handleAssets() the code iterates through all of the assets. This is typical.
for (auto &asset : assets)
// Put code here to handle asset
For each asset, the example creates a file on the flash file system with the same name. It then reads the data out of the asset and writes it to the file.
You must specify the
assetOtaDir in your project.properties file for assets to be generated.
You specify the name of the directory containing assets using
assetOtaDir so it doesn't need to be called
assets but that is what is used in the example.
There are two files in the example:
- assets/logo.png: A small Particle logo png image file
- assets/test1.json: A small JSON file to demonstrate using Asset OTA for distributing JSON configuration files
One common option for creating a binary is to use the Particle CLI. The main difference is that you must specify a .zip file instead of a .bin file if you specify the filename using
% cd FileAssetExample
% particle compile p2 . --saveTo firmware.zip --target 5.5.0
Compiling code for p2
Targeting version: 5.5.0
attempting to compile firmware
downloading binary from: /v1/binaries/64e377e11067c0b8a0d11471
text data bss dec hex filename
17518 124 3254 20896 51a0 /workspace/target/workspace.elf
Compile succeeded and bundle created.
Saved bundle to: /Users/rick/Downloads/FileAssetExample/firmware.zip
You can see the files that are added to the bundle listed in the
If you extract this zip file, you'll find that it contains
firmware.bin, the compiled binary, and the
assets directory containing your assets.
You can then flash the zip file to the device using the Particle CLI or upload it to a product.
% particle flash test-photon2 firmware.zip
When you flash a device with assets, the process is as follows:
- The .zip file is uploaded to the cloud.
- The cloud extracts the zip file, verifies the contents, and makes sure the bundle will fit on the target device.
- The firmware .bin is flashed to the device OTA.
- Normal checks are done to make sure system dependencies are met. If the device needs a Device OS upgrade, it goes into safe mode (breathing magenta) and these updates are flashed and the device rebooted.
- If the firmware has assets, the local asset storage on the device is checked to see if the file and hash match an existing assets. If not, the device will go into safe mode and the assets(s) downloaded. Only new or changed assets are downloaded.
- The device will now run the user firmware.
onAssetOtahandler function will be called (if used), and all assets will be available to the user firmware via the
If you want to flash by USB, you can use:
% particle flash --local firmware.zip
You can also use the local and cloud compile options in Particle Workbench to create an asset binary, directly flash the device OTA, or flash the device over USB.
At boot, you'll see output similar to this. This shows the data being copied to the flash file system.
0000003378 [app] INFO: handleAssets called
0000003383 [app] INFO: asset path=/usr/assets/logo.png size=2466
0000003434 [app] INFO: wrote 512 bytes to file
0000003442 [app] INFO: wrote 512 bytes to file
0000003454 [app] INFO: wrote 512 bytes to file
0000003463 [app] INFO: wrote 512 bytes to file
0000003470 [app] INFO: wrote 418 bytes to file
0000003518 [app] INFO: asset path=/usr/assets/test1.json size=44
0000003566 [app] INFO: wrote 44 bytes to file
0000003783 [app] INFO: set assetsHandled to true
Every 10 seconds, the example prints out the asset files. The logo.png file is printed in hex, and the data should be as it is below.
The top level keys of the test1.json file are printed out. You can edit the file, compile, and flash it and see the values change.
0000010001 [app] INFO: found asset /usr/assets/logo.png size=2466
0000010126 [app] INFO: found asset /usr/assets/test1.json size=44
0000010132 [app] INFO: key=a value=JSON example
0000010135 [app] INFO: key=b value=12345
In the Particle console, if you view a device, you can see the assets that were flashed just below the functions and variables:
This example will leave the files on the flash file system, which will be preserved even when you flash new firmware. To clean up these
files, change the
checkAssets() function to this and flash the firmware to your device to clean up the files in the
// This is just for demonstration purposes for reading assets
DIR *dirp = opendir(assetsDir);
struct dirent *de = readdir(dirp);
if (de->d_type != DT_REG)
// Not a file
String path = String::format("%s/%s", assetsDir, de->d_name);
Yes, you should include your assets in every firmware build.
No. Even though your asset bundle is uploaded to the cloud as a .zip file, it's unzipped and verified in the cloud. Each asset it mapped by its name and hash. If the contents of an asset binary do not change, the assets will not be downloaded to the device again, even if bundled with a different version of the firmware.
My external MCU doesn't have flash memory and I need to program it on every boot. Is this supported?
Yes. Instead of using the
System.onAssetOta() hook, you may prefer to use
System.assetsAvailable(). The assets are stored on device even if you call
System.assetsHandled() so you can always use them again.
System.assetsAvailable() is available at runtime. You can call this any time you want to access your assets.
For example, if you want to store a specific bitmap to a display, or play a sound asset, you can call
System.assetsAvailable(), iterate the results until you find the one you want, then stream the contents.
You can flash a new version of firmware that contains the same assets (same name, same hash) and the assets will be available again without having to download them to the device again.
No. Assets download is determined on a per-file basis based on name and hash, so if those do not change the file will not be downloaded to the device again.
No, the bundle creation is done entirely within the Particle CLI, not in the cloud. Particle Workbench uses the CLI as well.
This is not recommended. When a bundle is created, information about each asset file is inserted into the firmware .bin file, including its name and hash.
If the hash in the .bin file does not match the hash of the asset file, it will be rejected, both by the CLI if you attempt to flash it from the CLI, but also via the cloud API.
If you want to create a bundle from an existing .bin file, use the
particle bundle CLI command.