Set up zero-touch provisioning so machines automatically configure themselves when they first come online.
Install viam-agent during manufacturing, define a default configuration with a fragment, and when the end user connects the machine to a network, viam-agent installs viam-server and your latest software automatically.
viam-agent starts Bluetooth Low Energy (BLE) and accepts connections.
The customer installs an app you provide on a mobile device.
The customer uses the app to connect to the machine over Bluetooth.
Using the app, the customer provides the machine WiFi credentials to the machine to connect to a WiFi network.
The machine connects to the internet and sets itself up based on the specified fragment.
viam-agent starts a WiFi hotspot.
The customer uses a mobile device to connect to the machine’s temporary WiFi network.
Using a captive web portal or a mobile app, the customer provides WiFi credentials to connect to a WiFi network.
The machine connects to the internet and sets itself up based on the specified fragment.
viam-agent starts Bluetooth Low Energy (BLE) and accepts connections.
The customer installs an app you provide on a mobile device.
The customer uses the app to connect to the machine over Bluetooth and shares the mobile device’s internet connection with the machine for setup.
The machine uses the mobile-devices internet to set itself up based on the specified fragment.
Provision a device
The following instructions will preinstall viam-agent into an image.
Only use the following method for offline pre-installs with images. For live systems, follow the instructions on a machine’s setup tab to install viam-server with viam-agent.
1
Create a fragment
If you do not yet have a fragment, follow the steps to Create a fragment and make a note of the fragment ID.
2
Create the defaults file
If you would like to use a captive web portal, skip this and the next step.
Create a defaults file called viam-defaults.json to configure the provisioning experience for the users setting up their machines.
You will later pass this file to a script, so you can save it anywhere.
The script will save the file is at /etc/viam-defaults.json on the machine.
This file configures some basic metadata, specifies a fragment to use to configure the machine, and provides the WiFi hotspot network name and password to use on startup.
It also configures timeouts to control how long viam-agent waits for a valid local WiFi network to come online before creating its hotspot network, and how long to keep the hotspot active before terminating it.
Click to view attribute information
Name
Type
Required?
Description
manufacturer
string
Optional
Purely informative. May be displayed on captive portal or provisioning app. Default: "viam".
model
string
Optional
Purely informative. May be displayed on captive portal or provisioning app. Default: "custom".
fragment_id
string
Optional
The fragment_id of the fragment to configure machines with. Required when using the Viam mobile app for provisioning. The Viam mobile app uses the fragment to configure the machine.
hotspot_interface
string
Optional
The interface to use for hotspot/provisioning/wifi management. Example: "wlan0". Default: first discovered 802.11 device.
hotspot_prefix
string
Optional
viam-agent will prepend this to the hostname of the device and use the resulting string for the provisioning hotspot SSID or the Bluetooth device name(<hotspot_prefix>-<hostname>). Default: "viam-setup".
hotspot_password
string
Optional
Depending on the provisioning method, this is either the Wifi password or bluetooth connection password for the provisioning hotspot. Important: When provisioning devices with the Viam mobile app, the password must currently be "viamsetup". Be aware that if you do not set a custom password this may be a security risk. Default: "viamsetup".
disable_captive_portal_redirect
boolean
Optional
By default, all DNS lookups are redirected to the “sign in” portal, which can cause mobile devices to automatically display the portal. When set to true, only DNS requests for domains ending in .setup, like viam.setup are redirected, preventing the portal from appearing unexpectedly, especially convenient when using a mobile app for provisioning. Default: false.
disable_bt_provisioning
boolean
Optional
When set to true, disables Bluetooth provisioning. The machine will not advertise Bluetooth services for provisioning. Default: false.
disable_wifi_provisioning
boolean
Optional
When set to true, disables WiFi hotspot provisioning. The machine will not create a WiFi hotspot for provisioning. Default: false.
turn_on_hotspot_if_wifi_has_no_internet
boolean
Optional
By default, the device connects to a single prioritized WiFi network (provided during provisioning) and is considered online even if the global internet is not reachable. When turn_on_hotspot_if_wifi_has_no_internet is true and the primary network lacks internet connectivity, the device will try all configured networks and only mark itself as online if it successfully connects to the internet. Default: false.
offline_before_starting_hotspot_minutes
integer
Optional
Will only enter provisioning mode (hotspot) after being disconnected longer than this time. It may be useful to increase this on flaky connections, or when part of a system where the device may start quickly, but the wifi/router may take longer to be available. Default: 2 (2 minutes).
user_idle_minutes
integer
Optional
Amount of time before considering a user (using the captive web portal or provisioning app) idle, and resuming normal behavior. Used to avoid interrupting provisioning mode (for example for network tests/retries) when a user might be busy entering details. Default: 5 (5 minutes).
retry_connection_timeout_minutes
integer
Optional
Provisioning mode will exit after this time, to allow other unmanaged (for example wired) or manually configured connections to be tried. Provisioning mode will restart if the connection/online status doesn’t change. Default: 10 (10 minutes).
wifi_power_save
boolean
Optional
Boolean, which, if set, will explicitly enable or disable power save for all WiFi connections managed by NetworkManager. If not set, the system default applies. Default: NULL.
device_reboot_after_offline_minutes
integer
Optional
If set, viam-agent will reboot the device after it has been offline (and in hotspot mode) for the specified duration. Default: 0 (disabled).
3
Configure Networks
If a machine connects to a network during setup and you know in advance which WiFi a machine will connect to, this step allows you to add credentials for it.
If you do not know the network in advance, skip this step.
In this case the end user will have to provide network details later in the process.
If you know in advance that the machine should be able to connect to multiple networks, we recommend that you add WiFi settings in the operating system (for example, directly in NetworkManager).
If that is not possible, you can add networks with the additional_networks field.
viam-agent will then try to connect to each specified network in order of priority from highest to lowest.
The following configuration defines the connection information and credentials for two WiFi networks named fallbackNetOne and fallbackNetTwo:
Priority to choose the network with. Values between -999 and 999. Default: 0.
4
Create a machine in advance
If you are using a mobile app for provisioning, skip this step.
If you provision devices using a captive web portal, you can create a machine in advance.
You can either provide its machine cloud credentials to the preinstall script you will run in the next steps, or provide them using the captive web portal.
You can get the machine cloud credentials by clicking the copy icon next to Machine cloud credentials in the part status dropdown to the right of your machine’s name on the top of the page.
Paste the machine cloud credentials into a file on your hard drive called viam.json.
You will pass the file to the preinstall script later, so you can store it anywhere.
The script will save the file is at /etc/viam.json on the machine.
Want to create a machine and obtain its machine cloud credentials programmatically?
You can use the Fleet Management API to create machines, and obtain their machine cloud credentials:
import asyncio
import requests
from viam.rpc.dial import DialOptions, Credentials
from viam.app.viam_client import ViamClient
from viam.app.app_client import APIKeyAuthorization
# TODO: Replace "<API-KEY>" (including brackets) with your API key
API_KEY = "<API-KEY>"
# TODO: Replace "<API-KEY-ID>" (including brackets) with your API key ID
API_KEY_ID = "<API-KEY-ID>"
# The id of the location to create the machine in
LOCATION_ID = ""
# The name for the machine to create
MACHINE_NAME = ""
async def connect() -> ViamClient:
dial_options = DialOptions(
credentials=Credentials(
type="api-key",
payload=API_KEY,
),
auth_entity=API_KEY_ID
)
return await ViamClient.create_from_dial_options(dial_options)
async def main():
async with await connect() as viam_client:
cloud = viam_client.app_client
new_machine_id = await cloud.new_machine(
name=MACHINE_NAME, location_id=LOCATION_ID)
print("Machine created: " + new_machine_id)
list_of_parts = await cloud.get_machine_parts(
machine_id=new_machine_id)
print("Part id: " + list_of_parts[0].id)
org_list = await cloud.list_organizations()
print(org_list[0].id)
auth = APIKeyAuthorization(
role="owner",
resource_type="robot",
resource_id=new_machine_id
)
api_key, api_key_id = await cloud.create_key(
org_list[0].id, [auth], "test_provisioning_key")
print(api_key, api_key_id)
headers = {
'key_id': api_key_id,
'key': api_key
}
params = {
"client": 'true',
"id": list_of_parts[0].id
}
res = requests.get(
'https://app.viam.com/api/json1/config',
params=params,
headers=headers,
timeout=10
)
print(res.text)
with open("viam.json", "w") as text_file:
text_file.write(res.text)
if __name__ == '__main__':
asyncio.run(main())
5
Flash an operating system to the SD card of the single-board computer
If you are flashing a Raspberry Pi using the Raspberry Pi Imager, flash a 64-bit image to your SD card and customize at least the hostname when prompted by the Raspberry Pi Imager.
When you customize the hostname or other settings, the Raspberry Pi Imager creates firstrun.sh which is required to set up provisioning.
Provisioning is supported and tested on Ubuntu 22.04, Debian 11 (Bullseye), and 12 (Bookworm) but should work on most distros using NetworkManager v1.30 (or newer) as well.
For Bullseye, the installation of viam-agent changes the network configuration to use NetworkManager.
6
Mount the SD card
Still using the computer used for flashing the SD card, eject and reinsert the card to make sure it’s mounted with the newly written operating system.
7
Download the preinstall script
Run the following commands to download the preinstall script and make the script executable:
Please note this script works only under POSIX (macOS and Linux) at the moment.
8
Run the preinstall script
Run the preinstall script.
It will attempt to auto-detect a mounted root filesystem (or for Raspberry Pi, bootfs) and also automatically determine the architecture.
sudo ./preinstall.sh
Follow the instructions.
If you created a viam-defaults.json file or a viam.json file, specify their locations when prompted.
Optional environment variables for the preinstall script
Argument
Description
VIAM_JSON_PATH
The path to the machine cloud credentials file (viam.json) to be copied to the machine. The script will also prompt you for this file if not provided.
DEFAULTS_PATH
The path to the viam-defaults.json file. The script will also prompt you for this file if not provided.
VIAM_AGENT_PATH
The path to a beta or local build of viam-agent. Used for testing.
Troubleshooting:
Using a Raspberry Pi?
Important: Required customization
You must customize at least the hostname when prompted by the Raspberry Pi Imager.
When you customize the hostname or other settings, the Raspberry Pi Imager creates firstrun.sh which is required to set up provisioning.
If you do not customize anything, firstrun.sh is not present on the device and the preinstall.sh script fails.
For Raspberry Pis, the script will automatically perform the required next steps, it will:
create a tarball
update firstrun.sh.
extract the tarball to the mounted root filesystem
sudo ./preinstall.sh
Found Raspberry Pi bootfs mounted at /Volumes/bootfs
A Raspberry Pi boot partition has been found mounted at /Volumes/bootfs
This script will modify firstrun.sh on that partition to install Viam agent.
Continue pre-install? (y/n): y
Path to custom viam-agent binary (leave empty to download default):
Path to custom viam-defaults.json (leave empty to skip):
Path to custom viam.json (leave empty to skip)
Creating tarball for install.
a opt
a opt/viam
a opt/viam/cache
a opt/viam/bin
a opt/viam/bin/viam-agent
a opt/viam/bin/agent-provisioning
a opt/viam/cache/viam-agent-provisioning-factory-aarch64
a opt/viam/cache/viam-agent-factory-aarch64
a etc
a usr
a usr/local
a usr/local/lib
a usr/local/lib/systemd
a usr/local/lib/systemd/system
a usr/local/lib/systemd/system/viam-agent.service
a usr/local/lib/systemd/system/multi-user.target.wants
a usr/local/lib/systemd/system/multi-user.target.wants/viam-agent.service
Install complete! You can eject/unmount and boot the image now.
Error: no valid image found at mountpoints (or manually provided path)
If you get this error, you can run the script for the target system’s architecture.
It will create a tarball for the system’s architecture which you will then need to manually extract.
If you are building your own app to provide provisioning functionality you have three options for provisioning.
You can support any number of these options.
Provisioning method
Description
Package
Bluetooth with WiFi
Ask the user to connect to the machine over Bluetooth. The user then provides network credentials for an internet-connected WiFi network, through which machine setup can then occur. Recommended, if available.
Ask the user to connect to the machine’s temporary WiFi hotspot. The user then provides network credentials for an internet-connected WiFi network, through which machine setup can then occur. Slower than Bluetooth with WiFi but faster than Bluetooth tethering.
Ask the user to connect to the machine over Bluetooth. The user shares their mobile device’s internet with the machine over Bluetooth. Slowest provisioning method.
If you are not using Flutter or TypeScript and would like to use provisioning, please contact us.
The Viam mobile app
The Viam mobile app allows end users to create a new machine in the app, and viam-agent will then install viam-server and run it with the configuration provided by the fragment_id in the defaults file.
If you choose to use the Viam mobile app, you must provide a fragment for provisioning.
Caution
Currently, if you are using Bluetooth provisioning, you must leave hotspot_password as the default value viamsetup.
Troubleshooting
Can I re-provision a machine that was already provisioned?
You cannot re-run the preinstall.sh script.
Once a device is set up for provisioning, the preinstall script copies your viam-defaults.json to the device as /etc/viam-provisioning.json.
The device reads this file on boot to configure its provisioning behavior.
If you have not yet connected the device to a network and setup has not completed, you can still make changes to /etc/viam-provisioning.json on the device.
Once a machine has completed the provisioning flow, you cannot re-run the final setup steps without first manually removing the machine cloud credentials file (/etc/viam.json).
Device not detecting networks
Some systems can’t scan for WiFi networks while in hotspot mode, meaning they won’t automatically detect networks coming online or into range until the retry_connection_timeout_minutes expires.
The retry_connection_timeout_minutes causes your device to exit hotspot mode, at which point your device will be able to detect newly available networks.
If your device does not connect to your network, adjust the retry_connection_timeout_minutes value in the defaults file.
Device not connecting or showing as offline
Check if other devices on the network can connect to the internet without problems.
If other devices are fine, try restarting your device and check for other logs.
Test GRPC components of the provisioning service
If you need to test the GRPC components of the provisioning service, there is a CLI client available.
Get the code from the agent repo and run go run ./cmd/provisioning-client/ for info.