# iOS (Swift)

The iOS RT SDK has two separate APIs: one for the **iOS companion app** (`TerraRT` class) and one for **watchOS** (`Terra` class). They communicate via WatchConnectivity.

## Connections

```swift
public enum Connections: String {
    case BLE        // Bluetooth Low Energy devices (heart rate monitors, etc.)
    case APPLE      // iPhone's built-in sensors
    case WATCH_OS   // Data from paired Apple Watch via WatchConnectivity
}
```

## DataTypes

```swift
public enum DataTypes: String {
    case HEART_RATE
    case ECG
    case STEPS
    case HRV
    case CALORIES
    case LOCATION
    case SPEED
    case DISTANCE
    case STEPS_CADENCE
    case FLOORS_CLIMBED
    case GYROSCOPE
    case ACCELERATION
    case CORE_TEMPERATURE
    case SKIN_TEMPERATURE
}
```

## Update

Data points delivered via streaming callbacks.

```swift
public struct Update: Codable {
    public var ts: String?      // ISO 8601 timestamp
    public var val: Double?     // Scalar value (e.g. heart rate BPM, step count)
    public var type: String?    // Data type identifier (e.g. "HEART_RATE")
    public var d: [Double]?     // Array for multi-axis data (e.g. [x, y, z] for accelerometer)
}
```

For scalar metrics (heart rate, steps, calories), the value is in `val`. For vector metrics (acceleration, gyroscope, location), the values are in `d`.

## Device

Represents a discovered BLE device.

```swift
public struct Device: Identifiable {
    public let deviceName: String   // Human-readable BLE device name
    public let deviceUUID: String   // CoreBluetooth peripheral UUID
    public var id: String { get }   // Returns deviceUUID (for SwiftUI Identifiable)
}
```

## ConnectionState

```swift
public enum ConnectionState: Int {
    case CONNECTING     // 0
    case CONNECTED      // 1
    case DISCONNECTED   // 2
    case INACTIVE       // 3
}
```

## TerraError

```swift
public enum TerraError: Error {
    case UnknownOpcode
    case FeatureNotSupported
    case DataTypeNotSupportedForDevice
    case DeviceNotConnected
    case UnknownDevice
    case WebsocketDisconnected
}
```

***

## iOS Functions (`TerraRT` class)

### Initialization

#### TerraRT

Creates and authenticates a `TerraRT` instance. **Makes a network call** to Terra's servers.

```swift
init(devId: String, referenceId: String?, completion: @escaping (Bool) -> Void)
```

