Part 08 — Events and the Event CatalogLink to the section Part 08 — Events and the Event Catalog
On this page
Maturity: Draft · Profiles: S (mandatory set), C, N · Schema: univip.event.v0.2 (../schemas/event.schema.json)
8.1 ModelLink to the section 8.1 Model
An event is a discrete notification. Events are published on the session channel as type: "event" envelopes and are retrievable for a limited history via GET /events. Events are either stateless (something happened) or stateful (a condition became active and later cleared); stateful events carry state: ACTIVE | CLEARED and the same topic.
8.2 Envelope payloadLink to the section 8.2 Envelope payload
{
"schema": "univip.event.v0.2",
"event_id": "01J9ZC4B8X2V5N7P1Q3R6T9W0Y",
"device_id": "urn:univip:acme:SN12345",
"session_id": "flight-2026-10-15-1042",
"topic": "vehicle.battery.low",
"severity": "WARNING",
"state": "ACTIVE",
"timestamp": "2026-10-15T10:40:02.500Z",
"source": { "component": "AIRCRAFT" },
"data": { "battery_pct": 24, "threshold_pct": 25, "remaining_endurance_s": 310 },
"related": { "command_id": null, "lease_id": null }
}| Member | Required | Description |
|---|---|---|
event_id |
yes | Unique, RECOMMENDED ULID |
topic |
yes | Dotted lowercase; standard topics begin vehicle.; vendor topics use reverse-DNS (com.acme.…) |
severity |
yes | DEBUG, INFO, WARNING, ERROR, CRITICAL |
state |
stateful only | ACTIVE, CLEARED |
timestamp |
yes | Time of occurrence |
source.component |
yes | AIRCRAFT, PAYLOAD, DOCK, CONTROLLER, GATEWAY, ANALYTICS, UNIVIP |
source.payload_id |
if PAYLOAD/ANALYTICS | |
data |
yes (may be {}) |
Topic-specific object; standard topics define their members below |
related |
MAY | command_id, lease_id, media_id, stream_id |
8.3 Standard catalogLink to the section 8.3 Standard catalog
M = mandatory for Profile S devices that can detect the condition. A device that cannot detect a condition (for example a gateway with no battery access) MUST omit the topic from events.topics in capabilities. In particular, a gateway that reaches the vehicle only over the link whose loss it would report cannot tell link loss from the vehicle falling silent: it raises vehicle.telemetry.stale and does not advertise vehicle.link.lost unless another component (a dock or controller) reports the link state.
| Topic | Profile | Stateful | Default severity | data members |
|---|---|---|---|---|
vehicle.device.online |
S M | no | INFO | — |
vehicle.device.offline |
S M | no | WARNING | reason (VEHICLE_UNREACHABLE, GATEWAY_SHUTDOWN, POWER_OFF, MAINTENANCE, OTHER) |
vehicle.device.capabilities_changed |
S M | no | INFO | — |
vehicle.telemetry.stale |
S M | yes | WARNING | last_sample_at |
vehicle.operation.predeploy |
S | no | INFO | — (aerial: preflight checks begun) |
vehicle.operation.started |
S M | no | INFO | launch_position (a telemetry position object; aerial: take-off; underwater: dive/launch) |
vehicle.operation.ended |
S M | no | INFO | recovery_position (a telemetry position object), operation_time_s (aerial: landed; underwater: recovered) |
vehicle.operation.state_changed |
S M | no | INFO | from, to (vehicle_state enum) |
vehicle.operation.mode_changed |
S | no | INFO | from, to (vendor strings) |
vehicle.operation.emergency |
S M | yes | CRITICAL | kind (MOTOR_FAILURE, LOSS_OF_CONTROL, FORCED_LANDING, CRASH, OTHER), message |
vehicle.battery.low |
S M | yes | WARNING | battery_pct, threshold_pct, remaining_endurance_s |
vehicle.battery.critical |
S M | yes | CRITICAL | as above |
vehicle.link.degraded |
S M | yes | WARNING | signal_quality_pct, latency_ms |
vehicle.link.lost |
S M | yes | CRITICAL | last_contact_at, failsafe_action |
vehicle.positioning.degraded |
S | yes | WARNING | source, fix, satellites, hdop, horizontal_accuracy_m |
vehicle.health.fault |
S M | yes | per fault | code, message, component |
vehicle.geofence.warning |
N | yes | WARNING | distance_to_boundary_m |
vehicle.geofence.breach |
N | yes | CRITICAL | position, action |
vehicle.altitude.limit |
N (AIR) | yes | WARNING | altitude_agl_m, limit_agl_m |
vehicle.depth.limit |
N (UNDERWATER) | yes | WARNING | depth_m, limit_m |
vehicle.navigation.returning_home |
S | no | WARNING | reason (PILOT, CLIENT, LOW_BATTERY, LINK_LOST, GEOFENCE, LEAK, WEATHER, TRAFFIC, OBSTACLE, FAULT, OTHER) |
vehicle.navigation.hold |
N | no | INFO | reason |
vehicle.navigation.waypoint_reached |
N | no | INFO | mission_id, waypoint_index |
vehicle.navigation.mission_state |
N | no | INFO | mission_id, state (STARTED, PAUSED, RESUMED, COMPLETED, ABORTED) |
vehicle.control.lease_granted |
C/N | no | INFO | lease_id, scope, client_id, expires_at |
vehicle.control.lease_released |
C/N | no | INFO | lease_id, reason (RELEASED, EXPIRED, REVOKED, PREEMPTED) |
vehicle.control.pilot_override |
N M | yes | WARNING | lease_id |
vehicle.command.accepted |
C/N | no | DEBUG | command_id, type |
vehicle.command.rejected |
C/N M | no | WARNING | command_id, type, reason, message |
vehicle.command.completed |
C/N | no | INFO | command_id, type |
vehicle.command.failed |
C/N M | no | ERROR | command_id, type, reason, message |
vehicle.camera.recording.started |
S | no | INFO | payload_id, media_id |
vehicle.camera.recording.stopped |
S | no | INFO | payload_id, media_id, duration_s |
vehicle.camera.snapshot |
C | no | INFO | payload_id, media_id |
vehicle.camera.stream.started |
S | no | INFO | stream_id |
vehicle.camera.stream.stopped |
S | no | INFO | stream_id, reason (NO_VIEWERS, SHUTDOWN, SOURCE_ENDED, ERROR) |
vehicle.camera.mode_changed |
C | no | INFO | payload_id, from, to |
vehicle.analytics.object.detected |
optional | no | INFO | Part 12 target object |
vehicle.analytics.object.lost |
optional | no | INFO | target_id |
vehicle.dock.state_changed |
optional | no | INFO | from, to (CLOSED, OPENING, OPEN, CLOSING, CHARGING, FAULT) |
vehicle.dock.fault |
optional | yes | ERROR | code, message |
8.4 Ordering and deliveryLink to the section 8.4 Ordering and delivery
- Events are delivered in the order of occurrence per device.
event_idULIDs are time-sortable. - At-least-once delivery over the session channel. The device tracks, per configured endpoint, the last event it wrote to a session with that endpoint. After reconnection it MUST replay every event generated after that one, provided the disconnect lasted at most 15 minutes and produced at most 500 events; it MAY retain more. On the first session ever established with an endpoint nothing is replayed. Clients MUST deduplicate on
event_id. - A stateful condition is identified by its condition key: the topic plus
data.code(vehicle.health.fault,vehicle.dock.fault), elsedata.lease_id(vehicle.control.pilot_override), elsesource.payload_id, else the topic alone. ACLEAREDevent closes theACTIVEevent with the same condition key; at most one condition per key is active. - After every session establishment, the device MUST send each stateful event whose condition is still
ACTIVE, with its originalevent_id. A client that kept its state drops it as a duplicate; one that lost its state learns the condition.
8.5 Standard fault codesLink to the section 8.5 Standard fault codes
Devices SHOULD use these codes in health.faults[].code and vehicle.health.fault: IMU_CALIBRATION, COMPASS_INTERFERENCE, BAROMETER_FAULT, GNSS_SPOOFING_SUSPECTED, MOTOR_FAULT, ESC_FAULT, BATTERY_TEMPERATURE, BATTERY_CELL_IMBALANCE, GIMBAL_FAULT, CAMERA_FAULT, STORAGE_FULL, OBSTACLE_SENSOR_FAULT, RADIO_INTERFERENCE, FIRMWARE_MISMATCH, OTHER.
8.6 ONVIF topic mappingLink to the section 8.6 ONVIF topic mapping
Annex A maps standard topics to ONVIF topic namespace equivalents for gateways that also expose ONVIF events (for example vehicle.camera.recording.started ↔ tns1:RecordingConfig/RecordingJobConfiguration where sensible, vehicle.health.fault ↔ tns1:Device/HardwareFailure/...). Where no ONVIF equivalent exists, gateways MUST use the tns1:Device/Trigger/… or a vendor namespace and MUST NOT misreport as an unrelated ONVIF topic.
8.7 MQTT 5 alternativeLink to the section 8.7 MQTT 5 alternative
When the real-time plane uses MQTT 5:
| Content | Topic |
|---|---|
| Telemetry | univip/v1/{device_id}/telemetry |
| Events | univip/v1/{device_id}/events/{topic with . replaced by /} |
| Command status | univip/v1/{device_id}/commands/{command_id}/status |
| Signaling | univip/v1/{device_id}/signal/{stream_id} (both directions, with direction member) |
| Lease updates | univip/v1/{device_id}/leases/{lease_id} |
| Client → device commands | univip/v1/{device_id}/commands/submit |
Payloads are the same JSON envelopes as on the WebSocket channel. Telemetry uses QoS 0 with retained last sample; events and command status use QoS 1; vehicle.device.offline MUST be registered as the MQTT Will message. Topic aliases and user properties MAY be used; device_id MUST remain in the envelope regardless.