Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.altnautica.com/llms.txt

Use this file to discover all available pages before exploring further.

The event bus is how the host pushes data to plugins and how plugins push data to each other. This page is the topic-by-topic reference. For envelope shape and RPC mechanics, see event hooks.

Topic taxonomy

Every event has a dotted topic name. The first segment is the namespace; the rest is the path inside it.
NamespaceOwnerPurpose
telemetry.*HostNormalized vehicle telemetry.
mavlink.*HostRaw MAVLink streams.
vehicle.*HostCanonical vehicle events (mode change, arm, disarm).
mission.*HostMission lifecycle.
fc.*HostFlight controller link state.
video.*HostVideo pipeline state and frames.
recording.*HostRecording lifecycle.
peripheral.*HostPeripheral hotplug.
lifecycle.*HostPlugin lifecycle ticks and state changes.
theme.*, config.*, i18n.*HostUI and config push.
plg.<plugin-id>.*PluginPlugin-published topics.
A plugin cannot publish into the host namespaces. Attempts return permission_denied. A plugin’s own publish topics are namespaced under plg.<id> automatically; the SDK prefixes them at publish time.

Telemetry topics

Subscribe with telemetry.subscribe, gated by telemetry.subscribe.<topic>:
TopicPayload
telemetry.battery{ pack_id, voltage_v, current_a, remaining_percent, cells_v[] }
telemetry.gps{ lat, lon, alt_m, hdop, fix_type, sats }
telemetry.attitude{ roll_deg, pitch_deg, yaw_deg, roll_rate_dps, pitch_rate_dps, yaw_rate_dps }
telemetry.position{ lat, lon, alt_msl_m, alt_agl_m, ground_speed_mps, climb_mps }
telemetry.heading{ heading_deg, source }
telemetry.wind{ direction_deg, speed_mps }
telemetry.rc{ rssi, link_quality, channels[] }
telemetry.system{ cpu_percent, mem_percent, temperature_c }
Subscribe once per plugin per topic. The host coalesces. Sample rate is the FC’s native rate, capped at 20 Hz on telemetry topics.

Vehicle topics

TopicPayloadCapability
vehicle.mode_changed{ from, to, source }event.subscribe
vehicle.armed{ armed: true, by: "rc" | "gcs" | "plugin" }event.subscribe
vehicle.disarmed{ armed: false, reason }event.subscribe
vehicle.failsafe{ kind, severity, message }event.subscribe
vehicle.statustext{ severity, text }event.subscribe
Vehicle events are at-least-once. The host coalesces duplicates within a 50 ms window.

Mission topics

TopicPayload
mission.uploaded{ mission_id, item_count, hash }
mission.started{ mission_id }
mission.waypoint_reached{ mission_id, seq }
mission.completed{ mission_id }
mission.aborted{ mission_id, reason }

Peripheral topics

TopicPayload
peripheral.attached{ kind, vid, pid, serial, port }
peripheral.detached{ kind, port }
Drivers subscribe to peripheral.attached to react to hotplug without polling.

Lifecycle topics

TopicPayload
lifecycle.tick{ uptime_ms } (1 Hz)
lifecycle.config_changedfull new config object
lifecycle.capabilities_changed{ added[], removed[] }

ACL via capability tokens

Subscribing requires event.subscribe. Subscribing to a topic in the telemetry.* namespace also requires the matching telemetry.subscribe.<topic> capability. The host re-resolves the required capability from the topic name, not from the plugin’s say-so. Publishing into plg.<id>.* requires event.publish. The host prefixes your published topic with plg.<id>. automatically.
# manifest declares: event.publish, event.subscribe, telemetry.subscribe.battery
async with ctx.events.subscribe("telemetry.battery") as stream:
    async for sample in stream:
        ...

# publishing
await ctx.events.publish("battery.low", {"pack_id": 1, "v": 14.4})
# host fans out as: plg.com.example.battery.battery.low

Delivery guarantees

Two grades:
GradeTopicsGuarantee
At-most-oncetelemetry.*, mavlink.*, video.*Drops on slow consumer. No retry.
At-least-oncevehicle.*, mission.*, peripheral.*, lifecycle.*, plg.*Buffered up to 256 messages per plugin per topic, dropped after that with a back_pressure warning.
Telemetry and raw streams are at-most-once because back-pressuring them would block the FC pipeline. If your plugin needs a complete record of telemetry, subscribe to recording.* events and read the recording from disk, do not try to log the live stream.

Back-pressure handling

Each plugin has a per-topic outbox of 256 messages. When the outbox fills:
  1. The host drops the oldest pending message.
  2. The host emits one back_pressure warning per topic per minute, included as an event into the plugin’s normal stream.
  3. The host increments a counter visible under ados plugin info <id>.
To avoid back-pressure, do not block in the event handler. Process events on a background task and let the handler return quickly:
async def on_start(self, ctx: Context) -> None:
    queue: asyncio.Queue[Sample] = asyncio.Queue(maxsize=64)
    asyncio.create_task(self._worker(queue))
    async with ctx.events.subscribe("telemetry.battery") as stream:
        async for sample in stream:
            try:
                queue.put_nowait(sample)
            except asyncio.QueueFull:
                pass  # drop locally; do not block the host

Plugin-to-plugin

Plugins publish into their own plg.<id>.* namespace. Other plugins subscribe to that namespace if they declare the matching permission and the operator approves the explicit grant.
# Subscriber's manifest
agent:
  permissions:
    - event.subscribe
    - event.subscribe.plg.com.example.battery.*
The wildcard form is a separate capability; the operator sees “plugin com.example.battery’s events” in the grid and approves it explicitly.

See also