Skip to content

Type Definitions ​

Complete type reference for the Urban Sky SDK interfaces and types. Everything on this page mirrors the exported types in sdk/js/src/index.ts (Python equivalents live in sdk/py/src/urbansky_sdk/__init__.py).

Configuration ​

SDKConfig ​

Configuration object for initializing the SDK.

typescript
interface SDKConfig {
  apiToken: string // Required: your Urban Sky API token
  baseUrl?: string // Optional: API base URL (defaults to production)
  debug?: boolean // Optional: enable debug logging (default false)
}

Defaults:

typescript
const DEFAULT_CONFIG: Partial<SDKConfig> = {
  baseUrl: 'https://api.ops.atmosys.com',
  debug: false,
}

These three fields are the entire configuration surface — reconnection and heartbeat behavior is handled internally by the Centrifugo client and is not configurable.

Core Types ​

BalloonUpdate ​

Main data structure for balloon telemetry updates.

typescript
interface BalloonUpdate {
  balloonId: string // Unique balloon identifier
  missionId: string // Associated mission ID
  devices: DeviceLocation[] // Array of device telemetry data
}

UnassignedDevicesUpdate ​

Real-time telemetry for devices not assigned to any mission.

typescript
interface UnassignedDevicesUpdate {
  devices: DeviceLocation[]
}

DeviceLocation ​

Individual device telemetry within a balloon or unassigned-devices update.

typescript
interface DeviceLocation {
  deviceId: string // Unique device identifier (MAC address)
  deviceType: string // Raw device type string as reported by the device (e.g. "PLD", "APX", "BLS")
  lat: number // Latitude (decimal degrees)
  lng: number // Longitude (decimal degrees)
  altitude?: number // Altitude in meters
  timestamp: string // ISO 8601 timestamp
  batteryInfo?: BatteryInfo | null
  environmental?: EnvironmentalInfo | null
  status?: StatusInfo | null
  motion?: MotionInfo | null
  internal?: InternalTelemetry // Extended fields (internal_testing orgs only)
}

BatteryInfo / EnvironmentalInfo / StatusInfo / MotionInfo ​

typescript
interface BatteryInfo {
  soc?: number | null // State of charge (%)
  voltage?: number | null // Battery voltage (V)
  temperature?: number | null // Battery temperature (°C)
  power?: number | null // Battery power (W)
}

interface EnvironmentalInfo {
  airTemperature?: number | null // Air temperature (°C)
  pressure?: number | null // Atmospheric pressure (mBar)
  humidity?: number | null // Relative humidity (%)
}

interface StatusInfo {
  systemStatus?: string | number | null
  flightStage?: string | null // UPPERCASE stage, see FlightStage below
  gpsFixStatus?: number | null
  connectionStrength?: number | null // RSSI or signal strength
}

interface MotionInfo {
  ascentRate?: number | null
  groundSpeed?: number | null
  heading?: number | null
}

InternalTelemetry ​

Extended telemetry fields available only to organizations with internal_testing enabled. See Internal Telemetry Guide for details.

typescript
interface InternalTelemetry {
  ack?: boolean // Device acknowledged last command
  batteryVoltage?: number // Battery voltage (V)
  batterySoc?: number // Battery state of charge (%)
  batteryTemp?: number // Battery temperature (°C)
  tempBoard?: number // Board temperature (°C)
  airTemp?: number // External air temperature (°C)
  batteryHeating?: boolean // Battery heater active
  firmwareVersion?: string // Running firmware version
  hardwareVersion?: string // Hardware version
  flightStage?: string // PREFLIGHT | ASCENT | FLOAT | DESCENT | GROUNDED
  geofenceActive?: boolean // Geofence currently active
  geofenceBroken?: boolean // Geofence boundary violated
  gpsFixStatus?: number // GPS fix type
  gpsSatellites?: number // Satellites in view
  ascentRate?: number // Ascent rate (m/s)
  uptime?: number // System uptime (ms)
  massDropped?: number // Ballast dropped (g, ballaster only)
  dispenserIsDropping?: boolean // Dispenser active (ballaster only)
  systemStatusFlag?: boolean // system_status flag (unpacked from bitmask)
  gpsFixFlag?: boolean // gps_fix_status flag (unpacked from bitmask)
}

FlightStage values ​

StatusInfo.flightStage is typed as string | null — the SDK does not export a FlightStage type or a FLIGHT_STAGES constants object. On the wire it is always one of these UPPERCASE values:

'PREFLIGHT' | 'ASCENT' | 'FLOAT' | 'DESCENT' | 'GROUNDED'

Compare flightStage against these string values directly; there is no exported type or constants object to import.

ConnectionState ​

Represents the current connection state.

typescript
interface ConnectionState {
  state: 'connected' | 'connecting' | 'disconnected' | 'failed'
  reason?: string // Error reason if state is "failed"
}

SDKTokenResponse ​

Response from the /sdk/token exchange performed during init().

typescript
interface SDKTokenResponse {
  token: string // Short-lived connection token (grants no channel access on its own)
  subscriptionToken?: string // Authorizes subscription to `channelName` only
  orgId: string // Your organization ID
  sdkVersion: string // Server-selected SDK version
  channelName?: string // Org-scoped channel the SDK subscribes to
  websocketUrl?: string // Public Centrifugo WebSocket URL
}

The SDK consumes all of these automatically — you never pass them yourself. In particular, websocketUrl is how the SDK resolves the realtime host, so there is no need to construct or override a WebSocket URL. baseUrl in SDKConfig is the REST API only.

