DocsBluetooth LE Open APIDevice State Reference

Device State Reference

The device's live state, exposed as named values you can read, write, and subscribe to.

Device state is a flat set of named values. Each one is:

  • Readable — { method: "get", ns: "deviceState", prop: "<KEY>" }
  • Writable — { method: "set", ns: "deviceState", prop: "<KEY>", value: … }
  • Streamable — whenever a value changes, an event is pushed on EVENTS_OUT (while DEVICE_APP_CONNECTED is true).

Reading vs. writing in practice

Many values are populated by the device itself (GPS, battery, kill counts, ammo during play) — you'll usually read and subscribeto those rather than write them. The API allows writing any value; it's coerced to the value's type and rejected with invalidValue on a mismatch.

Device

KeyTypeDescription
FSM_STATEstringCurrent state-machine state (also on the fsm namespace).
DEVICE_ROLEnumberHost, client, moderator, etc.
DEVICE_ENVnumberIndoor / outdoor environment.
DEVICE_VOLUMEnumberDevice audio volume.
DEVICE_BATTERY_LEVELnumberBattery percent, 0–100, on the Li-ion discharge curve (0% at 3.2 V a cell); 255 before the first reading. Event rate-limited (~5s).
DEVICE_BATTERY_MVnumberThe pack's voltage in millivolts, smoothed: the one the percentage comes from. Event rate-limited (~5s).
DEVICE_BATTERY_MINUTESnumberEstimated minutes of play left, from the percentage and the minutes table (@battlecore/api/battery); 65535 with no pack or before the first reading. Event rate-limited (~5s).
DEVICE_BATTERY_WARNbooleanThe battery warning: the minutes left under device/batteryWarnMinutes (30 by default), or the low flag. What turns the tagger's battery red.
DEVICE_BATTERY_LOWbooleanUnder 3.2 V a cell (clears above 3.35 V): the hard floor.
DEVICE_BATTERY_FAULTbooleanUnder 2.8 V a cell: a dead cell or no working protection. Do not charge it.
DEVICE_BATTERY_PACK_PRESENTbooleanWhether a pack is fitted; false on USB power.
DEVICE_WIFI_NAMEstringProvisioned WiFi network name.
DEVICE_WIFI_STATUSnumber0 = disconnected, 1 = connecting, 2 = connected.
DEVICE_BLE_MACstringThe device's Bluetooth MAC address.
DEVICE_BLE_COUNTnumberNumber of connected BLE devices.
DEVICE_APP_CONNECTEDbooleanSet true to enable the live event stream. Set on connect.
DEVICE_HEADSET_CONNECTEDbooleanWhether a headset is paired.
HEADSET_BATTERY_LEVELnumberThe linked headset's battery percent, 0–100, as it reports it; 255 while none is linked or it has not reported. Event rate-limited (~5s).
HEADSET_BATTERY_MVnumberThe linked headset's pack voltage in millivolts; 0 while none is linked.
HEADSET_BATTERY_MINUTESnumberThe linked headset's estimated minutes left (the headset's table); 65535 when unknown.
HEADSET_BATTERY_LOWbooleanThe linked headset is under 3.2 V a cell.
HEADSET_BATTERY_FAULTbooleanThe linked headset is under 2.8 V a cell: do not charge it.
HEADSET_BATTERY_WARNbooleanThe linked headset's minutes left are under this tagger's device/batteryWarnMinutes, or it is low.
HEADSET_BATTERY_PACK_PRESENTbooleanThe linked headset has a pack fitted.
HEADSET_LOOKnumberHow the headset's lights look for this player: 0 as usual, 1 down between lives (a red pulse), 2 out (dark). Always 0 when the game's headsetDownFlash is off.
DEVICE_ESP_BRIDGEbooleanRelay ESP-NOW mesh traffic over the event channel.
IR_RECEIVER_ENABLEDbooleanWhether the IR receiver is enabled.
DEVICE_DEBUG_ENABLEDbooleanWhether BLE debug output is enabled.

NFC

KeyTypeDescription
NFC_TAGstringUID (hex) of the currently-present NFC tag; empty when no tag is present. Treat a change to a non-empty value as "a tag appeared", and to empty as "removed".
NFC_DATAstringThe first NDEF text/URI record payload of the last tag read. Set (and streamed) just before NFC_TAG when a tag appears, so it is available when NFC_TAG changes. NOT cleared on removal.

Location

