Skip to content

DeviceManagerSettings

Rob Dobson edited this page Oct 25, 2026 · 16 revisions

Raft DeviceManager Settings

{
    "Buses": [
        BusConfig#1,
        BusConfig#2
    ],
    "Devices": [
        DeviceConfig#1,
        DeviceConfig#2
    ],
    "typeTable": {
        "maxExtendedRecords": 32,
        "maxExtendedBytes": 20480
    }
}

Notes:

  • DeviceManager automatically scans the I2C bus to detect devices. For details on the scanning process, priority lists, and multiplexer handling, see I2C Device Scanning.
  • DeviceManager automatically publishes device data through the devjson and devbin topics. For details on the published message formats and how to subscribe to device data, see Device Data Publishing.

typeTable

Limits for device type records added at runtime (extended records - e.g. the records of static devices). Base records are compiled into the firmware and stored in flash, so they need no limit. Each extended record is one allocation, in PSRAM when the board has it (a typical record is about 540 bytes).

Setting Description Type Default Example
maxExtendedRecords Most extended records int 256 with PSRAM, 32 without 64
maxExtendedBytes Most bytes used by extended records int 262144 with PSRAM, 20480 without 40000
runtimeDecoders When a record with no compiled decoder gets its runtime decoder: onIdentify (when a device of the type is first identified - checked when the record is added), atLoad (when the record is added) or off (never: only clients decode its data) string onIdentify "off"
maxDecoderBytes Most bytes runtime decoders may use; -1 for no limit (beyond RAFT_RUNTIME_DECODE_MAX_DECODERS decoders) int no limit with PSRAM, 8192 without (about 8 typical decoders) 4096

A runtime decoder takes about 1 KB (internal RAM without PSRAM). With onIdentify only the types of devices actually present have one, so a board with a large type file and a few devices pays for a few. A decoder that can't be made when it's needed (maxDecoderBytes used up, or no decoder slot free) is logged, and devman/typeinfo reports runtimeFailed with the reason: the device is still identified and polled, and clients still decode its data.

A record that would exceed either limit is not added: a static device whose record isn't added has no device type, and an error is logged. A static device whose record has the same key (type) as one already added but different content (for example a different data size) is also not added - give it a distinct type.

typeSettings

Settings for device types that are choices for the board or product rather than properties of the device: the poll bus speed and the multiplexer slots it applies to, the poll interval, the samples kept, the sample rate and the scan priority. The device type record stays the same for every board.

