Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
3c30ad6
identify sensor streams by wearable and sensor to avoid collisions
DennisMoschina Feb 23, 2026
a010393
add websocket connector backend and ipc protocol server
DennisMoschina Feb 24, 2026
2ef36d1
wire connectors settings page into app navigation and startup
DennisMoschina Feb 24, 2026
9902950
use wearableConnector for connections in websocket to share connected…
DennisMoschina Feb 25, 2026
8308c01
feat: Implement command structure for wearable connector
DennisMoschina Feb 25, 2026
7a7ddfd
feat: Add AsyncScanCommand for asynchronous scanning and event streaming
DennisMoschina Feb 26, 2026
25bf879
feat: Add WebSocket IPC API documentation for OpenWearable connector
DennisMoschina Feb 26, 2026
29dcd2e
feat(connectors_page.dart): Update WebSocket IPC terminology and add …
DennisMoschina Mar 2, 2026
b92b289
feat: Implement device IP address resolution and integrate into conne…
DennisMoschina Mar 2, 2026
7ecb000
feat: Update iOS project settings and dependencies
DennisMoschina Mar 3, 2026
c8c5e97
feat: Update WebSocket IPC server to resolve device IP address and im…
DennisMoschina Mar 3, 2026
f96b47a
feat(connectors): migrate websocket audio playback to flutter_sound
DennisMoschina Mar 9, 2026
b69b81e
feat(connectors): add websocket audio commands with codec configuration
DennisMoschina Mar 9, 2026
d6375ed
docs(connectors): document websocket audio sources and codec options
DennisMoschina Mar 9, 2026
4fa2371
feat(connectors): switch websocket audio playback to audioplayers
DennisMoschina Mar 10, 2026
df61119
docs(connectors): remove websocket audio streaming API docs
DennisMoschina Mar 10, 2026
518bcd5
refactor(connectors): remove websocket URL audio playback
DennisMoschina Mar 10, 2026
200b503
feat(workflows): add GStreamer dependencies for Linux build
DennisMoschina Mar 10, 2026
87358e8
feat(settings): add keep app in foreground setting to disable automat…
DennisMoschina Mar 11, 2026
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
3 changes: 3 additions & 0 deletions .github/workflows/pr_build_all_platforms.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ jobs:
sudo apt-get install -y \
clang \
cmake \
libgstreamer1.0-dev \
libgstreamer-plugins-base1.0-dev \
gstreamer1.0-plugins-base \
libgtk-3-dev \
ninja-build \
pkg-config
Expand Down
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
251 changes: 251 additions & 0 deletions open_wearable/docs/connectors/websocket-ipc-api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
# 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}` |
| `store_sound` | `{"sound_id":string,"audio_base64":string,"codec"?:string,"sample_rate"?:int,"num_channels"?:int,"interleaved"?:bool,"buffer_size"?:int}` | `{"sound_id":string,"stored":true,"bytes":int,"config":object}` |
| `play_sound` | `{"sound_id":string,"volume"?:number,"codec"?:string,"sample_rate"?:int,"num_channels"?:int}` | `{"source":"sound_id","sound_id":string,"playing":true,"config":object}` |
| `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.

## Audio Playback Over WebSocket

The connector supports distinct preloaded sounds (store once, play many times).

### 1) Distinct Preloaded Sounds

Store sound bytes in memory:

```json
{
"id": 20,
"method": "store_sound",
"params": {
"sound_id": "beep_ok",
"audio_base64": "<base64-encoded-audio-bytes>"
}
}
```

Play a stored sound:

```json
{
"id": 21,
"method": "play_sound",
"params": {
"sound_id": "beep_ok",
"volume": 1.0
}
}
```

`play_sound` requires `sound_id`.

## 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.

### Distinct sound playback

1. `store_sound` with `sound_id` and `audio_base64`.
2. `play_sound` with the same `sound_id`.
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
Loading
Loading