Skip to content

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:

  1. An access token with the appropriate scopes.
  2. 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

  1. Subscribe to command_result filtered to your telescope.
  2. Publish manual_control_lease.acquire.
  3. On success, publish mount.track with the target.
  4. Wait for the mount snapshot stream (on /v1/ws/stream) to confirm the mount is tracking.
  5. Publish camera.exposure.start.
  6. Wait for the corresponding event_command_result.
  7. Publish manual_control_lease.release.

Autofocus sweep

  1. Acquire a lease.
  2. Publish imager.autofocus with the desired filter and strategy.
  3. Watch device snapshots for the focuser position moving.
  4. The command result arrives when the sweep completes.
  5. 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.