"typeSettings": {
    "LSM6DS3": { "busHz": 400000, "busHzSlots": "1,2,3,4,7" },
    "VL6180": { "intervalUs": 50000, "scanPriority": "low" }
}
Setting Meaning
intervalUs Poll interval in microseconds (the record's pollInfo.i is the default)
numSamples Poll results kept (the record's pollInfo.s is the default)
busHz I2C bus speed for the device's polls (0 for the bus default)
busHzSlots The multiplexer slots busHz applies to, as "1,2,3" or [1, 2, 3] (empty for all)
sampleRateHz Sample rate, through the record's _conf.rate action (see Device Type Record Format)
scanPriority high, medium, low or none, in place of the record's scanPriority (the scanner's priority lists). low and none both put the address in the last list
  • The first five are the settings devman/devconfig takes. They are applied when a device of the type is identified (and again when it is re-identified or re-initialised). A device's own settings - saved or set with devconfig while running - override them.
  • Each level overrides the one before: the record's defaults; typeSettings; the device's saved settings; devconfig while running.
  • Settings apply just after identification, so the first polls may run with the record's defaults. Initialisation runs at the bus's default speed.
  • Unknown setting names and invalid values are logged at startup and ignored. A key that isn't a device type in the build is logged at the information level. Names starting with _ (e.g. "_notes") are ignored.
  • The poll bus speed is set only here (or with devconfig). Records no longer take pollInfo.busHz or busHzSlots, and the build warns if one does.

typePolicy

Sets whether device type records are used for identification, by device type key. Only identification is affected: typeinfo, decoding and subscriptions are the same whatever the policy.

Policy Meaning
enabled Used for identification (the default)
disabled Not used: the next record that can identify a device at that address gets the chance, then any identification hook
disabledClaim Not used, but the address still counts as claimed: it stays reserved (re-addressable devices keep off it) and identification hooks aren't run there
"typePolicy": { "VCNL4040": "disabled", "AS5600": "disabledClaim" }

A protected type (see expectType) can't be disabled. A policy set here applies from startup. It can also be changed at runtime with devman/typepolicy (not saved), which identifies the devices it affects again. A compiled catalogue can also set a record's initial policy with "disable": true or "disable": "claim" - see Device Type Record Format - and DeviceTypeSources.json can set it for the build (builtin.policy). Use the build selection for "this product never has it", and typePolicy for a board that can be reconfigured.

Device type file

A file of device type records that adds types the firmware doesn't have, overrides compiled ones and disables ones that must not be identified - without rebuilding the firmware. It is loaded at startup, before any device is identified: buses scan for devices meanwhile, and identify them as soon as the file has been loaded. To apply a changed file, upload it under another name, check it with devman/typefile/check?file=... and apply it with devman/typefile/apply?file=..., which makes it the device type file only if nothing in it is rejected and restarts the device. (Uploading it as the device type file and calling devman/typefile/apply also works, without the check.) A type file can be built from a project's DeviceTypeSources.json. A change to device type records is always applied by a restart: until then devman/typefile reports restartRequired, so a client making several changes restarts once. Loading takes roughly 10-15 ms per ordinary record and 60-110 ms per record with custom decode code on an ESP32-S3 (a 44-record file loaded in about 620 ms on an Axiom) - well within typeFileTimeoutMs for a typical file.

Setting Description Type Default Example
typeFile Path of the file; empty for none string DeviceLibrary/devLibFile if set, otherwise /local/devlib.json "/local/devtypes.json"
typeFileRequired A missing file is an error (logged, and reported as state missing). Either way the compiled records are used bool false true
typeFileTimeoutMs If the file hasn't been loaded after this long, devices are identified without it (logged) int 10000 5000
typeFileLimits Limits for the file and its records: maxFileBytes (the file is read into one buffer, in PSRAM where there is any), maxReadBytes (one command), maxSamples (pollInfo.s), maxRecordRingBytes (poll result size with timestamp x samples) object 262144 with PSRAM, 65536 without (RaftCore 1.62.0 and earlier: 65536); 1024, 256, 65536 {"maxSamples": 64}

The file has the shape of DeviceTypeRecords.json, so a compiled record can be copied into it unchanged (Device Type Record Format):

{
    "_notes": "other top-level keys, and _notes in a record, are ignored",
    "devTypes": {
        "MCP9808": { "addresses": "0x18-0x1f", "detectionValues": "...", "pollInfo": {...}, "devInfoJson": {...} },
        "MyNewSensor": { "addresses": "0x4a", "detectionValues": "...", "pollInfo": {...}, "devInfoJson": {...} },
        "LSM6DS3": { "disable": true }
    }
}
  • A new key adds a record (as an extended record, within the typeTable limits).
  • The key of a compiled record overrides it: the file's record replaces the compiled one, keeping its device type index. The compiled record is not tried as well - if the file's detection doesn't match, the device isn't identified by that type.
  • "disable": true (or "claim", as disabledClaim in typePolicy) disables a type that is present; the rest of the entry is ignored, so a type can be disabled by copying its record and adding one field. With a full record and a new key, the record is added already disabled. Disabling a key that isn't present is reported as an error.
  • deviceType, if present, must equal the key. A protected type (see expectType) can't be overridden or disabled.
  • devTypes: {} is a valid file with no custom types.

Each record is checked before it is added - its addresses (0xHH or 0xHH-0xHH), identification fields, command strings (the grammar the firmware uses), the limits above, and that devInfoJson.resp.b equals the size the poll reads produce. A record that fails is rejected on its own; the rest of the file is applied, and the first error is reported by devman/typefile. A record with neither addresses nor hwTypeId is added with a warning, as it can't be identified. A record whose hwTypeId is already used by a record with another key is rejected, as is a record with deviceTypeId (the field's old name, from RaftCore 1.60.0). A record with pollInfo.ext (data supplied by firmware code rather than by polling) is added with a warning unless the firmware has code that supplies that type's data (registered with deviceTypeRecords.registerExtDataSource()).

