Commands
Commands are what you send when you want a telescope to do
something — slew the mount, fire an exposure, move a focuser,
acquire a manual control lease. They're published over the
/v1/ws/commands WebSocket as publish_command messages and
result events flow back as event_command_result.
You'll only successfully publish a command against a telescope you have permission for — typically because you hold a manual control lease on that telescope (or are operating as the telescope owner / authorized operator).
Command stream
To receive commands and command results, subscribe to the command
streams (CommandStreamName values: command, command_result):
{
"kind": "subscribe_commands",
"subscription_id": "<client-chosen id>",
"filter": {
"telescope_uid": "<telescope uid>"
}
}
To publish a command:
{
"kind": "publish_command",
"telescope_uid": "<telescope uid>",
"command_id": "<client-chosen uuid>",
"command": {
"command_type": "mount.point",
"target": { /* TargetPosition */ }
},
"origin": { /* Origin record */ }
}
The command_id is your correlation key — match it against
event_command_result to know when the command finishes.
Command catalog
The command_type field discriminates among the concrete command
classes. Today's commands:
Mount commands
| Command type | Payload | What it does |
|---|---|---|
mount.point |
target: TargetPosition |
Slew the mount to the target's current position and stop tracking |
mount.track |
target: TargetPosition, optional offset_pattern |
Slew to the target and continuously track it; optionally play an offset pattern (raster, daisy) |
mount.offset_relative |
delta_arcsec, axis |
Apply a relative offset in arcseconds |
Camera commands
| Command type | Payload | What it does |
|---|---|---|
camera.exposure.start |
duration_s, binning, optional filter_id |
Start an exposure with the specified duration and (optional) binning + filter |
Imager (optical-imaging instrument) commands
| Command type | Payload | What it does |
|---|---|---|
imager.autofocus |
filter_id, strategy |
Run an autofocus pass through the specified filter using the chosen strategy |
Filter wheel commands
| Command type | Payload | What it does |
|---|---|---|
filter_wheel.set_option |
filter_wheel_position_id |
Move the filter wheel to a specific slot |
Focuser commands
| Command type | Payload | What it does |
|---|---|---|
focuser.move_absolute |
position_um |
Move the focuser to an absolute position (microns) |
focuser.move_relative |
delta_um |
Move the focuser by a relative offset (microns) |
Two additional focus.* aliases exist
(focus.move_absolute / focus.move_relative) for higher-level
focus operations; check the schemas if you need them.
Rotator commands
| Command type | Payload | What it does |
|---|---|---|
rotator.move_absolute |
angle_deg |
Move the instrument rotator to an absolute angle |
rotator.move_relative |
delta_deg |
Move by a relative offset |
Manual control lease commands
| Command type | Payload | What it does |
|---|---|---|
manual_control_lease.acquire |
duration_s, optional purpose |
Request a manual control lease — pauses automated task execution and gives the caller manual command rights |
manual_control_lease.renew |
lease_id, duration_s |
Extend an existing lease |
manual_control_lease.release |
lease_id |
Release the lease, returning the telescope to automated operation |
System commands
| Command type | Payload | What it does |
|---|---|---|
system.abort_manual_control |
lease_id |
Owner-side force-revoke of an active lease (raises an immediate abort that SkyNode handles by releasing) |
Command results
When SkyNode finishes a command, it publishes a result that arrives
as an event_command_result with the same command_id:
{
"kind": "event_command_result",
"subscription_id": "<your-subscription-id>",
"result": {
"command_id": "<the published command's id>",
"status": "ok | error | canceled",
"data": { /* per-command-type result data */ },
"error": { /* present when status=error */ }
}
}
The data shape is command-specific — mount.point returns the
final commanded position; camera.exposure.start returns the
exposure metadata; etc.
Canceling
Publish a cancel_command referencing the command_id you want
canceled:
{
"kind": "cancel_command",
"command_id": "<the original command id>"
}
Cancellation is a request; SkyNode decides whether the command can
cleanly cancel and reports back through event_command_result
with status: canceled once it's actually stopped.
Permissions and auth
Publishing commands requires both:
- An access token with the appropriate scopes.
- Standing authority on the target telescope — typically through an active manual control lease, or as an authorized operator.
If your token doesn't carry sufficient authority, the publish call
returns an error message with code forbidden. The fix is
usually to acquire a lease first (and to confirm the telescope's
access grants reach your account).
Patterns
Manual slew-and-expose sequence
- Subscribe to
command_resultfiltered to your telescope. - Publish
manual_control_lease.acquire. - On success, publish
mount.trackwith the target. - Wait for the mount snapshot stream (on
/v1/ws/stream) to confirm the mount is tracking. - Publish
camera.exposure.start. - Wait for the corresponding
event_command_result. - Publish
manual_control_lease.release.
Autofocus sweep
- Acquire a lease.
- Publish
imager.autofocuswith the desired filter and strategy. - Watch device snapshots for the focuser position moving.
- The command result arrives when the sweep completes.
- Release the lease.
Reference
Command schemas are at
packages/py/skynet-sdk/skynet_sdk/schemas/ws_protocol.py
under CommandPayload and the per-command subclasses
(MountPointCommand, MountTrackCommand, CameraExposureStartCommand,
…). Use these typed envelopes rather than hand-rolling JSON.