SPOT Tools JSON File Spec
This document defines the JSON format used by
SPOT Tools to load/save radio
and channel state.
Audience: developers integrating tooling, converters, or automated
pipelines.
Format Overview
SPOT Tools stores two types of information: radio-wide settings and an array of channel objects. It will accept a file that has only a channels array. In that case defaults will be used for the radio-wide settings. Lists are stored in the radio-wide settings, so a more practical minimal file is a radio object with list names and a channel array.
On import/read, compatibility mapping is applied first so deprecated JSON forms and receiver-specific encodings are converted into the current field set. The resulting radio and channel data are then normalized once into SPOT Tools' canonical in-memory model before downstream code uses them.
Current exported schema:
schema_version: 10radio_model: "uv-k5-telemetry"
Canonical Top-Level Shape
{
"schema_version": 10,
"radio_model": "uv-k5-telemetry",
"radio": { "...": "see Radio section" },
"channel_count": 200,
"channels": [ { "...": "see Channel section" } ]
}
Notes:
-
channel_countis informational on import (not authoritative). -
schema_versionandradio_modelare currently not enforced by the parser.
Radio Object
The radio has one canonical sub-object, active_options, which carries the radio-wide settings.
Older files may also carry deprecated compatibility data such as
legacy_values. Those forms are still accepted on
import for now and are documented in Appendix B, but they are no
longer emitted when a file is saved.
radio.active_options (canonical)
{
"beep_control": true,
"bpm_control": true,
"battery_type": 0,
"scan": {
"active_list_mask": 1,
"list_names": ["L1", "...", "L16"],
"resume_mode": "stop",
"dwell_time_seconds": 5
},
"telemetry": {
"peak_time": 22
},
"receiver": {
"rf_gain": 12,
"tag_mode": "channel"
},
"display": {
"power_on_display_mode": "logo",
"backlight_time": 4
},
"boot": {
"line1": "SPOT",
"line2": "Telemetry RX"
},
"keys": {
"flashlight_enabled": true,
"arrow_orientation": "up_down"
},
"developer": {
"squelch_level": 0,
"pulse_threshold_dbm": -95,
"full_scale_dbm": -31,
"battery_calibration": 2300
}
}
radio.active_options Field Definitions
| Field | Type | Description |
|---|---|---|
beep_control |
boolean | Flag that enables or disables button/key beep feedback in the receiver UI. |
bpm_control |
boolean | Flag that enables or disables BPM display/processing behavior in telemetry operation. |
battery_type |
integer | Selector for the battery profile used by the firmware’s battery meter logic. |
scan.
|
integer |
Mask, effective visible range 0..65535 (& 0xffff
on read/write; each bit enables one visible scan
list. The low-order bit (0x0001) is list 1,
and the high-order visible bit (0x8000) is
list 16. A zero mask means the built-in
ALL channels list.
|
scan.
|
array |
Up to the first 16 entries are used. Each entry should be a string of at most 10 printable ASCII characters. Names will be normalized to
normalized to L<n> if missing or empty.
|
scan.
|
"stop" | "dwell" |
Controls whether scanning stays on a hit or continues after a dwell interval. |
scan.
|
integer |
Sanitized to the nearest of
1, 2, 3, 5, 10, 15, 20, 25, 30; used when
scan.resume_mode is "dwell".
|
telemetry.
|
integer |
Sanitized to the nearest of
5, 10, 20, 22, 24, 29, 39 (encoded values for
0.5, 1, 2, 3, 5, 10, 20 seconds); controls
how long the peak meter indicator is held.
|
receiver.
|
integer |
Clamped to 0..24; selects the manual
telemetry RF gain setting.
|
receiver.
|
"channel" | "tag" |
Controls whether navigation/search prefers channel order or tag-style naming. |
display.
|
"message" | "sound" |
"voltage" | "logo" |
"none"
|
Selects what the receiver shows at power-on. Import also
accepts "full_screen" and normalizes it to
"logo".
|
display.
|
integer |
SPOT UI backlight-time index, clamped to
0..7: 0=OFF,
1=5 sec, 2=10 sec,
3=20 sec, 4=1 min,
5=2 min, 6=4 min,
7=ON.
SPOT Tools maps this UI
index to the firmware’s stored timing value internally.
|
boot.
|
string |
Used as the first and second lines of the boot message
when power-on display mode is set to
"message". Truncated to 15 characters.
|
keys.
|
boolean | Determines whether the flashlight key is enabled. |
keys.
|
"up_down" | "left_right" |
Specifies the orientation of the arrow keys on the
physical receiver. Standard units use
up_down.
|
Channel Object
Each element of the channels array has this canonical
shape:
channels[] (canonical)
{
"index": 0,
"active": true,
"name": "664 R L",
"rx_frequency": 16840830,
"step_setting": 9,
"attributes": {
"band": 2,
"scanlists": [1, 2, 3]
}
}
channels[] Field Definitions
| Field | Type | Description | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
index |
integer | Zero-based channel slot index within the 200-channel receiver memory. | ||||||||||||||||||||
active |
boolean | Indicates whether this channel should be treated as an enabled, usable telemetry channel. | ||||||||||||||||||||
name |
string | Operator-visible channel label, usually used for tag number and/or descriptive text. Up to 10 printable ASCII characters. | ||||||||||||||||||||
rx_frequency |
number |
Given in 10's of Hz. For example, 15536720 is
155.36720 MHz. This is the same resolution as
is displayed by the firmware.
|
||||||||||||||||||||
step_settingoptional |
integer |
Numeric code to select the frequency step. If omitted or
invalid, the default telemetry step,
0.5 kHz (code 11), will be used. Available values are:
|
||||||||||||||||||||
attributes.
|
integer | Internal band classification used by the firmware for frequency validation and channel normalization. | ||||||||||||||||||||
attributes.optional |
array |
Indicates which lists this channel is a member of, expressed
as list numbers 1..16.
|
Deprecated legacy channel compatibility fields and import aliases are collected in Appendix B. These will be removed in a future release.
Normalization (Sanitization) Rules
Radio Object Normalization (Sanitization) Rules
After compatibility mapping and parsing/import, SPOT Tools sanitizes radio-wide settings once into its canonical in-memory radio model:
-
radio.active_options.battery_type: rounded and clamped to0..4 -
radio.active_options.scan.active_list_mask: normalized to the visible 16-bit range (& 0xffff) -
radio.active_options.scan.list_names: only the first 16 entries are used; each entry is reduced to printable ASCII, trimmed, truncated to 10 characters, and normalized toL<n>if the internalized result is empty -
radio.active_options.scan.resume_mode: normalized to"stop"or"dwell" -
radio.active_options.scan.dwell_time_seconds: sanitized to the nearest of1, 2, 3, 5, 10, 15, 20, 25, 30 -
radio.active_options.telemetry.peak_time: sanitized to the nearest of5, 10, 20, 22, 24, 29, 39(encoded values for0.5, 1, 2, 3, 5, 10, 20seconds) -
radio.active_options.receiver.squelch_level: rounded and clamped to0..9 -
radio.active_options.receiver.rf_gain: rounded and clamped to0..24 -
radio.active_options.receiver.tag_mode: normalized to"channel"or"tag" -
radio.active_options.display.power_on_display_mode: legacy import value"full_screen"is normalized to"logo" -
radio.active_options.display.backlight_time: rounded and clamped to the SPOT UI range0..7 -
radio.active_options.boot.line1andline2: truncated to 15 characters -
radio.active_options.keys.arrow_orientation: normalized to"up_down"or"left_right" -
radio.active_options.developer.pulse_threshold_dbm: rounded and clamped to-125..-60 -
radio.active_options.developer.full_scale_dbm: rounded and clamped to-100..-20 -
radio.active_options.developer.force_bandwidth: normalized to"dont_force","wide","narrow", or"narrower" -
radio.active_options.developer.battery_calibration: rounded and clamped to1500..3500
Important:
- Save and receiver-write paths emit this canonical radio state using JSON or receiver-specific encoding rules. Receiver writes still perform transport-specific encoding such as timing conversion and bit packing.
Channel Object Normalization (Sanitization) Rules
After compatibility mapping and parsing/import, SPOT Tools sanitizes channels once into its canonical in-memory channel model:
-
channels[].name: trim, printable ASCII only, max 10 chars -
channels[].attributes.scanlists: normalized to the currently visible 16-bit range (& 0xffff) internally before being re-emitted as list numbers -
channels[].step_setting: if omitted or unsupported, replaced with default telemetry step (0.5 kHz) -
channels[].legacy.bandwidth: forced to"narrow"internally -
channels[].active = trueentries are validated against telemetry constraints:-
channels[].attributes.bandmust be0..6 -
channels[].rx_frequencyrange must be:- min
14400000(144 MHz) - max exclusive
17400000(174 MHz)
- min
-
-
invalid
channels[].active = trueentries are coerced/inactivated per sanitizer logic
Important:
-
Save and write paths emit this canonical channel state. JSON
export re-emits visible scan-list memberships as
scanlists, while receiver writes still perform receiver-specific encoding.
Export Behavior (Canonicalization)
When SPOT Tools saves JSON, it emits:
schema_version: 10- canonical
radio.active_optionsonly -
channels with:
-
index,active,name,rx_frequency,step_setting attributes.band-
attributes.scanlists
-
-
radio.active_options.developeronly when one or more optional developer-backed values are actually present. It will not provide defaults for these values. They are either set explicitly or not at all.
Strictness and Unknown Fields
- Known fields are type-checked strictly.
- Missing optional fields fall back to defaults.
- Unknown fields are generally ignored by parser.
- Deprecated compatibility fields in older files are still accepted on import. See Appendix B.
Minimal Valid Input Example
{
"channels": [
{
"index": 0,
"active": true,
"name": "CH001",
"rx_frequency": 16840000,
"attributes": {
"band": 2,
"scanlists": [1]
}
}
]
}
Omitted radio fields are filled from defaults, and omitted
step_setting is normalized to the default telemetry
step.
Appendix A: Developer Radio Fields
This appendix documents the optional developer-facing fields
nested within radio.active_options.developer.
radio.active_options.developer (canonical)
{
"squelch_level": 0,
"pulse_threshold_dbm": -95,
"full_scale_dbm": -31,
"force_bandwidth": "narrower",
"battery_calibration": 2300
}
radio.active_options.developer Field Definitions
| Field | Type | Description |
|---|---|---|
squelch_level |
integer | For telemetry purposes, squelch should always be 0. It is hear only for developer experimentation. |
pulse_threshold_dbm |
integer | Developer-facing threshold used by telemetry pulse qualification logic. |
full_scale_dbm |
integer | Developer-facing full-scale reference for telemetry power/meter display. |
force_bandwidth |
"dont_force" | "wide" |
"narrow" | "narrower"
|
Forces the bandwidth setting for all channels to the selected value. Using "dont_force" respects the channel setting. |
battery_calibration |
integer | Developer-facing calibration value for battery reporting. |
Appendix B: Deprecated Import-Only Compatibility
These fields are still accepted on import for near-term compatibility, but current exports do not emit them. They are deprecated and will be removed.
Radio Legacy Fields
radio.legacy_values (deprecated import-only)
{
"tx_timeout_timer": 1,
"mic_sensitivity": 4,
"roger_mode": "off",
"repeater_tail_tone_elimination": 0,
"tx_vfo_index": 0,
"auto_keypad_lock": false,
"cross_band_rx_tx": "off",
"dual_watch": "off",
"vfo_open": true,
"raw": {}
}
radio.legacy_values Field Definitions
| Field | Type | Description |
|---|---|---|
tx_timeout_timer |
integer | Legacy transmit timeout setting retained only for compatibility and round-tripping. |
mic_sensitivity |
integer | Legacy microphone gain setting retained for compatibility with inherited layouts. |
roger_mode |
"off" | "roger" |
"mdc"
|
Legacy roger-beep/MDC transmit behavior setting. |
repeater_tail_tone_elimination |
integer | Legacy repeater-tail suppression field preserved for compatibility. |
tx_vfo_index |
integer | Legacy selected transmit VFO index from the source radio model. |
auto_keypad_lock |
boolean | Legacy keypad auto-lock preference. |
cross_band_rx_tx |
"off" | "chan_a" |
"chan_b"
|
Legacy cross-band receive/transmit mode selector. |
dual_watch |
"off" | "chan_a" |
"chan_b"
|
Legacy dual-watch mode selector. |
vfo_open |
boolean | Legacy flag indicating whether VFO mode was enabled/open. |
raw |
object | Opaque compatibility bucket for legacy or vendor-specific values not explicitly modeled elsewhere. |
Legacy radio import aliases
-
radio.active_options.scan.target_mode: accepted on import for compatibility and collapsed into the mask-only scan model. -
radio.active_options.scan.default_list: legacy alias accepted on import and mapped intoscan.active_list_mask. -
radio.active_options.keys.flashlight_key: legacy alias accepted on import and normalized intokeys.flashlight_enabled. -
radio.active_options.display.power_on_display_modewith value"full_screen": accepted on import and normalized to"logo". -
radio.legacy_values.beep_control,radio.legacy_values.bpm_control, andradio.legacy_values.battery_type: accepted as fallback sources when the canonicalactive_optionsfields are absent. -
radio.active_options.receiver.squelch_level: deprecated import-only alias for canonicalradio.active_options.developer.squelch_level. -
radio.active_options.meter_calibration: deprecated import-only compatibility object.
Channel Legacy Fields
channels[].legacy (deprecated import-only)
channels[].legacy Field Definitions
| Field | Type | Description |
|---|---|---|
legacy.
|
"wide" | "narrow" |
Legacy compatibility field accepted on import, but normalized to SPOT’s telemetry-safe bandwidth behavior. |
legacy.
|
integer |
Legacy fallback source for step_setting on
import.
|
channels[].attributes legacy scan-list import fields
(deprecated import-only)
channels[].attributes Field Definitions
| Field | Type | Description |
|---|---|---|
attributes.
|
0..65535 |
Legacy mask-based form accepted on import. |
attributes.attributes.
|
boolean | Legacy boolean scan-list membership fields accepted on import. |