4

The API over RF

You can build a simple API client with a radio and no internet connectivity. Four bot commands have a machine form: CQ, INFO, TIME and CHASERS. Each is the ordinary command with ! immediately following the keyword. The machine forms take the same arguments as their human-friendly counterparts. The replies to the machine forms are made of fields in a well-defined order instead of a human-readable sentence. Each command’s page documents its exact reply under “Machine form”. This page explains the common grammar.

Not all bot commands have a machine form. The commands that change something, a HOST, a CHASE, a QSL, answer with confirmations and hints, not data, so they have no machine form.

The bang

The machine form is a bot command with ! (sometimes called a bang) appended, i.e. CQ!, INFO!, INFO! K7ABC, TIME!, CHASERS!. As with every command, case does not matter. The bang doesn’t work on q-code synonyms, so QRT?! is not recognized. CQ ! (with a space before the bang) is an ordinary CQ command with trailing text, which the CQ command ignores.

I chose ! because APRS forbids | and ~ in message text, ? opens a directed query and is part of QRT?, - joins a callsign to its SSID so CQ-6 reads as a station, and / is a path and grid character. ! is visually distinctive and carries the “do it now” meaning for most programmers.

The reply grammar

  1. The reply begins with the command that initiated it. APRS gives you no correlation between your query and OTA’s reply. Messages may arrive out of order. The APRS ack only confirms receipt of your message, and its response arrives later as an unrelated message. Send CQ! and it answers CQ! ..., so your parser can dispatch on the first token and doesn’t have to try and figure out which command initiated this response.
  2. Fields are positional, separated by a single space, with no free text inside a record. The sixty-seven character limit of an APRS message does not make key=value pairs practical. Fields are not quoted and can’t contain spaces. The one exception is the description message: when the host described their op, INFO! sends a separate message of the command, the station, the literal DESC, and then the host’s text to the end of the message. DESC sits where a record has a grid or _ and a miss has NIL, so switch on the third token. Free text never appears inside a record.
  3. _ in a field is null. In json this would show up as null. Not every field can contain this value, but you should check for it before coercing a field value to a number.
  4. NIL means the record was not found: If you use the INFO! command to ask about a callsign that doesn’t have an op on the air, you’ll get NIL back.
  5. Number formats. Most numbers are bare integers. A time is whole minutes from now. A position is latitude then longitude in signed decimal degrees with four digits after the decimal point. A missing or unknown position is _ _, so the fields after it keep their positional places.
  6. New fields append, never insert, and your parser must ignore fields past the ones it knows. This is the RF adaptation of the HTTP API’s additive rule. We will only ever add to the end of a response. You should tolerate and accept responses with more fields than you expect.

The op record

CQ! and INFO! both transmit information about ops, and they share some fields. CQ! sends the first three fields for each op. INFO! sends all of them. A CQ! response may have multiple records, each of which is a prefix of an INFO! record. There is no record delimiter. Your parser consumes three fields per op. The order of the fields is the op object’s wire order and it is shown on each command’s page.

Paging

CQ! and CHASERS! can return a response that is more than one APRS message. Here’s how it works, with CQ! as the example:

CHASERS! pages the same way. CHASERS!, then n/N, then the total number of chasers waiting, then one station call per chaser, longest waiting first. Nobody waiting is CHASERS! 1/1 0.

No matter how many pages (aka messages) come back to you, it counts as one query against the command’s rate limit. The machine forms share the human forms’ limits and budgets throughout. A client cannot double its budget by alternating forms, and a client that trips an error condition, TIME! from the wrong station or a bare INFO! with no op, gets the same hint a human would.

Examples

A CQ! with five ops on the air, answered in two messages. The op with the least time left comes first, and WB4BOR-5 has no grid:

W1XYZ-5OTACQ!
OTAW1XYZ-5CQ! 1/2 5 K0TFU-1 CN87xo 12 K7ABC-6 DN40bs 45 WB4BOR-5 _ 60
OTAW1XYZ-5CQ! 2/2 5 NW5W-1 EM12ab 78 VE3XBI-9 FN03hr 90

INFO! about a station that is hosting, answered with the whole op record. The host described this op, so the description message comes first:

W1XYZ-5OTAINFO! K7ABC
OTAW1XYZ-5INFO! K7ABC-6 DESC lakeshore op, HT and a signal stick
OTAW1XYZ-5INFO! K7ABC-6 DN40bs 45 12 3 11 40.0542 -111.5250

An op with no description gets only the record. The description is cut to fit one message, and the two messages may arrive in either order.

INFO! about a station that is not hosting:

W1XYZ-5OTAINFO! K7III
OTAW1XYZ-5INFO! K7III NIL

TIME! from the station running the op. The reply is the minutes left, then the minutes to the two-hour cap:

K7ABC-6OTATIME!
OTAK7ABC-6TIME! 45 75

CHASERS! from the station running the op, with three chasers waiting on a QSL, the one who has waited longest first:

K7ABC-6OTACHASERS!
OTAK7ABC-6CHASERS! 1/1 3 W1XYZ-5 N0CALL-7 KJ4HQS-15