Skip to content

Device Manifest

Each device library entry is a folder that must contain a manifest.json at its root. This document describes the manifest format; the machine-readable subset is in device-manifest.schema.json.

Top-level fields

Most of the fields are optional, defined depending on needs.

FieldDescription
nameDisplay name in the device library and scan UI.
descriptionShort summary.
authorAuthor or vendor label.
manifest_versionInteger manifest format version (which keys and semantics the app expects). Current value: 1.
manifest_version_noteOptional. Only if you need a short label when bumping manifest_version (e.g. "added device_name_regex")
versionInteger content revision; shown in the library UI, bumped when you edit a the entry, and compared with the ESP32 copy for sync.
notesLonger free-form notes and description.
author_url, model_url, source_urlOptional links (URI).
profileRelative path to BLE profile JSON (e.g. ble.json).
uuidsRelative path to UUID map (default uuids.json when omitted).
varsRelative path to JSON merged into the Lua vars global (e.g. vars.json).
assetsicon, graphics, optional icon_tint for scan row / Lua.
appsCompanion app store links (google, apple, direct[]).
rolesobserver, central, peripheral — see below.

Roles

Observer (roles.observer)

Runs on scan when advertisement conditions match. Lower priority runs first.

FieldDescription
entryRelative path to observer Lua (e.g. observer/adv_decode.lua). Omit for simple manifest-only option: scan_conditions + assets.icon apply overlay icon without Lua.
priorityInteger. Lower priority runs first.
scan_conditionsWhen to run this observer — see Scan conditions.

Fingerprinting (Lua parse() or manifest-only icon) runs only when the canonical advertisement payload for that device changes, not on every duplicate ADV.

Central (roles.central)

Scripts after connect / on the Inspect sheet. Each item in scripts[]:

FieldDescription
idStable script id.
titleUI label.
kindfull_menu (Scripts tab + menu JSON) or quick_action (one-shot Inspect action).
entryRelative path to central Lua.
menuMenu JSON path (required for full_menu).
priorityOrdering when multiple scripts match.
auto_run_on_connectRun automatically after GATT discovery when matched.
varsPer-script string map merged into Lua vars.
matchfingerprint (key → allowed values), services (GATT UUIDs), require_discovered_services (default true), fingerprint_or_services.

Central matching uses fingerprint overlay keys and discovered GATT services, not scan_conditions.

Peripheral (roles.peripheral)

Advertiser / peripheral simulation.

FieldDescription
advertisementPath to advertisement profile JSON.
entryPeripheral Lua entry.
interfaceUI interface JSON - simulating “physical” on-device buttons etc.

Scan conditions

Used only under roles.observer.scan_conditions. Evaluated against the parsed advertisement before observer Lua runs.

Combining rules

  • Top-level keys on one object are ANDed.
  • one_of: array of nested condition objects; at least one branch must match (OR). Each branch is ANDed internally. Branches may nest one_of.
  • Most fields accept a single value or a JSON array; within that field, any array element may match (OR).

Condition keys

KeyMatches
company_idManufacturer company ID (16-bit). Prefer four hex digits (004C, 05A7).
manufacturer_data_prefix_hexHex prefix of manufacturer specific data.
service_uuid_128Full 128-bit service UUID in the AD service list.
service_uuid_1616-bit service UUID in the AD service list (e.g. fe2c).
service_data_uuid_128128-bit UUID key in service data AD.
service_data_uuid_1616-bit UUID key in service data AD (0x16).
device_name_containsCase-sensitive substring of the advertised device name.
device_name_regexKotlin regex on the advertised device name (see below).
fingerprint_has_entry_idPrior fingerprint entry id from another observer (chained decode).
fingerprint_entry_attributesAttribute map on that entry; requires fingerprint_has_entry_id.
ad_typeAD type byte(s), used with ad_type_data_hex.
ad_type_data_hexHex prefix or regex on payload(s) for ad_type.
has_gap_device_type_hintstrue if Appearance, Class of Device, or service UUID list is present.

device_name_contains vs device_name_regex

Use device_name_contains for simple substring checks:

"scan_conditions": {
  "device_name_contains": "Pixel Buds 2a"
}
"device_name_contains": ["WH-CH720N", "LE-WH-CH720N"]

Use device_name_regex when you need anchors, character classes, or alternation:

"scan_conditions": {
  "device_name_regex": "^QCAR-[0-9A-F]{4}$"
}
"scan_conditions": {
  "device_name_regex": ["^WH-CH720N$", "^LE-WH-CH720N$"]
}
TopicBehavior
TargetComplete / Short Local Name from the advertisement (device_name in Lua). Empty if absent.
Match modeRegex(pattern).containsMatchIn(name) — use ^ and $ for full-string match.
CaseCase-sensitive; use (?i) in the pattern for ignore-case.
Invalid regexTreated as non-match (no crash).
With device_name_containsIf both are set, both must pass.

Chained observers (one_of + fingerprint)

Example: run only when Apple meta continuity was decoded first:

"scan_conditions": {
  "fingerprint_has_entry_id": "apple_meta",
  "fingerprint_entry_attributes": {
    "continuity_has_nearbyinfo": "true"
  }
}

Example: company id only (manifest-only icon)

"roles": {
  "observer": {
    "priority": 20,
    "scan_conditions": {
      "company_id": "05A7"
    }
  }
}

Requires assets.icon when entry is omitted.

JSON Schema

device-manifest.schema.json validates the structured parts of the manifest (especially scan_conditions). The app does not load this file at runtime; it documents the contract for authors and editors.

Point your editor’s JSON Schema setting at that file when editing a pack’s manifest.json, or use it in CI if you add manifest linting.

Version fields and ESP32 sync

  • manifest_version: format of the JSON file (bump when adding breaking manifest keys).
  • version: content revision of the device library folder. The app increments version when you save edits; ESP32 sync compares the phone copy with manifest.json on the device (SYNCED when equal, OUTDATED when the phone is higher).
© BLESPlo.it · BLE Research Tool · GitHub