A Swift package for real-time WebSocket connectivity to Ambient Weather personal weather stations. Receive live weather observations directly in your iOS and macOS apps via the Ambient Weather Realtime API.
- Real-time WebSocket streaming — Connects to
rt2.ambientweather.netfor live weather data pushed to your app as it arrives - SwiftUI-ready —
ObservableObjectconformance with@Publishedproperties for seamless SwiftUI integration - Automatic reconnection — Handles disconnects gracefully with configurable retry intervals and heartbeat keep-alive
- Comprehensive data model — Decodes 100+ sensor data points covering temperature, humidity, wind, rain, lightning, soil, air quality, and more
- Built-in unit conversions — Temperature (F/C/K), pressure (inHg/mb/kPa/hPa), wind speed (MPH/KPH/Knots), rainfall (in/cm/mm)
- Sensor discovery — Automatically detects which sensors are active and groups them by category
- Connection status indicator — Drop-in SwiftUI view showing connection state (green/orange/red)
- Structured logging — Uses
OSLogfor organized, filterable debug output - Multi-station support — Subscribe to multiple weather stations with separate API keys
| Platform | Minimum Version |
|---|---|
| iOS | 16.0 |
| macOS | 15.0 |
| Swift | 6.1 |
Add AmbientWeather to your project via Xcode:
- Go to File > Add Package Dependencies...
- Enter the repository URL:
https://github.com/MikeManzo/AmbientWeatherSocket.git - Select the version rule and add the package
Or add it directly to your Package.swift:
dependencies: [
.package(url: "https://github.com/MikeManzo/AmbientWeatherSocket.git", from: "1.0.0")
]Then add the dependency to your target:
.target(
name: "YourApp",
dependencies: ["AmbientWeather"]
)You'll need an Application Key and one or more API Keys from the Ambient Weather Dashboard.
import AmbientWeather
// Create the WebSocket controller
let weather = AmbientWebSocket(applicationKey: "your-application-key")
// Connect to your station(s)
weather.connectStations(apiKeys: ["your-api-key"])import SwiftUI
import AmbientWeather
struct WeatherView: View {
@StateObject private var weather = AmbientWebSocket(applicationKey: "your-app-key")
var body: some View {
VStack {
HStack {
Text("Station Status")
weather.connectionIndicator
}
if let data = weather.weatherData {
Text("Station: \(data.info.name)")
Text("Temperature: \(data.observation.tempF ?? 0, specifier: "%.1f")°F")
Text("Humidity: \(data.observation.humidity ?? 0)%")
Text("Wind: \(data.observation.windSpeedMPH ?? 0, specifier: "%.1f") MPH \(data.observation.cardinalWindDirection ?? "")")
Text("Last Updated: \(data.observation.observationDateFormatted)")
} else {
ProgressView("Waiting for data...")
}
}
.onAppear {
weather.connectStations(apiKeys: ["your-api-key"])
}
}
}The top-level object received for each station update:
| Property | Type | Description |
|---|---|---|
observation |
AmbientLastData |
Latest sensor readings |
stationID |
String |
Station MAC address |
info |
AmbientStationInfo |
Station name, location, and coordinates |
availableSensors |
[String: Any] |
Dictionary of all sensors currently reporting |
Sensor data is organized into categories via the SensorCategory enum, each with an associated SF Symbol icon:
| Category | Icon | Example Sensors |
|---|---|---|
| Temperature | thermometer.high |
tempF, tempInF, feelsLike |
| Humidity & Dew Point | humidity |
humidity, dewPoint, humidityIn |
| Atmospheric Pressure | gauge |
baromAbsIn, baromRelIn |
| Wind | wind |
windSpeedMPH, windGustMPH, windDir |
| Rain/Precipitation | cloud.rain |
dailyRainIn, weeklyRainIn, yearlyRainIn |
| Solar & UV | sun.max |
solarRadiation, uv |
| Lightning | bolt |
lightningHour, lightningDistance |
| Soil Temperature | thermometer.and.liquid.waves |
soiltemp1f through soiltemp10f |
| Soil Moisture | water.waves |
soilhum1 through soilhum10 |
| Air Quality | air.purifier |
pm25, co2 |
| Leak Detection | water.waves.and.arrow.trianglehead.down |
leak1 through leak4 |
| Battery Status | battery.100percent.bolt |
battIn, battOut, battRain |
Built-in computed properties provide instant unit conversions:
let data = weather.weatherData?.observation
// Temperature
data?.tempC // Celsius
data?.tempK // Kelvin
// Wind
data?.windSpeedKPH // Kilometers per hour
data?.windSpeedKnots // Knots
data?.cardinalWindDirection // "N", "NNE", "NE", etc.
// Pressure
data?.baromRelMb // Millibars
data?.baromRelkPa // Kilopascals
data?.baromRelhPa // Hectopascals
// Rain
data?.dailyRainCm // Centimeters
data?.dailyRainMm // MillimetersKeep the WebSocket connection alive (default: 30 seconds):
weather.setHeartBeatInterval(60.0) // Ping every 60 secondsTime to wait before reconnecting after a disconnect (default: 2 seconds):
weather.setReconnectInterval(5.0) // Wait 5 seconds before reconnectingweather.disconnectStations()This package works with any Ambient Weather station that reports data through the Ambient Weather API, including:
- WS-5000 series
- WS-2902 series
- And other compatible stations
The data model follows the official Device Data Specs.
- Starscream (4.0.8+) — WebSocket client library
See LICENSE for details.