Saved device settings

Device names, roles, devconfig settings and stopped polling can be saved (save=1 on devman/setname, setrole, devconfig and devenable) and are applied again after a restart. They are kept in one file, keyed by device ID:

Setting Description Type Default Example
deviceSettingsFile Path of the file; empty to save nothing string /local/devsettings.json "/local/mydevs.json"
{
    "devices": {
        "1_68": { "name": "Arm IMU", "role": "system", "type": "MPU6050", "devconfig": { "intervalUs": "100000" }, "poll": false }
    }
}
  • name and role are applied at startup (a name saved here takes the place of one in the SysType configuration).
  • devconfig settings are for the type in type: they are applied when the device is identified as that type, and not if it is identified as another.
  • "poll": false stops polling the device when it is identified (see devman/devenable).

A device ID names a bus and an address (with the multiplexer slot), so the settings belong to whatever device is at that place. Static device IDs are 0_<position in the Devices list>, so reordering that list moves their settings to other devices.

Buses

Array of configurations for Buses which must contain at least the settings defined below. Any other information is passed to the bus constructor as part of the JSON configuration and is specific to the type of bus being defined.

Setting Description Type Default Example
name The name of the bus. string N/A "I2CA"
type The type of the bus which must match a registered bus type string N/A "I2C"

Devices

An array of configurations for Devices. Each entry is either a static-device entry (identified by the presence of a class field — DeviceManager instantiates the device via the DeviceFactory) or a bus-tagging entry (no class field — used purely to assign a friendly name and/or role to a bus-discovered device identified by its bus+addr).

Static-device entries

A class field is required. Any other information is passed to the device constructor as part of the JSON configuration and is specific to the type of device being defined.

Setting Description Type Default Example
class The class name of the device which must match a registered device class. string N/A "Buzzer"
name Optional friendly name for the device. Recorded in DeviceManager's name map and returned by /devman/typeinfo and /devman/listdevs. string (optional) — "Buzzer1"
role Optional role tag. The default role is normal; set to system to mark the device as system infrastructure (e.g. fuel gauge, RTC) so that consumers can distinguish it from standard measurement devices. string (optional) "normal" "system"
enable true (or non-zero) if the device is to be created. bool (optional) true false

Bus-tagging entries

Used to attach a friendly name and/or role to a device that is dynamically detected on a bus (i.e. not instantiated from the Devices list). No factory instantiation occurs — the entry exists purely to associate metadata with the bus address.

Setting Description Type Default Example
bus Bus name (e.g. "I2CA") on which the device lives. string N/A "I2CA"
addr Device address on the bus (hex, with or without 0x). string N/A "0x36"
name Friendly name to assign to the bus device. string (optional) — "FuelGauge"
role Role tag for the bus device (e.g. "system"). string (optional) "normal" "system"
expectType With role: "system": the device type key this device must be. That type is protected - it can't be disabled, overridden or replaced (by typePolicy, a type file or code). A device at this address identified as a different type is logged as an error, and code that uses the device can check the expected type (DeviceManager::getDeviceExpectedType()) so it doesn't misread its data. string (optional) — "MAX17048"
enable Set to false to skip this entry. bool (optional) true false

Example

"Devices": [
    { "class": "Buzzer", "name": "Buzzer1" },
    { "class": "MotorControl", "name": "MotorControl", "role": "system" },
    { "bus": "I2CA", "addr": "0x36", "name": "FuelGauge", "role": "system", "expectType": "MAX17048" },
    { "bus": "I2CA", "addr": "0x6a", "name": "IMU1" }
]

The role and name mappings configured here can also be changed at runtime through the /devman/setname and /devman/setrole REST endpoints (in-memory only — runtime changes are not persisted).

Clone this wiki locally