* `devId` ➡ Your developer ID from the [Terra Dashboard](https://dashboard.tryterra.co).
* `referenceId` ➡ Optional user identifier in your system. Appears as `reference_id` in webhooks.
* `completion` ➡ `true` if initialization succeeded, `false` on failure.

### Connection Setup

#### initConnection

Authenticates the SDK user with Terra's backend. **Makes a network call.** The `token` should be generated server-side via the [Generate Authentication Token](https://docs.tryterra.co/reference/generate-authentication-token) endpoint.

```swift
func initConnection(token: String, completion: @escaping (Bool) -> Void = {_ in})
```

#### getUserid

Returns the Terra user ID, or `nil` if not yet initialized. Synchronous, no network call.

```swift
func getUserid() -> String?
```

#### disconnect

Disconnects from the given connection type.

```swift
func disconnect(type: Connections)
```

### Device Scanning

#### startBluetoothScan (with built-in UI)

Starts scanning and returns a SwiftUI `TerraBLEWidget` view for device selection. When `bluetoothLowEnergyFromCache` is `true`, attempts to reconnect to a previously cached device.

```swift
func startBluetoothScan(type: Connections,
                         bluetoothLowEnergyFromCache: Bool = false,
                         callback: @escaping (Bool) -> Void = {_ in}) -> TerraBLEWidget?
```

#### startBluetoothScan (with device callback)

Starts scanning and calls `deviceCallback` for each discovered device, giving you programmatic control over device selection.

```swift
func startBluetoothScan(type: Connections,
                         deviceCallback: @escaping (Device) -> Void)
```

#### stopBluetoothScan

Stops an active Bluetooth scan.

```swift
func stopBluetoothScan(type: Connections)
```

#### connectDevice

Connects to a specific `Device` returned from `startBluetoothScan(deviceCallback:)`.

```swift
func connectDevice(_ device: Device, _ connectionCallback: @escaping (Bool) -> Void)
```

#### getConnectedDevice

Returns the currently connected BLE device, or `nil`.

```swift
func getConnectedDevice() -> Device?
```

### Data Streaming

Three `startRealtime` overloads for different streaming modes:

#### startRealtime (server + local)

Streams data to **both** Terra's websocket server (via `token`) and a local `callback`.

```swift
func startRealtime(type: Connections,
                   dataType: Set<DataTypes>,
                   token: String,
                   callback: @escaping (Update) -> Void,
                   connectionCallback: @escaping (Bool) -> Void = {_ in})
```

#### startRealtime (server only)

Streams data to Terra's websocket server only. No local callback — data is not delivered to the app.

```swift
func startRealtime(type: Connections,
                   dataType: Set<DataTypes>,
                   token: String,
                   connectionCallback: @escaping (Bool) -> Void = {_ in})
```

#### startRealtime (local only)

Streams data to a local callback only. No server connection — data stays on the device.

```swift
func startRealtime(type: Connections,
                   dataType: Set<DataTypes>,
                   callback: @escaping (Update) -> Void)
```

**Parameters:**

* `type` ➡ The connection type (`.BLE`, `.APPLE`, `.WATCH_OS`).
* `dataType` ➡ Set of data types to stream.
* `token` ➡ Authentication token for the websocket connection (from `initConnection`).
* `callback` ➡ Called with each `Update` data point.
* `connectionCallback` ➡ Called when the websocket connection state changes.

#### stopRealtime

Stops streaming for a given connection type.

```swift
func stopRealtime(type: Connections)
```

### Websocket

#### setWebsocketListener

Registers a listener for websocket connection state changes.

```swift
func setWebsocketListener(_ listener: @escaping (Bool, Error?) -> Void)
```

* `Bool` indicates connected/disconnected, `Error?` provides failure details.

### iOS → WatchOS Functions

These functions control the Apple Watch companion app via WatchConnectivity.

{% hint style="info" %}
These require a watchOS app using the [watchOS functions](#watchos-functions) below.
{% endhint %}

#### connectWithWatchOS

Establishes a WatchConnectivity session with the paired Apple Watch.

```swift
func connectWithWatchOS() throws
```

Throws `TerraError.FeatureNotSupported` if WatchConnectivity is not available.

#### setWatchOSConnectionStateListener

Fires when the WatchConnectivity session state changes.

```swift
func setWatchOSConnectionStateListener(listener: @escaping (ConnectionState) -> Void)
```

#### setWatchStateChangeListeners

Registers listeners for watch pairing state changes.

```swift
func setWatchStateChangeListeners(isPairedListener: ((Bool) -> Void)?,
                                   isAppInstalledListener: ((Bool) -> Void)?,
                                   isComplicationEnabledListener: ((Bool) -> Void)?)
```

#### pauseWatchOSWorkout / resumeWatchOSWorkout / stopWatchOSWorkout

Controls a workout running on the watchOS companion.

```swift
func pauseWatchOSWorkout(completion: @escaping (Bool) -> Void)
func resumeWatchOSWorkout(completion: @escaping (Bool) -> Void)
func stopWatchOSWorkout(completion: @escaping (Bool) -> Void)
```

#### sendMessage / setMessageHandler

Send and receive arbitrary messages between iOS and watchOS.

```swift
func sendMessage(_ data: [String: Any])
func setMessageHandler(_ messageHandler: @escaping ([String: Any]) -> Void)
```

***

## WatchOS Functions (`Terra` class)

The watchOS `Terra` class runs on the Apple Watch. It manages workouts, sensor streaming, and communication with the iOS companion app.

### Initialization

```swift
public init() throws
```

No parameters. Throws if HealthKit is not available.

{% hint style="info" %}
All methods below are called on the `Terra` instance.
{% endhint %}

### ReadTypes

watchOS uses `ReadTypes` instead of `DataTypes`:

```swift
public enum ReadTypes: String {
    case STEPS
    case LOCATION
    case CALORIES
    case HEART_RATE
    case HEART_RATE_VARIABILITY
    case SPEED
    case DISTANCE
    case STEPS_CADENCE
    case FLOORS_CLIMBED
    case GYROSCOPE
    case ACCELERATION
}
```

### WorkoutTypes

82 workout types available — maps to HealthKit `HKWorkoutActivityType`. Common values: `RUNNING`, `WALKING`, `BIKING`, `SWIMMING_POOL`, `SWIMMING_OPEN_WATER`, `HIKING`, `YOGA`, `STRENGTH_TRAINING`, `HIGH_INTENSITY_INTERVAL_TRAINING`, etc.

### WorkoutStates

```swift
public enum WorkoutStates: Int {
    case PREPARING                    // 0
    case USER_STARTING                // 1
    case ACTIVE                       // 2
    case USER_PAUSING                 // 3
    case USER_PAUSED                  // 4
    case AUTO_PAUSING                 // 5
    case AUTO_PAUSED                  // 6
    case USER_RESUMING                // 7
    case AUTO_RESUMING                // 8
    case USER_ENDING                  // 9
    case USER_ENDED                   // 10
    case AUTO_ENDING                  // 11
    case AUTO_ENDED                   // 12
    case AUTO_ENDING_PERMISSION_LOST  // 13
    case AUTO_ENDED_PERMISSION_LOST   // 14
    case TERMINATING                  // 15
    case TERMINATED                   // 16
}
```

### Connection

#### connect

Establishes a WatchConnectivity session with the iOS companion app.

```swift
func connect()
```

#### sharingDataAuthorised

Returns whether HealthKit sharing authorization has been granted.

```swift
func sharingDataAuthorised() -> Bool
```

#### setWatchOSConnectionStateListener

```swift
func setWatchOSConnectionStateListener(listener: @escaping (ConnectionState) -> Void)
```

### Data Streaming

#### startStream

Starts streaming sensor data from the watch. Data is delivered via the update handler.

```swift
func startStream(forDataTypes dTypes: Set<ReadTypes>,
                 completion: @escaping (Bool, TerraWatchOSErrors?) -> Void)
```

#### stopStream

```swift
func stopStream()
```

#### setUpdateHandler

Registers a callback for incoming data updates.

```swift
func setUpdateHandler(_ updateHandler: @escaping (Update) -> Void)
```

### Workout Session Management

#### startExercise

Starts an HKWorkoutSession, enabling enhanced sensor access.

```swift
func startExercise(forType workoutType: WorkoutTypes,
                   completion: @escaping (Bool, TerraWatchOSErrors?) -> Void)
```

#### pauseExercise / resumeExercise

```swift
func pauseExercise()
func resumeExercise()
```

#### stopExercise

```swift
func stopExercise(completion: @escaping (Bool, TerraWatchOSErrors?) -> Void)
```

#### setWorkoutStateListener

Fires when the workout session state changes.

```swift
func setWorkoutStateListener(_ workoutStateListener: @escaping (WorkoutStates) -> Void)
```

### Messaging

```swift
func sendMessage(_ data: [String: Any])
func setMessageHandler(_ messageHandler: @escaping ([String: Any]) -> Void)
```
