Skip to content

Tracking & Rotor API

The Tracking & Rotor API provides full control over antenna rotors through the Hamlib rotctld TCP protocol. You can configure multiple rotors, point them at celestial objects, run continuous tracking sessions, and perform automated sky scans with RSSI measurement.

GET /api/rotors
[
{
"id": 1,
"name": "AZ-EL Main",
"rotor_type": "azel",
"host": "127.0.0.1",
"port": 4533,
"min_elevation": 5.0,
"park_az": 0.0,
"park_el": 0.0
}
]

Register a new rotor configuration.

POST /api/rotors
{
"name": "AZ-EL Main",
"rotor_type": "azel",
"host": "127.0.0.1",
"port": 4533,
"min_elevation": 5.0,
"park_az": 0.0,
"park_el": 0.0
}
FieldTypeDefaultDescription
namestringUnique rotor name
rotor_typestringazelRotor type
hoststring127.0.0.1rotctld host address
portint4533rotctld TCP port
min_elevationfloat5.0Minimum elevation limit (degrees)
park_azfloat0.0Park azimuth (degrees)
park_elfloat0.0Park elevation (degrees)
StatusDescription
409Rotor with that name already exists

Update an existing rotor configuration. All fields are optional — only provided fields are updated.

PUT /api/rotors/{rotor_id}
StatusDescription
404Rotor not found
409Cannot update rotor while tracking is active

DELETE /api/rotors/{rotor_id}
StatusDescription
404Rotor not found
409Cannot delete rotor while tracking is active

Test the TCP connection to the rotor’s rotctld daemon.

GET /api/rotors/{rotor_id}/test
{
"connected": true,
"model": "Yaesu GS-232B"
}

If the connection fails:

{
"connected": false
}

Read the rotor’s current azimuth and elevation.

GET /api/rotors/{rotor_id}/position
{
"azimuth": 145.2,
"elevation": 32.8,
"rotor_name": "AZ-EL Main",
"timestamp": "2026-02-14T22:30:00Z"
}
StatusDescription
503Cannot connect to rotctld

Compute the current position of a target and slew the rotor to it.

POST /api/rotors/{rotor_id}/point
{
"target_type": "satellite",
"target_id": "25544"
}
{
"status": "ok",
"target": "ISS (ZARYA)",
"azimuth": 185.3,
"elevation": 42.1
}
StatusDescription
400Target is below the horizon
400Target is below minimum elevation limit
404Rotor not found

Immediately stop rotor movement. Also stops any active tracking session.

POST /api/rotors/{rotor_id}/stop
{
"status": "stopped",
"rotor": "AZ-EL Main"
}

Move the rotor to its configured park position. Stops any active tracking session first.

POST /api/rotors/{rotor_id}/park
{
"status": "parked",
"rotor": "AZ-EL Main",
"azimuth": 0.0,
"elevation": 0.0
}

Continuous tracking keeps the rotor pointed at a moving target (typically a satellite) by recomputing the position and sending updates to rotctld in a loop.

POST /api/rotors/{rotor_id}/track
{
"target_type": "satellite",
"target_id": "25544"
}
{
"id": 17,
"rotor_id": 1,
"target_type": "satellite",
"target_id": "25544",
"started_at": "2026-02-14T22:30:00Z",
"ended_at": null,
"notes": null
}
StatusDescription
409Rotor is already tracking a target

DELETE /api/rotors/{rotor_id}/track
{
"status": "stopped",
"rotor": "AZ-EL Main",
"session_id": 17
}

Check whether a rotor is actively tracking and what target it is following.

GET /api/rotors/{rotor_id}/tracking
{
"tracking": true,
"target_type": "satellite",
"target_id": "25544",
"session_id": 17
}
{
"tracking": false
}

List previous tracking sessions for a rotor.

GET /api/rotors/{rotor_id}/sessions
ParameterTypeDefaultDescription
limitint20Max results (max 100)
[
{
"id": 17,
"rotor_id": 1,
"target_type": "satellite",
"target_id": "25544",
"started_at": "2026-02-14T22:30:00Z",
"ended_at": "2026-02-14T22:42:00Z",
"notes": null
}
]

Real-time rotor position updates at 2 Hz.

