Skip to content

Provisioning

Provisioning prepares a fresh ESP32 to join your fleet: it generates a device key, builds (or downloads) firmware, writes the encrypted configuration, flashes everything, and registers the device in the keystore. It is done from the Provision view in C3PO and implemented by the c3po/provision/ package (config.py, builder.py, nvs.py, flasher.py).

Copland is gone

Earlier versions used a standalone copland.py script. Provisioning is now fully integrated into the C3PO UI. There is no external script to run.

The Provision view

Fill in the form and click Provision:

Field Notes
Port Serial port (e.g. /dev/ttyACM0); use Scan to refresh
Chip esp32c6, esp32s3, esp32s3-v0.2, esp32, esp32c3, esp32s2, esp32s3-cam-n16r8, esp32-cam-aithinker
Device ID Unique id; auto-generated if left empty
Network WiFi (SSID + password) or GPRS (APN, SIM PIN, board profile)
C2 Server IP and port the device will connect to (default :2626)
Firmware Path to a local Espilon-Firmware checkout to build, or empty to use a release
Keystore Path to keys.json (default keys.json)
Erase flash Recommended for first-time provisioning

What provisioning does

flowchart TD
    A["Generate 32-byte master_key"] --> B["Build firmware (idf.py)<br/>or fetch release"]
    B --> C["Generate fctry NVS binary<br/>master_key + device_id + board pins"]
    C --> D["Generate config NVS binary<br/>ChaCha20-Poly1305 encrypted<br/>WiFi + server, key = HKDF(master_key)"]
    D --> E["esptool: flash all partitions"]
    E --> F["Save device entry to keys.json"]
  1. Generate the key. A random 32-byte master_key is created. This is the root of the device's key hierarchy.
  2. Build or fetch firmware. With a firmware path, C3PO auto-detects the chip target (CONFIG_IDF_TARGET), generates an sdkconfig from your form values, and runs idf.py build. Otherwise it uses release binaries.
  3. Generate the factory NVS (fctry, offset 0x14000, 24 KB). Holds the master_key (namespace crypto, key master_key), the device id, and any board-specific modem or camera pins.
  4. Generate the encrypted config NVS. WiFi SSID/password and the Management Protocol server address are encrypted with ChaCha20-Poly1305 under a key derived from master_key via HKDF-SHA256(salt = device_id).
  5. Flash. esptool writes the bootloader, partition table, NVS, OTA data, factory partition, firmware, and config at the architecture-correct offsets (Xtensa bootloader at 0x1000, RISC-V at 0x0).
  6. Register. The device id and key are written to keys.json.

On the next boot the device decrypts its config, connects to the Management Protocol server, and appears in the Fleet view.

Per-device binding

Because the master_key is generated per device and written only to that device's immutable fctry partition, every device has a unique identity. The same key derives the transport, module-signing, and config-encryption keys, so a module signed for one device will not load on another. See the security model.

GPRS and camera boards

For cellular boards, choose GPRS and a board profile (t-call, t-sim7070g) to auto-fill the modem pins. Camera board profiles (esp32s3-cam-n16r8, esp32-cam-aithinker) write the camera pin map to NVS, but runtime camera support is not in the current version (see planned modules). See GPRS boards and ESP32-CAM.

See also