KeyTypeDescription
GPS_SATELLITESnumberSatellites locked. Event rate-limited (~2s).
MOTION_SPEEDnumberThe player's speed from the tagger's accelerometer: 0 still, 1 walking, 2 running. Changes at most every couple of seconds (a new speed has to hold 2 s). Always 0 on a tagger with no accelerometer.
GPS_LATITUDEnumberLatitude. Event rate-limited (~2s).
GPS_LONGITUDEnumberLongitude. Event rate-limited (~2s).

Game

KeyTypeDescription
GAME_CONNECTEDbooleanWhether the device is in a game.
GAME_IDnumberCurrent game id.
GAME_UIDstringThe game's uid for telemetry: 32 hex characters the host made as it started the game, the same on every tagger in it. Empty outside a game, and before the start.
GAME_STARTED_ATnumberWhen the host started the game, in seconds since 1970 (UTC); 0 when the host's clock had not been set (device/time).
GAME_PLAYER_COUNTnumberPlayers in the game / lobby.
GAME_HOST_MACstringThe host's MAC address (when this device is a client).
GAME_DISPLAY_NAMEstringHuman-readable game name.
GAME_TIMEnumberLive game clock. GET returns the running clock.
GAME_TIME_MAX_MINSnumberGame length in minutes (0 = unlimited).
GAME_SCRIPT_IDstringBattleScript file id for the game.
GAME_SCRIPT_LABELstringBattleScript label.
GAME_IS_TEAM_BASEDbooleanWhether the game is team-based.
GAME_ENVIRONMENTnumberWhere the game is played: 0 indoor, 1 mixed, 2 outdoor. The host's choice, sent to every tagger in its game.
GAME_SHOT_RANGE_MAXnumberThe environment's maximum shot range, 1-100% of full reach, from the host's device/environmentRanges.
GAME_RESPAWN_MODEnumberHow the game respawns a player, from its config (respawnMode). The game script gives it meaning, not the firmware: the shipped games use 0 for "pull the trigger" and anything else for "something else respawns you" (a base, a medic).
GAME_RESPAWN_TIME_SECSnumberHow long a respawn takes, in seconds, from the config (respawnTimeSecs, 5 when absent) or the script. The respawn screen counts it down.
GAME_LAST_STANDING_ENDSbooleanWhether the game ends by itself when only one side, or one player, is still in. True unless the config (lastStandingEnds) or the script turns it off, as a game that ends itself does.
GAME_WEAPON_SLOT_1numberWeapon id the first slot starts holding — a reference into the game's weapons list, not a definition. 0 means the slot starts empty, which is how a game makes players find a weapon before they can shoot.
GAME_WEAPON_SLOT_2numberAs above for the second slot. Published but not yet equipped from: there is no weapon switching, so a second slot has nowhere to go.
GAME_IR_PROTOCOLstringThe game's IR protocol (irProtocol in its config): every tagger in the game shoots and hears with it. Empty outside a game, where the default (battlecore2) is used.
GAME_IR_CARRIER_HZnumberThe game's IR carrier in place of its protocol's own (irCarrierHz in its config): 36000, 38000, 40000 or 56000; 0 for the protocol's. The host's, sent to every tagger in its game and kept for a rejoin.
GAME_RADAR_TYPEnumberMotion tracker mode: 0 = off, 1 = players shown only while walking or running (MOTION_SPEED above 0, by the thresholds in motion/config), 2 = players always shown.
GAME_TRACKER_RANGE_MnumberRadius the motion tracker covers, in metres.
GAME_GPS_TRANSMITbooleanWhether the device broadcasts its position even with the radar off, so positions can be logged for replay. Any GAME_RADAR_TYPE above 0 turns this on regardless.
GAME_GPS_MIN_MOVE_MnumberMetres the player must move before their position is broadcast again. Keeps GPS drift off the air while a player stands still.
GAME_MAP_TYPEnumber0 = unlimited, 1 = limited.
GAME_SCORE_BASEDbooleanWhether this game scores points. When false the leaderboard ranks on kills alone and every player's points stay at zero. Absent means false.
AUDIO_PACKstringAudio pack in use.
TEAM_POINTSnumberThe team's total score (signed).

Player & vitals

