.scadable/ Folder Spec

The .scadable/ folder lives at the root of your firmware repo. SCADABLE reads it on every build to decide what to compile and how your device behaves in the field. Two files:

FilePurpose
.scadable/config.yamlBuild target + ESP-IDF version + runtime observability (heartbeat, metrics, logs).
.scadable/tests.ymlDeclarative diagnostic test manifest, surfaced in the dashboard.

Both are optional — a repo with no .scadable/ folder still builds (it falls back to an esp32 classic target with all opt-in features off). You add only the keys you need; your repo is the source of truth.

config.yaml

A complete example with every section:

# .scadable/config.yaml

# --- Build ---
device_type: esp32-s3        # which chip to compile for (default: esp32 classic)
idf_version: v5.2.7          # pin the ESP-IDF toolchain (default: build server's)

# --- Heartbeat ---
heartbeat:
  interval_seconds: 30       # how often the device reports in (default: 30)

# --- Metrics (opt-in; always-on fields ship regardless) ---
metrics:
  collect:
    - cpu_percent
    - mem_kb
    - wifi_rssi
    - mqtt_reconnect_count

# --- On-device logs (opt-in) ---
logs:
  enabled: true
  upload_interval_seconds: 60
  buffer_kb: 16
  min_level: I               # one of V, D, I, W, E

Everything outside device_type and idf_version is translated into CONFIG_SCD_* Kconfig flags and compiled in — there's zero overhead when a feature is left out.

device_type

Picks the ESP-IDF build target. Hyphen, lowercase. Unknown or missing → esp32 classic.

device_typeChip
esp32-classic (or esp32)ESP32 (original / "classic")
esp32-s2ESP32-S2
esp32-s3ESP32-S3
esp32-c2ESP32-C2
esp32-c3ESP32-C3
esp32-c6ESP32-C6
esp32-h2ESP32-H2

idf_version

Pins the ESP-IDF toolchain the build uses. Accepts v5.2.7 or 5.2.5 (normalised to the v-prefixed tag). Omit it to use the build server's default image.

heartbeat

KeyDefaultNotes
interval_seconds30How often the device publishes a heartbeat.

metrics

Five fleet-health fields ship in every heartbeat automatically and don't need to be requested: boot, reset_reason, client_ts_ms, fw, uptime_s.

Beyond those, list the extra metrics you want under metrics.collect. Each one you opt into is compiled in; unknown names are ignored with a build-log warning.

MetricMeaning
bytes_outBytes transmitted
bytes_inBytes received
cpu_percentCPU utilisation
mem_percentFree heap as a percentage
mem_kbFree heap in KB
storage_kbFree storage in KB
server_latency_msRound-trip latency to the broker
wifi_rssiWi-Fi signal strength
mqtt_reconnect_countMQTT reconnect count
ota_rollback_countOTA rollback count
current_partitionActive OTA partition

logs

On-device log capture: the library hooks ESP_LOG*, batches lines into a ring buffer, and uploads them to the dashboard. Off by default.

KeyDefaultNotes
enabledfalseMaster switch for log capture + upload.
upload_interval_seconds60Flush cadence.
buffer_kb16Ring buffer size (2–64 KB).
min_levelIMinimum level to upload: V, D, I, W, E.

tests.yml

A declarative manifest of diagnostic tests SCADABLE surfaces in the dashboard. Captured at build time and attached to the deployment.

# .scadable/tests.yml
- id: wifi_connect
  type: connectivity
  description: Verify the device joins Wi-Fi within 30s of boot
- id: sensor_read
  type: hardware
  description: Confirm the primary sensor returns a plausible reading

Sync semantics

  • The build reads .scadable/ from your latest pushed commit.
  • A change inside .scadable/ takes effect on the next build (push to your repo's default branch, or trigger a build from the dashboard).
  • These files are build-time configuration — they're baked into the firmware image. They are not live-editable from the dashboard. Your repo is the source of truth.
  • For settings you do want to change live from the dashboard without rebuilding, see Config Variables — the config: block of config.yaml declares typed variables you set per org / namespace / device at runtime.

Common mistakes

  • YAML, not TOML. It's .scadable/config.yaml, not .scadable/config.toml. Older examples used TOML; that format is gone.
  • config.yaml vs tests.yml. The build config is config.yaml; the test manifest is tests.yml (note the .yml spelling). Mixing them up means your tests won't be captured.
  • Hyphen, not underscore. esp32-classic, not esp32_classic. Hyphen, lowercase.
  • Unknown metric names are silently dropped (with a build-log warning). Check the build log if a metric you expected isn't showing up.