Event Types ​

SDKEventType ​

Available event types you can listen for.

typescript
type SDKEventType =
  | 'balloon:update' // Balloon telemetry updates (mission-assigned devices)
  | 'unassigned:devices' // Unassigned device updates (devices not assigned to missions)
  | 'connected' // Successfully connected
  | 'disconnected' // Disconnected from service
  | 'connecting' // Attempting to connect
  | 'failed' // Connection failed
  | 'error' // General error occurred

SDKEventHandler ​

Generic event handler function type.

typescript
type SDKEventHandler<T = unknown> = (data: T) => void

Error Types ​

All request failures throw a subclass of SdkError (note the casing — there is no SDKError class and no string code field).

typescript
class ValidationError extends Error {} // Client-side input validation failed

class SdkError extends Error {
  statusCode?: number // HTTP status of the failed request, when available
  responseData?: string // Raw response body, when available
}

class SdkAuthenticationError extends SdkError {} // statusCode 401 (or 403 responses)
class SdkNotFoundError extends SdkError {} // statusCode 404
class SdkBadRequestError extends SdkError {} // statusCode 400
class SdkNetworkError extends SdkError {} // No response — responseData carries the underlying error message

Handling pattern:

typescript
import { SdkAuthenticationError, SdkNotFoundError, SdkError } from '@urbansky/sdk-js'

try {
  await sdk.listMissions()
} catch (err) {
  if (err instanceof SdkAuthenticationError) {
    // Refresh/rotate the API token
  } else if (err instanceof SdkNotFoundError) {
    // Resource does not exist
  } else if (err instanceof SdkError) {
    console.error(err.statusCode, err.responseData)
  }
}

Python Type Equivalents ​

The Python SDK (urbansky_sdk) mirrors these types as dataclasses with snake_case fields, and uses the same error class names:

python
from urbansky_sdk import (
    SDKConfig,          # api_token, base_url
    BalloonUpdate,      # balloon_id, mission_id, devices
    DeviceLocation,     # device_id, device_type, lat, lng, altitude, timestamp, ...
    ConnectionState,
    SDKEventType,
    ValidationError,
    SdkError,           # .status_code, .response_data
    SdkAuthenticationError,
    SdkNotFoundError,
    SdkBadRequestError,
    SdkNetworkError,
)

Payload telemetry types ​

PayloadTelemetry runs on a payload and sends logs and metrics to its Husky bus. See the JavaScript and Python references.

typescript
export const DEFAULT_BUS_URL = 'http://192.168.8.1:4318'
export const BUS_URL_ENV = 'USKY_BUS_INGEST_URL'

export type PayloadLogLevel = 'debug' | 'info' | 'warn' | 'error'
export type PayloadAttrValue = string | number | boolean

export interface PayloadTelemetryOptions {
  busUrl?: string // default: USKY_BUS_INGEST_URL, else DEFAULT_BUS_URL
  flushIntervalMs?: number // default 2000
  metricIntervalMs?: number // default 10000
  maxQueuedLines?: number // default 2000
  timeoutMs?: number // default 3000
  transport?: BusTransport
  start?: boolean // default true
}

export interface PayloadLogOptions {
  event?: string
  attrs?: Record<string, PayloadAttrValue>
}

/** The bus's answer to a logs or metrics request. */
export interface PayloadIngestResult {
  accepted: number
  dropped: number
  reasons?: Record<string, number> // rate, bus_rate, push_rate, undeclared, type, invalid, unwritable
}

/** Replaces the HTTP call, for tests. */
export type BusTransport = (
  method: 'GET' | 'POST',
  url: string,
  body: string | undefined,
  contentType: string | undefined,
  timeoutMs: number,
) => Promise<BusResponse>

export interface BusResponse {
  status: number
  headers: Record<string, string | string[] | undefined>
  body: string
}

In Python, urbansky_payload.py has PayloadTelemetry, PayloadLogHandler, DEFAULT_BUS_URL and BUS_URL_ENV. Log levels are the same strings. Attribute values are str, int, float or bool. last_result is a plain dict with the PayloadIngestResult keys.

Data Flow ​

Mission-Assigned Devices (Balloon Updates) ​

  1. Device sends telemetry data
  2. Data is assigned to a mission based on device assignment
  3. Data is batched by mission/balloon
  4. balloon:update events are emitted with all devices in the mission

Unassigned Devices ​

  1. Device sends telemetry data
  2. Device has no mission assignment
  3. Data is cached by organization
  4. unassigned:devices events are emitted with all unassigned devices in the organization

Usage Patterns ​

Handle Both Event Types ​

typescript
const sdk = await UrbanSkySDK.init({ apiToken: 'your-token' })

// Handle mission-assigned devices
sdk.on('balloon:update', (update: BalloonUpdate) => {
  console.log(`Mission ${update.missionId} has ${update.devices.length} devices`)
})

// Handle unassigned devices
sdk.on('unassigned:devices', (update: UnassignedDevicesUpdate) => {
  console.log(`${update.devices.length} unassigned devices detected`)
})

// Connection state handlers
sdk.on('connected', (state: ConnectionState) => {})
sdk.on('disconnected', (state: ConnectionState) => {})
sdk.on('failed', (state: ConnectionState) => {})

// Error handler
sdk.on('error', (error: { message: string; error?: string }) => {})

Related Documentation: