Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions open_wearable/.metadata
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,20 @@
# This file should be version controlled and should not be manually edited.

version:
revision: "3297454732841b1a5a25d9f35f1fd5d7a4479e12"
channel: "main"
revision: "f5a8537f90d143abd5bb2f658fa69c388da9677b"
channel: "stable"

project_type: app

# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: 3297454732841b1a5a25d9f35f1fd5d7a4479e12
base_revision: 3297454732841b1a5a25d9f35f1fd5d7a4479e12
create_revision: f5a8537f90d143abd5bb2f658fa69c388da9677b
base_revision: f5a8537f90d143abd5bb2f658fa69c388da9677b
- platform: ios
create_revision: 3297454732841b1a5a25d9f35f1fd5d7a4479e12
base_revision: 3297454732841b1a5a25d9f35f1fd5d7a4479e12
create_revision: f5a8537f90d143abd5bb2f658fa69c388da9677b
base_revision: f5a8537f90d143abd5bb2f658fa69c388da9677b

# User provided section

Expand Down
210 changes: 210 additions & 0 deletions open_wearable/docs/connectors/websocket-ipc-api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
# WebSocket IPC API

This document describes how to communicate with the OpenWearable WebSocket connector.

## Endpoint

Default endpoint:

- `ws://<device-ip>:8765/ws`

Notes:

- The app binds the websocket server on all IPv4 interfaces and advertises the current device IP for clients on the same network.
- Port and path are configurable in app settings.
- The API is JSON over WebSocket text frames.

## Message Envelopes

Request:

```json
{"id":1,"method":"ping","params":{}}
```

Success response:

```json
{"id":1,"result":{"ok":true}}
```

Error response:

```json
{
"id": 1,
"error": {
"message": "Unknown method: foo",
"type": "UnsupportedError",
"stack": "..."
}
}
```

## Server Events

On connect, the server sends:

```json
{
"event": "ready",
"methods": ["ping", "methods", "..."],
"endpoint": "ws://192.168.1.23:8765/ws"
}
```

`ready.endpoint` may be `null` when the app cannot determine a client-reachable
LAN IP address. The connector still runs in that case.

Other event messages:

- `scan`: broadcast when a device is discovered.
- `connecting`: broadcast when a connect attempt starts.
- `connected`: broadcast when a wearable is connected.
- `stream`: stream subscription data.
- `stream_error`: error for a stream subscription.
- `stream_done`: stream finished.

`stream` event format:

```json
{
"event": "stream",
"subscription_id": 1,
"stream": "sensor_values",
"device_id": "string",
"data": {}
}
```

## Top-Level Methods

| Method | Params | Result |
|---|---|---|
| `ping` | `{}` | `{"ok":true}` |
| `methods` | `{}` | `string[]` |
| `has_permissions` | `{}` | `bool` |
| `check_and_request_permissions` | `{}` | `bool` |
| `start_scan` | `{"check_and_request_permissions"?:bool}` | `{"started":true}` |
| `start_scan_async` | `{"check_and_request_permissions"?:bool}` | `{"started":true,"subscription_id":int,"stream":"scan","device_id":"scanner"}` |
| `get_discovered_devices` | `{}` | `DiscoveredDevice[]` |
| `connect` | `{"device_id":string,"connected_via_system"?:bool}` | `WearableSummary` |
| `connect_system_devices` | `{"ignored_device_ids"?:string[]}` | `WearableSummary[]` |
| `list_connected` | `{}` | `WearableSummary[]` |
| `disconnect` | `{"device_id":string}` | `{"disconnected":true}` |
| `subscribe` | `{"device_id":string,"stream":string,"args"?:object}` | `{"subscription_id":int,"stream":string,"device_id":string}` |
| `unsubscribe` | `{"subscription_id":int}` | `{"subscription_id":int,"cancelled":bool}` |
| `invoke_action` | `{"device_id":string,"action":string,"args"?:object}` | depends on action |

## Action Commands (`invoke_action`)

Current actions:

- `disconnect` (no `args`)
- `synchronize_time`
- `list_sensors`
- `list_sensor_configurations`
- `set_sensor_configuration` with args:
- `{"configuration_name":string,"value_key":string}`

Examples:

```json
{"id":10,"method":"invoke_action","params":{"device_id":"abc","action":"synchronize_time"}}
```

```json
{"id":11,"method":"invoke_action","params":{"device_id":"abc","action":"set_sensor_configuration","args":{"configuration_name":"Accelerometer","value_key":"100Hz"}}}
```

## Subscribe Streams

Supported values for `subscribe.params.stream`:

- `sensor_values` (requires one of below in `args`)
- `{"sensor_id":string}` (recommended)
- `{"sensor_index":int}`
- `{"sensor_name":string}`
- `sensor_configuration`
- `button_events`
- `battery_percentage`
- `battery_power_status`
- `battery_health_status`
- `battery_energy_status`

Note:

- `scan` is not a direct `subscribe` stream.
- Use `start_scan_async` to receive scan data via `stream` events.

## Data Shapes

### DiscoveredDevice

```json
{
"id": "string",
"name": "string",
"service_uuids": ["string"],
"manufacturer_data": [1, 2, 3],
"rssi": -56
}
```

### WearableSummary

```json
{
"device_id": "string",
"name": "string",
"type": "OpenEarableV2",
"capabilities": ["SensorManager", "SensorConfigurationManager"]
}
```

### `list_sensors` item

```json
{
"sensor_id": "accelerometer_0",
"sensor_index": 0,
"name": "Accelerometer",
"chart_title": "Accelerometer",
"short_chart_title": "ACC",
"axis_names": ["x", "y", "z"],
"axis_units": ["m/s²", "m/s²", "m/s²"],
"timestamp_exponent": -9
}
```

### `list_sensor_configurations` item

```json
{
"name": "Accelerometer",
"unit": "Hz",
"values": [
{
"key": "100Hz",
"frequency_hz": 100,
"options": ["streamSensorConfigOption"]
}
],
"off_value": "off"
}
```

## Suggested Workflows

### Scan and connect

1. Call `start_scan` or `start_scan_async`.
2. Use `get_discovered_devices` (or consume stream events from `start_scan_async`).
3. Call `connect` with selected `device_id`.

### Sensor streaming

1. `invoke_action` with `action="list_sensors"`.
2. Pick `sensor_id`.
3. `subscribe` with `stream="sensor_values"` and `args={"sensor_id":"..."}`.
4. `unsubscribe` when done.
2 changes: 2 additions & 0 deletions open_wearable/ios/Flutter/AppFrameworkInfo.plist
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,7 @@
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>13.0</string>
</dict>
</plist>
2 changes: 0 additions & 2 deletions open_wearable/ios/Flutter/Profile.xcconfig

This file was deleted.

2 changes: 1 addition & 1 deletion open_wearable/ios/Podfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Uncomment this line to define a global platform for your project
platform :ios, '13.0'
# platform :ios, '13.0'

# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
Expand Down
21 changes: 14 additions & 7 deletions open_wearable/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -48,18 +48,21 @@ PODS:
- SwiftProtobuf
- open_file_ios (1.0.3):
- Flutter
- path_provider_foundation (0.0.1):
- Flutter
- FlutterMacOS
- permission_handler_apple (9.3.0):
- Flutter
- SDWebImage (5.21.5):
- SDWebImage/Core (= 5.21.5)
- SDWebImage/Core (5.21.5)
- SDWebImage (5.21.6):
- SDWebImage/Core (= 5.21.6)
- SDWebImage/Core (5.21.6)
- share_plus (0.0.1):
- Flutter
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS
- SwiftCBOR (0.4.7)
- SwiftProtobuf (1.33.3)
- SwiftProtobuf (1.34.1)
- SwiftyGif (5.4.5)
- universal_ble (0.0.1):
- Flutter
Expand All @@ -75,6 +78,7 @@ DEPENDENCIES:
- flutter_archive (from `.symlinks/plugins/flutter_archive/ios`)
- mcumgr_flutter (from `.symlinks/plugins/mcumgr_flutter/ios`)
- open_file_ios (from `.symlinks/plugins/open_file_ios/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
- share_plus (from `.symlinks/plugins/share_plus/ios`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
Expand Down Expand Up @@ -105,6 +109,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/mcumgr_flutter/ios"
open_file_ios:
:path: ".symlinks/plugins/open_file_ios/ios"
path_provider_foundation:
:path: ".symlinks/plugins/path_provider_foundation/darwin"
permission_handler_apple:
:path: ".symlinks/plugins/permission_handler_apple/ios"
share_plus:
Expand All @@ -126,17 +132,18 @@ SPEC CHECKSUMS:
iOSMcuManagerLibrary: e9555825af11a61744fe369c12e1e66621061b58
mcumgr_flutter: 969e99cc15e9fe658242669ce1075bf4612aef8a
open_file_ios: 46184d802ee7959203f6392abcfa0dd49fdb5be0
path_provider_foundation: bb55f6dbba17d0dccd6737fe6f7f34fbd0376880
permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d
SDWebImage: e9c98383c7572d713c1a0d7dd2783b10599b9838
SDWebImage: 1bb6a1b84b6fe87b972a102bdc77dd589df33477
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb
SwiftCBOR: 465775bed0e8bac7bfb8160bcf7b95d7f75971e4
SwiftProtobuf: e1b437c8e31a4c5577b643249a0bb62ed4f02153
SwiftProtobuf: c901f00a3e125dc33cac9b16824da85682ee47da
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
universal_ble: ff19787898040d721109c6324472e5dd4bc86adc
url_launcher_ios: 7a95fa5b60cc718a708b8f2966718e93db0cef1b
ZIPFoundation: b8c29ea7ae353b309bc810586181fd073cb3312c

PODFILE CHECKSUM: 251cb053df7158f337c0712f2ab29f4e0fa474ce
PODFILE CHECKSUM: 3c63482e143d1b91d2d2560aee9fb04ecc74ac7e

COCOAPODS: 1.16.2
Loading