Skip to main content

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:

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:

FieldTypeDefaultDescription
versioninteger | null3Template 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.
familystring | nullfrom device on exportTarget device family: "ED", "ES", or "BB". null = any. Apply refuses to push a template to a device of a different family.
compatibleModelsstring[] | nullnullOptional 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.
descriptionstring | nullnullHuman-readable description. Shown in the desktop app's template list and in bb-eco template validate output.
createdAtRFC 3339 timestamp | nullexport timeWhen 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"
}
FieldTypeDescription
macstringHardware MAC, colon-separated uppercase
ipstringAddress the device was reachable at when exported
modelstringModel number (e.g. ED-549)
modelVariantstring | nullHardware variant suffix, if any
firmwareVersionstringRunning firmware version
firmwareTypestring | nullChip-class marker on ED (e.g. T); null on ES
firmwareDatestringFirmware 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
}
FieldTypeNotes
dhcpboolean | nulltrue = DHCP, false = static. Static addressing wants staticIp + subnet + gateway together; apply fills any omission from the device's current configuration
staticIpstring | nullDotted quad. Typically null in fleet templates — IPs are device-specific
subnetstring | nullDotted-quad subnet mask
gatewaystring | nullDefault gateway IP. 0.0.0.0 = no gateway
dnsstring | nullRead-only in exports — BB-Eco never writes it (ES firmware has no DNS setting at all)
webPortinteger | nullWeb server port, 1–65535 (default 80). Changing it restarts the device's web server
upnpboolean | nullUPnP/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
}
FieldTypeNotes
namestring | nullUser-facing device name. Maximum 10 characters on ED, 40 on ES — BB-Eco rejects longer values before they reach the device
locationstring | nullFree-form location label, 10-character limit. ED only — ES firmware has no location field
checkConnectivityboolean | nullRead-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"
}
FieldTypeNotes
adminUsername, userUsernamestring | nullAccount usernames, up to 20 characters. Authentication turns on the moment a username is non-empty
adminPassword, userPasswordstring | nullUp to 20 characters. Never commit these to Git
adminPasswordSet, userPasswordSetboolean | nullRead-only export indicators — true if the device has a password set. Ignored by apply
adminMacFilterEnabled, userMacFilterEnabledboolean | nullMAC-based access control toggles
adminMacAddressstring | nullAdmin MAC as exactly 12 hex digits, no separators. 000000000000 = unset. Must differ from every entry in the user MAC list
userMacAddressesstring[] | nullRead-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
authenticationstring | null"Basic" or "Digest"
resetProtectionstring | 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.

Don't commit passwords

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:

FieldTypeNotes
protocolstring | null"ASCII" or "Modbus"
dconAddressint | nullDCON unit address, 1–255 (factory: 1)
dconTcpPortint | nullASCII/DCON TCP port, 1–65535 (factory: 9500)
maxConnectionsint | nullModbus 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
idleTimeoutint | nullASCII idle disconnect in seconds, 0–65535 (0 = never)
counterUpdate, counterModeint | nullCounter configuration, 0 or 1 (digital models)
checksumint | nullDCON checksum enable, 0 or 1
modbusTcpPortint | nullModbus TCP port, 1–65535 (factory: 502)
modbusSlaveIdint | nullRead-only — the device's reported Modbus address (255 = accept all)
modbusIdleTimeoutint | nullModbus idle disconnect in seconds, 0–65535 (0 = never)
modbusRespondToAllSlaveIdsboolean | nulltrue = respond to Modbus server IDs 0–247 and 255; false = 0 and 255 only (factory)
modbusAcceptAllAddressesboolean | nullAccept every register, coil and input address (factory: false)
coldJunctionCompensationboolean | nullThermocouple models (ED-593) only: cold-junction compensation on/off (factory: true)
openWireDetectionboolean | nullThermocouple models only: open-wire detection on/off (factory: true)
temperatureOffsetnumber | nullThermocouple 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)
temperatureOffsetUnitstring | null"C", "F" or "K" — the unit temperatureOffset is written in
gatewayBaudRateint | nullReal 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
commandTimeoutint | nullDCON gateway command timeout in ms, 0–50000 (factory: 200)
eStopLinestring | nullQuick-stop trigger input, as a digital-input number ("0" = DIn 0; "255" = disabled). Present only on devices with both digital outputs and inputs
eStopDirectionstring | nullQuick-stop trigger edge: "0" = falling, "1" = rising. Travels with eStopLine
linesarray | nullPer-line config (see below)

Each entry in lines:

FieldTypeNotes
indexintDevice line slot (0-based, outputs first — the numbering shown on the device's own IO settings page). Required when present
namestring | nullLine name, maximum 10 characters. Only configurable on analogue models — digital models keep their factory names
lineTypestring | nullRead-only hardware fact: "digitalInput", "digitalOutput", "relay", "analogInput", "analogOutput", "rtd", "thermocouple"
enabledboolean | nullAnalogue lines only — digital lines cannot be disabled
unitstring | nullRead-only display unit reported by the device ("°C", "V", "mA")
sensorTypestring | nullAnalogue models: sensor/range selection — thermocouple types ("K", "J", …), RTD types ("Pt100-385", …), voltage/current ranges ("+/-10V", "4-20mA"). Legal values are model-specific
wiringstring | nullRTD models only: "2-wire", "3-wire", "4-wire"
powerOnValuestring | nullOutput 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"
safeValuestring | nullOutput lines: the state driven when all network connections are lost. Same format as powerOnValue
quickStopValuestring | nullDigital outputs and relays (on devices that also have inputs): the state driven when the quick-stop trigger fires. "0"/"1"
debouncestring | nullDigital 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.

note

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
}
}
]
FieldTypeNotes
indexint1-based port number. Required when present
portModestring | null"RS232" or "RS422/485". Only settable on switchable hardware; fixed-mode ports ignore it
overrideAppSettingsboolean | null"Always use these settings" — device settings beat client (RFC 2217) settings
baudRateint | nullReal 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)
dataBitsint | null5–8 (factory: 8)
paritystring | null"None", "Odd", "Even", "Mark", "Space"
stopBitsstring | null"One", "Two", "OnePointFive" (1.5 only on some hardware)
flowControlstring | null"None", "CtsRts", "DtrDsr", "XonXoff". Hardware flow control requires the port to have those lines — unsupported modes are rejected by the device
duplexstring | null"None", "FullDuplex", "HalfDuplexAutoGating". Only meaningful on RS422/485 ports; RS232 forces "None"
protocolstring | null"RawTcp", "TelnetServer", "TelnetRfc2217Server". The device firmware upgrades TelnetServer to TelnetRfc2217Server automatically, so exports show the latter
tcpPortint | nullListening TCP port, 1–65535; ports already in use on the device are rejected (factory: 9001 for port 1, 9002 for port 2, …)
idleTimeoutint | nullIdle disconnect in seconds, 0–65535 (0 = never)
fifoEnabledboolean | nullUART FIFO buffer. Changing it restarts the device
tunnelingobject | nullPort-to-port tunnel across the network (see below)

tunneling shape:

FieldTypeNotes
enabledbooleanTunnel mode on/off
isMasterbooleantrue = initiates the connection, false = listens
remoteIpstring | nullPeer device IP (master side)
remotePortint | nullPeer 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.

warning

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:

  1. device — name, location (no connection impact)
  2. security — credentials (no connection impact)
  3. io (ED) — protocol changes restart the device
  4. serialPorts (ES, ED gateway models) — FIFO changes restart the device
  5. network.webPort + network.upnpmay disconnect if the web port changes
  6. network.dhcp, staticIp, subnet, gatewaymay 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