BB-Eco template JSON format
This page documents the JSON file format used by bb-eco template export, bb-eco template apply, bb-eco template diff, and the desktop app's Download Template / Apply Template actions on a device's Info tab.
For the concepts behind config as code see Configuration as code with BB-Eco. For the CLI commands that read and write this format, see the bb-eco template reference.
Reference templates (download)
Two fully-commented reference templates document every key, its factory default, and the value range the device firmware enforces:
- ED range reference template — Ethernet Remote IO (digital, analogue, temperature models)
- ES range reference template — Ethernet-to-Serial models
They are .jsonc files (JSON with comments) so every key can carry its explanation inline. template apply parses strict JSON, so strip the comments before feeding one to the tool:
sed 's|//.*||' ed-template-reference.jsonc > my-template.json
bb-eco template validate my-template.json
Top-level shape
{
"identity": { /* DeviceIdentitySection — read-only, shown by bb-eco config */ },
"network": { /* NetworkTemplateSection — DHCP, gateway, web port */ },
"device": { /* DeviceTemplateSection — name, location */ },
"security": { /* SecurityTemplateSection — credentials, MAC filter */ },
"io": { /* IoTemplateSection — ED only */ },
"serialPorts": [ /* SerialPortTemplateSection[] — ES, and ED gateway models */ ],
"version": 3,
"family": "ED",
"compatibleModels": ["ED-588", "ED-549"],
"description": "Production ED I/O baseline — Modbus TCP, DHCP",
"createdAt": "2026-05-05T15:42:00Z"
}
Every section and every field is optional. A null field or a missing section means don't touch — BB-Eco leaves the corresponding setting on the target device unchanged, and template diff never reports it as drift.
Envelope fields
Five top-level fields describe the template itself, not the device configuration:
| Field | Type | Default | Description |
|---|---|---|---|
version | integer | null | 3 | Template schema version. Omit it and the current version is assumed. 3 (current) adds the Modbus server-ID and address flags, the thermocouple globals and serial ports on ED gateway models; 2 files still validate, diff and apply. Older 1 files are refused — re-export them. |
family | string | null | from device on export | Target device family: "ED", "ES", or "BB". null = any. Apply refuses to push a template to a device of a different family. |
compatibleModels | string[] | null | null | Optional model allowlist. If set, apply refuses a device whose model isn't in the list. Useful for templates that include settings only valid on specific hardware. |
description | string | null | null | Human-readable description. Shown in the desktop app's template list and in bb-eco template validate output. |
createdAt | RFC 3339 timestamp | null | export time | When the template was generated. Informational only. |
These envelope fields are suppressed from bb-eco config <device> output but written by bb-eco template export.
identity — read-only device identity
A read-only snapshot of one device. bb-eco template export and the app's Download Template leave it out, so an exported template is portable from the start; bb-eco config <device> shows it as part of the device readout. Never applied by template apply, never compared by template diff — if you add it to a template by hand, it is ignored.
"identity": {
"mac": "00:0A:4F:06:4A:EE",
"ip": "192.168.0.63",
"model": "ED-549",
"modelVariant": null,
"firmwareVersion": "8.25",
"firmwareType": "T",
"firmwareDate": "26/06/2023"
}
| Field | Type | Description |
|---|---|---|
mac | string | Hardware MAC, colon-separated uppercase |
ip | string | Address the device was reachable at when exported |
model | string | Model number (e.g. ED-549) |
modelVariant | string | null | Hardware variant suffix, if any |
firmwareVersion | string | Running firmware version |
firmwareType | string | null | Chip-class marker on ED (e.g. T); null on ES |
firmwareDate | string | Firmware build date as the device reports it |
network — network configuration
"network": {
"dhcp": true,
"staticIp": null,
"subnet": "255.255.255.0",
"gateway": "0.0.0.0",
"dns": null,
"webPort": 80,
"upnp": true
}
| Field | Type | Notes |
|---|---|---|
dhcp | boolean | null | true = DHCP, false = static. Static addressing wants staticIp + subnet + gateway together; apply fills any omission from the device's current configuration |
staticIp | string | null | Dotted quad. Typically null in fleet templates — IPs are device-specific |
subnet | string | null | Dotted-quad subnet mask |
gateway | string | null | Default gateway IP. 0.0.0.0 = no gateway |
dns | string | null | Read-only in exports — BB-Eco never writes it (ES firmware has no DNS setting at all) |
webPort | integer | null | Web server port, 1–65535 (default 80). Changing it restarts the device's web server |
upnp | boolean | null | UPnP/SSDP announcements on/off. Applies live on both families |
network is applied last in the apply order so that an IP change can't strand the rest of the apply.
device — device-level identity settings
"device": {
"name": "Pumphouse1",
"location": "Pumphouse",
"checkConnectivity": false
}
| Field | Type | Notes |
|---|---|---|
name | string | null | User-facing device name. Maximum 10 characters on ED, 40 on ES — BB-Eco rejects longer values before they reach the device |
location | string | null | Free-form location label, 10-character limit. ED only — ES firmware has no location field |
checkConnectivity | boolean | null | Read-only on current firmware — exported for information, never written |
On ED devices name and location are always written together as one operation — the firmware only accepts them as a pair.
security — credentials and access control
Excluded from export by default. Pass --include-security to opt in for usernames, MAC filters, and auth method. Passwords are never written by export; a template only carries one if you type it in (rarely a good idea — see the warning below).
"security": {
"adminUsername": "admin",
"adminPassword": null,
"userUsername": null,
"userPassword": null,
"adminPasswordSet": true,
"userPasswordSet": false,
"adminMacFilterEnabled": false,
"adminMacAddress": "000000000000",
"userMacFilterEnabled": null,
"userMacAddresses": ["000A4F112233"],
"authentication": "Basic",
"resetProtection": "Everybody"
}
| Field | Type | Notes |
|---|---|---|
adminUsername, userUsername | string | null | Account usernames, up to 20 characters. Authentication turns on the moment a username is non-empty |
adminPassword, userPassword | string | null | Up to 20 characters. Never commit these to Git |
adminPasswordSet, userPasswordSet | boolean | null | Read-only export indicators — true if the device has a password set. Ignored by apply |
adminMacFilterEnabled, userMacFilterEnabled | boolean | null | MAC-based access control toggles |
adminMacAddress | string | null | Admin MAC as exactly 12 hex digits, no separators. 000000000000 = unset. Must differ from every entry in the user MAC list |
userMacAddresses | string[] | null | Read-only via templates — the device manages this list one entry at a time (up to 32 entries), so maintain it through the device web UI |
authentication | string | null | "Basic" or "Digest" |
resetProtection | string | null | "Everybody" or "AdminOnly" — controls who may factory-reset or restart the device |
Apply uses read-modify-write: null fields are filled from the device's current values, so a partial security template can never accidentally clear a password.
A template can carry passwords if you add them by hand, but storing passwords in version control is rarely the right answer. Prefer leaving adminPassword and userPassword as null in committed templates and setting them through a separate secure-secrets workflow.
io — IO protocol configuration (ED only)
"io": {
"protocol": "Modbus",
"modbusTcpPort": 502,
"modbusIdleTimeout": 60,
"maxConnections": 8,
"modbusRespondToAllSlaveIds": false,
"modbusAcceptAllAddresses": false,
"gatewayBaudRate": 9600,
"eStopLine": "255",
"eStopDirection": "0",
"lines": [
{ "index": 0, "powerOnValue": "0", "safeValue": "1", "quickStopValue": "0" },
{ "index": 4, "debounce": "50" },
{ "index": 6, "name": "TankTemp", "enabled": true, "sensorType": "Pt100-385", "wiring": "3-wire" }
]
}
Top-level fields:
| Field | Type | Notes |
|---|---|---|
protocol | string | null | "ASCII" or "Modbus" |
dconAddress | int | null | DCON unit address, 1–255 (factory: 1) |
dconTcpPort | int | null | ASCII/DCON TCP port, 1–65535 (factory: 9500) |
maxConnections | int | null | Modbus TCP "Max. Connections", 1–16 (factory: 8). Exports from BB-Eco releases before version-3 templates recorded a different, unused value here; apply and diff ignore it in those files |
idleTimeout | int | null | ASCII idle disconnect in seconds, 0–65535 (0 = never) |
counterUpdate, counterMode | int | null | Counter configuration, 0 or 1 (digital models) |
checksum | int | null | DCON checksum enable, 0 or 1 |
modbusTcpPort | int | null | Modbus TCP port, 1–65535 (factory: 502) |
modbusSlaveId | int | null | Read-only — the device's reported Modbus address (255 = accept all) |
modbusIdleTimeout | int | null | Modbus idle disconnect in seconds, 0–65535 (0 = never) |
modbusRespondToAllSlaveIds | boolean | null | true = respond to Modbus server IDs 0–247 and 255; false = 0 and 255 only (factory) |
modbusAcceptAllAddresses | boolean | null | Accept every register, coil and input address (factory: false) |
coldJunctionCompensation | boolean | null | Thermocouple models (ED-593) only: cold-junction compensation on/off (factory: true) |
openWireDetection | boolean | null | Thermocouple models only: open-wire detection on/off (factory: true) |
temperatureOffset | number | null | Thermocouple models only: offset added to every reading, in temperatureOffsetUnit. −99.99 to +99.99 in C or K, −179.96 to +179.96 in F (factory: 0) |
temperatureOffsetUnit | string | null | "C", "F" or "K" — the unit temperatureOffset is written in |
gatewayBaudRate | int | null | Real baud rate in bps of the DCON serial gateway: 1200, 2400, 4800, 9600, 19200, 38400, 57600, or 115200. Digital-only models have no gateway port and keep their stored value regardless of writes |
commandTimeout | int | null | DCON gateway command timeout in ms, 0–50000 (factory: 200) |
eStopLine | string | null | Quick-stop trigger input, as a digital-input number ("0" = DIn 0; "255" = disabled). Present only on devices with both digital outputs and inputs |
eStopDirection | string | null | Quick-stop trigger edge: "0" = falling, "1" = rising. Travels with eStopLine |
lines | array | null | Per-line config (see below) |
Each entry in lines:
| Field | Type | Notes |
|---|---|---|
index | int | Device line slot (0-based, outputs first — the numbering shown on the device's own IO settings page). Required when present |
name | string | null | Line name, maximum 10 characters. Only configurable on analogue models — digital models keep their factory names |
lineType | string | null | Read-only hardware fact: "digitalInput", "digitalOutput", "relay", "analogInput", "analogOutput", "rtd", "thermocouple" |
enabled | boolean | null | Analogue lines only — digital lines cannot be disabled |
unit | string | null | Read-only display unit reported by the device ("°C", "V", "mA") |
sensorType | string | null | Analogue models: sensor/range selection — thermocouple types ("K", "J", …), RTD types ("Pt100-385", …), voltage/current ranges ("+/-10V", "4-20mA"). Legal values are model-specific |
wiring | string | null | RTD models only: "2-wire", "3-wire", "4-wire" |
powerOnValue | string | null | Output lines: the state driven at power-up. Digital outputs and relays: "0"/"1"; analogue outputs: the device's display-formatted value, e.g. "+05.000" |
safeValue | string | null | Output lines: the state driven when all network connections are lost. Same format as powerOnValue |
quickStopValue | string | null | Digital outputs and relays (on devices that also have inputs): the state driven when the quick-stop trigger fires. "0"/"1" |
debounce | string | null | Digital inputs on debounce-capable models: input debounce time in milliseconds |
Exports include only the per-line keys that apply to the line's hardware type — a relay carries its three output values, a digital input its debounce, an analogue line its sensor config. An absent key means the same as null: don't touch.
A template may list only the lines it changes — apply reads the device's current line configuration and merges before writing, because the device accepts line configuration only as a complete set. If the device reports an active ASCII/Modbus client connection, it refuses line-configuration writes until the client disconnects; apply surfaces the device's own message when that happens.
Applying protocol settings (the io section's top-level fields) restarts the device — plan for a brief loss of IO connectivity.
serialPorts — serial port configuration (ES, and ED gateway models)
Every ES device exports its ports here; so does an ED model with a serial gateway port, which reports it in the same shape. Array of port configurations:
"serialPorts": [
{
"index": 1,
"portMode": "RS422/485",
"overrideAppSettings": true,
"baudRate": 115200,
"dataBits": 8,
"parity": "None",
"stopBits": "One",
"flowControl": "None",
"duplex": "HalfDuplexAutoGating",
"protocol": "RawTcp",
"tcpPort": 9001,
"idleTimeout": 60,
"fifoEnabled": true,
"tunneling": {
"enabled": false,
"isMaster": true,
"remoteIp": null,
"remotePort": null
}
}
]
| Field | Type | Notes |
|---|---|---|
index | int | 1-based port number. Required when present |
portMode | string | null | "RS232" or "RS422/485". Only settable on switchable hardware; fixed-mode ports ignore it |
overrideAppSettings | boolean | null | "Always use these settings" — device settings beat client (RFC 2217) settings |
baudRate | int | null | Real baud rate in bps, 60–1,000,000 (up to 3,000,000 on some ES-522 hardware). Non-standard rates in range are legal (factory: 115200) |
dataBits | int | null | 5–8 (factory: 8) |
parity | string | null | "None", "Odd", "Even", "Mark", "Space" |
stopBits | string | null | "One", "Two", "OnePointFive" (1.5 only on some hardware) |
flowControl | string | null | "None", "CtsRts", "DtrDsr", "XonXoff". Hardware flow control requires the port to have those lines — unsupported modes are rejected by the device |
duplex | string | null | "None", "FullDuplex", "HalfDuplexAutoGating". Only meaningful on RS422/485 ports; RS232 forces "None" |
protocol | string | null | "RawTcp", "TelnetServer", "TelnetRfc2217Server". The device firmware upgrades TelnetServer to TelnetRfc2217Server automatically, so exports show the latter |
tcpPort | int | null | Listening TCP port, 1–65535; ports already in use on the device are rejected (factory: 9001 for port 1, 9002 for port 2, …) |
idleTimeout | int | null | Idle disconnect in seconds, 0–65535 (0 = never) |
fifoEnabled | boolean | null | UART FIFO buffer. Changing it restarts the device |
tunneling | object | null | Port-to-port tunnel across the network (see below) |
tunneling shape:
| Field | Type | Notes |
|---|---|---|
enabled | boolean | Tunnel mode on/off |
isMaster | boolean | true = initiates the connection, false = listens |
remoteIp | string | null | Peer device IP (master side) |
remotePort | int | null | Peer TCP port |
A template may set only the fields it cares about — apply reads the port's current configuration and merges before writing, because the device accepts port configuration only as a complete set.
A serial port with a connected TCP client rejects configuration changes — apply reports the error and the port keeps its old settings. Disconnect clients first.
Apply order
bb-eco template apply pushes the sections to the device in a fixed order so a connection-dropping change can't strand the rest of the apply:
device— name, location (no connection impact)security— credentials (no connection impact)io(ED) — protocol changes restart the deviceserialPorts(ES, ED gateway models) — FIFO changes restart the devicenetwork.webPort+network.upnp— may disconnect if the web port changesnetwork.dhcp,staticIp,subnet,gateway— may disconnect if the IP changes
If the device becomes unreachable after step 5 or 6, apply treats this as success — the new settings took effect, and the device is now at its new address. bb-eco discover finds it again.
Versioning
version: 3 is the current schema. Compared with 2 it is purely additive: the two Modbus
flags, the thermocouple globals and serialPorts on ED gateway models. version: 2 files
still validate, diff and apply. version: 1 files — exports made by BB-Eco releases before
August 2026 — are refused, because they recorded IO line values in a different order;
re-export the device to get a current template. BB-Eco also refuses templates from a newer
schema than it understands. Don't set the field manually — BB-Eco writes the right value on
export, and a hand-written template can leave it out.
More resources
- ED reference template and ES reference template — every key with defaults and firmware-enforced ranges
- Configuration as code with BB-Eco — concept and rationale
- Detect configuration drift with BB-Eco — task walkthrough
bb-eco templateCLI reference — every command and option, with real output