Appearance
Internal Telemetry (Extended Fields)
Overview
Organizations with internal_testing enabled receive expanded device telemetry beyond the standard location fields. This is used by the manufacturing team for MRF (Manufactured Ready for Flight) validation and internal QA workflows.
Internal telemetry is a strict superset of the public SDK — all standard fields are always present, with additional fields nested under an internal property on each device.
Enabling Internal Telemetry
The internal_testing flag is set directly on the organization record in the database. There is no UI toggle — this is by design, mirroring the super_admin pattern.
sql
UPDATE organization SET internal_testing = true WHERE id = 'YOUR_ORG_ID';Once enabled, all SDK connections for that organization will automatically include internal telemetry fields. No SDK code changes or token regeneration required.
Data Structure
Balloon Update (with internal fields)
javascript
{
balloonId: "BLN-2024-001",
missionId: "MSN-2024-001",
devices: [
{
// Standard public fields (always present)
deviceId: "APX-001",
deviceType: "APX",
lat: 40.7128,
lng: -74.0060,
altitude: 15240,
timestamp: "2024-01-15T10:30:00.000Z",
motion: {
groundSpeed: 12.5,
heading: 90.0,
ascentRate: 2.3
},
// Internal fields (only for internal_testing orgs)
internal: {
ack: true,
batteryVoltage: 3.7,
batterySoc: 85,
batteryTemp: 22.5,
tempBoard: 25.0,
airTemp: -30.5,
batteryHeating: true,
firmwareVersion: "12.73.35",
hardwareVersion: "11.24.38",
flightStage: "FLOAT",
geofenceActive: true,
geofenceBroken: false,
gpsFixStatus: 3,
gpsSatellites: 12,
ascentRate: 2.3,
uptime: 3600000,
massDropped: 150,
dispenserIsDropping: false
}
}
]
}Field Reference
| Field | Type | Unit | Description |
|---|---|---|---|
ack | boolean | — | Device acknowledged the last command |
batteryVoltage | number | V | Battery voltage |
batterySoc | number | % | Battery state of charge |
batteryTemp | number | °C | Battery temperature |
tempBoard | number | °C | Board-level temperature |
airTemp | number | °C | External air temperature |
batteryHeating | boolean | — | Battery heater is active |
firmwareVersion | string | — | Running firmware version (e.g. "12.73.35") |
hardwareVersion | string | — | Hardware version (e.g. "11.24.38") |
flightStage | string | — | Current flight stage (see below) |
geofenceActive | boolean | — | Geofence is currently active |
geofenceBroken | boolean | — | Geofence boundary has been violated |
gpsFixStatus | number | — | GPS fix type (0=none, 2=2D, 3=3D) |
gpsSatellites | number | — | Satellites in view |
ascentRate | number | m/s | Vertical ascent rate |
uptime | number | ms | System uptime |
massDropped | number | g | Ballast mass dropped (ballaster devices only) |
dispenserIsDropping | boolean | — | Ballast dispenser actively dropping (ballaster only) |
Flight Stages
| Value | Description |
|---|---|
PREFLIGHT | Device powered on, pre-launch checks |
ASCENT | Balloon ascending |
FLOAT | At target altitude, floating |
DESCENT | Descending (valve open or terminated) |
GROUNDED | On the ground post-flight |
Usage Examples
JavaScript — MRF Validation
javascript
import { UrbanSkySDK } from '@urbansky/sdk'
const sdk = await UrbanSkySDK.init({
apiToken: 'your-internal-api-token',
baseUrl: 'https://api.ops.atmosys.com',
})
sdk.on('balloon:update', update => {
for (const device of update.devices) {
if (!device.internal) continue
// Verify ACK received
if (device.internal.ack) {
console.log(`✓ ${device.deviceId}: ACK received`)
}
// Check battery health
const bv = device.internal.batteryVoltage
if (bv !== undefined && bv < 3.3) {
console.warn(`⚠ ${device.deviceId}: Low battery ${bv}V`)
}
// Verify firmware version
if (device.internal.firmwareVersion) {
console.log(` FW: ${device.internal.firmwareVersion}`)
}
}
})Python — MRF Validation
python
from urbansky_sdk import UrbanSkySDK, SDKConfig
sdk = await UrbanSkySDK.init(SDKConfig(
api_token="your-internal-api-token",
base_url="https://api.ops.atmosys.com",
))
def handle_update(update):
for device in update.devices:
if not device.internal:
continue
# Verify ACK received
if device.internal.ack:
print(f"✓ {device.device_id}: ACK received")
# Check battery health
if device.internal.battery_voltage is not None:
if device.internal.battery_voltage < 3.3:
print(f"⚠ {device.device_id}: Low battery {device.internal.battery_voltage}V")
# Verify firmware version
if device.internal.firmware_version:
print(f" FW: {device.internal.firmware_version}")
sdk.on("balloon:update", handle_update)Important Notes
- Public SDK consumers are unaffected. The
internalfield is simply absent for non-internal orgs — no breaking changes. - All data flows through MC. Internal telemetry follows the full pipeline: Iridium → packet-manager → MC database → Centrifugal → SDK. This validates the entire system, not just raw device output.
- Field availability varies by device type. Not all devices report all fields. Ballaster-specific fields (
massDropped,dispenserIsDropping) only appear on BAL devices. Always check forundefined/Nonebefore using a field. - The
internal_testingflag is cached for 5 minutes on the server. After toggling the flag in the DB, allow up to 5 minutes for the change to take effect on active connections.