Skip to content

Basic Telemetry

Overview

The Urban Sky SDK provides access to real-time balloon telemetry data. This guide covers the fundamental telemetry data you'll receive and how to work with it.

Telemetry Data Structure

Balloon Update Event

When a balloon's position changes, you'll receive a balloon:update event with the following structure:

javascript
{
  balloonId: "BLN-2024-001",
  missionId: "MSN-2024-001", 
  devices: [
    {
      deviceId: "PLD-001",
      deviceType: "PLD",
      lat: 40.7128,
      lng: -74.0060,
      altitude: 15240,
      timestamp: "2024-01-15T10:30:00.000Z"
    }
  ]
}

Device Types

Each balloon typically carries multiple devices that report telemetry:

  • PLD - Payload device (main tracking device)
  • APX - Apex device (top of balloon)
  • BLS - Ballaster device (ballast control system)

Working with Telemetry Data

JavaScript Example

javascript
sdk.on('balloon:update', (update) => {
  console.log(`Balloon ${update.balloonId} - Mission ${update.missionId}`)
  
  update.devices.forEach(device => {
    console.log(`Device ${device.deviceId} (${device.deviceType}):`)
    console.log(`  Location: ${device.lat}, ${device.lng}`)
    console.log(`  Altitude: ${device.altitude}m`)
    console.log(`  Time: ${new Date(device.timestamp).toLocaleString()}`)
  })
})

Python Example

python
def handle_balloon_update(update):
    print(f"Balloon {update['balloon_id']} - Mission {update['mission_id']}")
    
    for device in update['devices']:
        print(f"Device {device['device_id']} ({device['device_type']}):")
        print(f"  Location: {device['lat']}, {device['lng']}")
        print(f"  Altitude: {device['altitude']}m")
        print(f"  Time: {device['timestamp']}")

sdk.on('balloon:update', handle_balloon_update)

Data Processing Examples

Tracking Latest Positions

Keep track of the most recent position for each device:

javascript
class BalloonTracker {
  constructor() {
    this.latestPositions = new Map()
  }
  
  handleUpdate(update) {
    update.devices.forEach(device => {
      const key = `${update.balloonId}-${device.deviceId}`
      this.latestPositions.set(key, {
        balloonId: update.balloonId,
        missionId: update.missionId,
        ...device
      })
    })
  }
  
  getLatestPosition(balloonId, deviceId) {
    return this.latestPositions.get(`${balloonId}-${deviceId}`)
  }
  
  getAllLatestPositions() {
    return Array.from(this.latestPositions.values())
  }
}

const tracker = new BalloonTracker()
sdk.on('balloon:update', (update) => tracker.handleUpdate(update))

Distance Calculations

Calculate distance between positions:

javascript
function calculateDistance(lat1, lng1, lat2, lng2) {
  const R = 6371e3 // Earth's radius in meters
  const φ1 = lat1 * Math.PI/180
  const φ2 = lat2 * Math.PI/180
  const Δφ = (lat2-lat1) * Math.PI/180
  const Δλ = (lng2-lng1) * Math.PI/180

  const a = Math.sin(Δφ/2) * Math.sin(Δφ/2) +
            Math.cos(φ1) * Math.cos(φ2) *
            Math.sin(Δλ/2) * Math.sin(Δλ/2)
  const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a))

  return R * c // Distance in meters
}

// Usage
sdk.on('balloon:update', (update) => {
  const payload = update.devices.find(d => d.deviceType === 'PLD')
  const apex = update.devices.find(d => d.deviceType === 'APX')
  
  if (payload && apex) {
    const distance = calculateDistance(
      payload.lat, payload.lng,
      apex.lat, apex.lng
    )
    console.log(`Distance between payload and apex: ${distance.toFixed(2)}m`)
  }
})

Data Logging

Log telemetry data to a file:

javascript
const fs = require('fs')

class TelemetryLogger {
  constructor(filename = 'telemetry.log') {
    this.filename = filename
  }
  
  log(update) {
    const timestamp = new Date().toISOString()
    const logEntry = {
      receivedAt: timestamp,
      ...update
    }
    
    fs.appendFileSync(this.filename, JSON.stringify(logEntry) + '\n')
  }
}

const logger = new TelemetryLogger()
sdk.on('balloon:update', (update) => logger.log(update))

Data Quality Considerations

Timestamp Handling

Always use the device timestamp for accurate positioning:

javascript
sdk.on('balloon:update', (update) => {
  update.devices.forEach(device => {
    const deviceTime = new Date(device.timestamp)
    const receivedTime = new Date()
    const delay = receivedTime - deviceTime
    
    console.log(`Device ${device.deviceId} data is ${delay}ms old`)
  })
})

Coordinate Validation

Validate coordinates before processing:

javascript
function isValidCoordinate(lat, lng) {
  return lat >= -90 && lat <= 90 && lng >= -180 && lng <= 180
}

sdk.on('balloon:update', (update) => {
  update.devices.forEach(device => {
    if (!isValidCoordinate(device.lat, device.lng)) {
      console.warn(`Invalid coordinates for device ${device.deviceId}`)
      return
    }
    
    // Process valid coordinates
    processLocation(device)
  })
})

Testing Your Telemetry Processing

Use the test endpoint to verify your telemetry processing:

javascript
// Send a test balloon update
const testResponse = await fetch('https://api.atmosys.com/sdk/test/balloon', {
  method: 'POST',
  headers: {
    'x-api-token': 'your-api-token',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({})
})

if (testResponse.ok) {
  console.log('Test message sent - check your telemetry processing')
}

Next Steps