ws://host:port/ws/rotor/{rotor_id}

Each message includes the current rotor state:

{
"rotor": "AZ-EL Main",
"azimuth": 145.2,
"elevation": 32.8,
"connected": true,
"tracking": true,
"target": "satellite",
"target_id": "25544",
"session_id": 17,
"timestamp": "2026-02-14T22:30:00.500Z"
}

When the rotor is disconnected:

{
"rotor": "AZ-EL Main",
"connected": false,
"tracking": false,
"timestamp": "2026-02-14T22:30:01Z"
}
const ws = new WebSocket("ws://localhost:8000/ws/rotor/1");
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log(`Az: ${data.azimuth}, El: ${data.elevation}`);
if (data.tracking) {
console.log(`Tracking: ${data.target} ${data.target_id}`);
}
};

Real-time target position updates at 1 Hz. Computes the current altitude, azimuth, RA/Dec, and distance for any trackable object.

ws://host:port/ws/tracking/{target_type}/{target_id}
ParameterTypeDescription
target_typestringsatellite, planet, star, dso, comet, sun, moon
target_idstringObject identifier
{
"name": "ISS (ZARYA)",
"target_type": "satellite",
"target_id": "25544",
"altitude_deg": 42.3,
"azimuth_deg": 185.7,
"distance_km": 420.5,
"ra_hours": 14.23,
"dec_deg": -12.45,
"is_above_horizon": true,
"timestamp": "2026-02-14T22:30:01Z"
}
const ws = new WebSocket("ws://localhost:8000/ws/tracking/satellite/25544");
ws.onmessage = (event) => {
const pos = JSON.parse(event.data);
if (pos.is_above_horizon) {
console.log(`${pos.name}: Alt ${pos.altitude_deg.toFixed(1)} Az ${pos.azimuth_deg.toFixed(1)}`);
}
};

The sky scan system performs automated az/el grid scans with RSSI (signal strength) measurement at each point. This is used for RF signal mapping and antenna pattern measurement.

POST /api/skyscan/start
{
"rotor_id": 1,
"az_start": 0.0,
"az_end": 360.0,
"el_start": 18.0,
"el_end": 65.0,
"step_deg": 2.0,
"rssi_iterations": 10
}
FieldTypeDefaultDescription
rotor_idintRotor to use for the scan
az_startfloat0.0Start azimuth (degrees)
az_endfloat360.0End azimuth (degrees)
el_startfloat18.0Start elevation (degrees)
el_endfloat65.0End elevation (degrees)
step_degfloat2.0Step size in degrees
rssi_iterationsint10Number of RSSI samples at each grid point
{
"id": 5,
"rotor_id": 1,
"status": "pending",
"az_start": 0.0,
"az_end": 360.0,
"el_start": 18.0,
"el_end": 65.0,
"step_deg": 2.0,
"rssi_iterations": 10,
"total_points": 4320,
"completed_points": 0,
"progress_pct": 0.0,
"started_at": null,
"finished_at": null,
"notes": null
}

GET /api/skyscan/sessions

GET /api/skyscan/{session_id}

Retrieve all collected data points for a completed (or in-progress) scan.

GET /api/skyscan/{session_id}/data
[
{
"azimuth": 0.0,
"elevation": 18.0,
"rssi_reads": 10,
"rssi_average": -85,
"rssi_current": -83,
"measured_at": "2026-02-14T22:35:00Z"
}
]

EndpointDescription
POST /api/skyscan/{session_id}/pausePause a running scan
POST /api/skyscan/{session_id}/resumeResume a paused scan
POST /api/skyscan/{session_id}/cancelCancel a running, paused, or pending scan

Real-time scan progress updates. The connection closes automatically when the scan finishes, is cancelled, or fails.

ws://host:port/ws/skyscan/{session_id}
{
"session_id": 5,
"status": "running",
"point": {
"azimuth": 45.0,
"elevation": 22.0,
"rssi_reads": 10,
"rssi_average": -82,
"rssi_current": -80,
"measured_at": "2026-02-14T22:36:00Z"
},
"progress_pct": 12.5,
"completed": 540,
"total": 4320
}

The status field progresses through: pending -> running -> completed | cancelled | failed.