KeyTypeDescription
PLAYER_READYbooleanWhether the player is marked ready.
PLAYER_NAMEstringPlayer name.
PLAYER_IDnumberPlayer / tagger id.
PLAYER_TEAM_IDnumberTeam the player is on: 0–15 (0 red, 1 blue, 2 yellow, 3 green; 4–15 have no colour yet), or 255 for none, as in a free-for-all.
PLAYER_SHIELDnumberCurrent shield.
PLAYER_SHIELD_INITIALnumberShield the player starts with.
PLAYER_SHIELD_MAXnumberMaximum shield.
PLAYER_SHIELD_FULL_RECHARGE_TIMEnumberms to recharge shield 0→100%. 0 = not recharging.
PLAYER_ARMOURnumberCurrent armour.
PLAYER_ARMOUR_INITIALnumberArmour the player starts with.
PLAYER_ARMOUR_MAXnumberMaximum armour.
PLAYER_LIVESnumberCurrent lives.
PLAYER_LIVES_INITIALnumberLives the player starts with.
PLAYER_LIVES_MAXnumberMaximum lives.
PLAYER_POINTSnumberThe player's total score (signed).
PLAYER_KILL_COUNTnumberKills achieved.
PLAYER_DEATH_COUNTnumberDeaths.
PLAYER_IS_INVULNERABLEbooleanWhether the player cannot take damage.
PLAYER_IS_RESPAWNINGbooleanWhether a respawn countdown is running.
COUNTDOWN_SECSnumberLive on-screen countdown in seconds (e.g. respawn). Read alongside FSM_STATE.

Weapon

KeyTypeDescription
WEAPON_IDnumberCurrently enabled weapon.
WEAPON_AMMOnumberCurrent ammo.
WEAPON_AMMO_MAXnumberMaximum ammo.
WEAPON_SHOTS_FIREDnumberTotal shots fired.
WEAPON_SHOT_POWERnumberCurrent shot power (damage or healing).
WEAPON_SHOT_RANGEnumberHow far the current weapon's shots carry, 1-100% of the emitter's full reach (50 reaches about half as far). Set from the weapon when it is equipped; each shot carries it times GAME_SHOT_RANGE_MAX.
WEAPON_SHOT_TYPEnumberCurrent shot type.
WEAPON_SHOT_INTERVAL_MSnumberMinimum time between shots (fire rate).
WEAPON_SHOT_CHARGE_MIN_MSnumberMinimum charge-up time.
WEAPON_SHOT_CHARGE_MAX_MSnumberMaximum charge-up time.
WEAPON_SHOT_DELAY_MSnumberDelay between trigger pull and firing.
WEAPON_IS_CHARGE_BASEDbooleanWhether the weapon must be charged before firing.
WEAPON_IS_CHARGINGbooleanWhether the weapon is currently charging.
WEAPON_SHOT_CHARGE_AUTO_FIREbooleanFire on full charge vs. on trigger release.
WEAPON_CAN_RELOADbooleanWhether the current weapon can reload.
WEAPON_RELOAD_DELAY_MSnumberReload time in ms.
WEAPON_BUSY_COUNTnumberCount of actions making the weapon busy (reloading, jammed, …). A count, not a flag — values above 1 are normal when actions overlap.
LED_MUZZLE_FLASHbooleanWhether the muzzle-flash LED is on.

Reading NFC tags

Subscribe to NFC_TAG to react to tags: it holds the UID (hex) of the tag currently on the reader, and is set back to an empty string the moment the tag is removed. So a change to a non-empty value means "a tag appeared" and a change to empty means "removed".

NFC_DATA is set before NFC_TAG

When a tag appears, the device reads its first NDEF text or URI record and puts the payload in NFC_DATA — and it does so before updating NFC_TAG. Because events are delivered in order, by the time you receive the NFC_TAG change the matching NFC_DATA has already arrived. Read them together: trigger off NFC_TAG, then use the latest NFC_DATA.

NFC_DATA is not cleared on removal (it reflects the last tag read), and is empty if the tag had no readable NDEF text/URI record. Both NTAG/Ultralight and MIFARE Classic tags are supported.

Game states

The device's state machine drives what's happening in a game. Subscribe to the fsm event ({ ns: "fsm", prop: "state", value }) to follow transitions, or read the current value with { method: "get", ns: "fsm", prop: "state" }. The common gameplay states:

StateMeaning
HOMELobby / idle — looking for and counting nearby players.
GAME_LOBBYJoined a game lobby, waiting for the game to start.
IN_GAMEActively playing.
DEADEliminated, awaiting respawn (trigger-pull or respawn box).
RESPAWNINGRespawn countdown running — see COUNTDOWN_SECS.
GAME_OVERThis player is out of lives (player-specific).
GAME_ENDThe game has ended for everyone.