@mentra/bluetooth-sdk 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/README.md +75 -19
  2. package/android/src/main/java/com/mentra/bluetoothsdk/BluetoothSdkModule.kt +13 -13
  3. package/android/src/main/java/com/mentra/bluetoothsdk/Bridge.kt +42 -18
  4. package/android/src/main/java/com/mentra/bluetoothsdk/DeviceManager.kt +19 -21
  5. package/android/src/main/java/com/mentra/bluetoothsdk/DeviceStore.kt +4 -4
  6. package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothModels.kt +118 -103
  7. package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothSdk.kt +110 -38
  8. package/android/src/main/java/com/mentra/bluetoothsdk/controllers/ControllerManager.kt +4 -4
  9. package/android/src/main/java/com/mentra/bluetoothsdk/controllers/R1.kt +2 -2
  10. package/android/src/main/java/com/mentra/bluetoothsdk/services/PhoneMic.kt +6 -6
  11. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G1.java +1 -1
  12. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G2.kt +3 -3
  13. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Mach1.java +1 -1
  14. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraLive.java +18 -18
  15. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraNex.kt +1 -1
  16. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/SGCManager.kt +4 -4
  17. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Simulated.kt +2 -2
  18. package/android/src/main/java/com/mentra/bluetoothsdk/utils/Constants.kt +6 -6
  19. package/app.plugin.js +3 -1
  20. package/build/BluetoothSdk.types.d.ts +126 -27
  21. package/build/BluetoothSdk.types.d.ts.map +1 -1
  22. package/build/BluetoothSdk.types.js.map +1 -1
  23. package/build/_internal.d.ts +12 -0
  24. package/build/_internal.d.ts.map +1 -0
  25. package/build/_internal.js +11 -0
  26. package/build/_internal.js.map +1 -0
  27. package/build/{BluetoothSdkModule.d.ts → _private/BluetoothSdkModule.d.ts} +19 -8
  28. package/build/_private/BluetoothSdkModule.d.ts.map +1 -0
  29. package/build/{BluetoothSdkModule.js → _private/BluetoothSdkModule.js} +41 -26
  30. package/build/_private/BluetoothSdkModule.js.map +1 -0
  31. package/build/index.d.ts +4 -2
  32. package/build/index.d.ts.map +1 -1
  33. package/build/index.js +3 -4
  34. package/build/index.js.map +1 -1
  35. package/build/react/index.d.ts +5 -0
  36. package/build/react/index.d.ts.map +1 -0
  37. package/build/react/index.js +5 -0
  38. package/build/react/index.js.map +1 -0
  39. package/build/react/useBluetoothEvent.d.ts +6 -0
  40. package/build/react/useBluetoothEvent.d.ts.map +1 -0
  41. package/build/react/useBluetoothEvent.js +21 -0
  42. package/build/react/useBluetoothEvent.js.map +1 -0
  43. package/build/react/useBluetoothScan.d.ts +22 -0
  44. package/build/react/useBluetoothScan.d.ts.map +1 -0
  45. package/build/react/useBluetoothScan.js +135 -0
  46. package/build/react/useBluetoothScan.js.map +1 -0
  47. package/build/react/useBluetoothStatus.d.ts +16 -0
  48. package/build/react/useBluetoothStatus.d.ts.map +1 -0
  49. package/build/react/useBluetoothStatus.js +137 -0
  50. package/build/react/useBluetoothStatus.js.map +1 -0
  51. package/build/react/useGlassesConnection.d.ts +29 -0
  52. package/build/react/useGlassesConnection.d.ts.map +1 -0
  53. package/build/react/useGlassesConnection.js +140 -0
  54. package/build/react/useGlassesConnection.js.map +1 -0
  55. package/ios/BluetoothSdkModule.swift +14 -9
  56. package/ios/Source/Bridge.swift +44 -12
  57. package/ios/Source/DeviceManager.swift +27 -26
  58. package/ios/Source/DeviceStore.swift +4 -4
  59. package/ios/Source/MentraBluetoothSDK.swift +250 -132
  60. package/ios/Source/controllers/ControllerManager.swift +5 -5
  61. package/ios/Source/controllers/R1.swift +3 -3
  62. package/ios/Source/services/PhoneMic.swift +5 -5
  63. package/ios/Source/sgcs/Frame.swift +1 -1
  64. package/ios/Source/sgcs/G1.swift +1 -1
  65. package/ios/Source/sgcs/G2.swift +3 -3
  66. package/ios/Source/sgcs/Mach1.swift +1 -1
  67. package/ios/Source/sgcs/MentraLive.swift +31 -33
  68. package/ios/Source/sgcs/MentraNex.swift +2 -2
  69. package/ios/Source/sgcs/SGCManager.swift +5 -5
  70. package/ios/Source/sgcs/Simulated.swift +3 -3
  71. package/ios/Source/utils/Constants.swift +6 -6
  72. package/ios/Source/utils/JSCExperiment.swift +8 -8
  73. package/ios/Source/utils/TarBz2Extractor.swift +2 -2
  74. package/package.json +19 -1
  75. package/src/BluetoothSdk.types.ts +186 -28
  76. package/src/_internal.ts +11 -0
  77. package/src/{BluetoothSdkModule.ts → _private/BluetoothSdkModule.ts} +71 -38
  78. package/src/index.ts +80 -4
  79. package/src/react/index.ts +22 -0
  80. package/src/react/useBluetoothEvent.ts +38 -0
  81. package/src/react/useBluetoothScan.ts +173 -0
  82. package/src/react/useBluetoothStatus.ts +180 -0
  83. package/src/react/useGlassesConnection.ts +194 -0
  84. package/build/BluetoothSdkModule.d.ts.map +0 -1
  85. package/build/BluetoothSdkModule.js.map +0 -1
@@ -0,0 +1,22 @@
1
+ export {
2
+ useBluetoothEvent,
3
+ type UseBluetoothEventOptions,
4
+ } from "./useBluetoothEvent"
5
+ export {
6
+ useBluetoothScan,
7
+ type BluetoothScanDedupe,
8
+ type BluetoothScanHookResult,
9
+ type UseBluetoothScanOptions,
10
+ } from "./useBluetoothScan"
11
+ export {
12
+ useBluetoothStatus,
13
+ type BluetoothStatusHookResult,
14
+ type UseBluetoothStatusOptions,
15
+ } from "./useBluetoothStatus"
16
+ export {
17
+ useGlassesConnection,
18
+ type DefaultDeviceStorage,
19
+ type GlassesConnectionAction,
20
+ type GlassesConnectionHookResult,
21
+ type UseGlassesConnectionOptions,
22
+ } from "./useGlassesConnection"
@@ -0,0 +1,38 @@
1
+ import {useEffect, useRef} from "react"
2
+
3
+ import BluetoothSdk from "../index"
4
+ import type {
5
+ BluetoothSdkEventListener,
6
+ BluetoothSdkEventName,
7
+ } from "../BluetoothSdk.types"
8
+
9
+ export type UseBluetoothEventOptions = {
10
+ enabled?: boolean
11
+ }
12
+
13
+ export function useBluetoothEvent<EventName extends BluetoothSdkEventName>(
14
+ eventName: EventName,
15
+ listener: BluetoothSdkEventListener<EventName>,
16
+ options: UseBluetoothEventOptions = {},
17
+ ): void {
18
+ const enabled = options.enabled ?? true
19
+ const listenerRef = useRef(listener)
20
+
21
+ useEffect(() => {
22
+ listenerRef.current = listener
23
+ }, [listener])
24
+
25
+ useEffect(() => {
26
+ if (!enabled) {
27
+ return undefined
28
+ }
29
+
30
+ const subscription = BluetoothSdk.addListener(eventName, (event) => {
31
+ listenerRef.current(event)
32
+ })
33
+
34
+ return () => {
35
+ subscription.remove()
36
+ }
37
+ }, [enabled, eventName])
38
+ }
@@ -0,0 +1,173 @@
1
+ import {useEffect, useRef, useState} from "react"
2
+
3
+ import BluetoothSdk, {DeviceModels} from "../index"
4
+ import type {Device, DeviceModel} from "../BluetoothSdk.types"
5
+
6
+ export type BluetoothScanDedupe = "id" | "name" | ((device: Device) => string)
7
+
8
+ export type UseBluetoothScanOptions = {
9
+ dedupe?: BluetoothScanDedupe
10
+ model?: DeviceModel
11
+ onError?: (error: unknown) => void
12
+ timeoutMs?: number
13
+ }
14
+
15
+ export type BluetoothScanHookResult = {
16
+ clearResults: () => void
17
+ devices: Device[]
18
+ error: unknown | null
19
+ model: DeviceModel
20
+ scanning: boolean
21
+ selectedDevice: Device | null
22
+ selectDevice: (device: Device | null) => void
23
+ setModel: (model: DeviceModel) => void
24
+ startScan: (model?: DeviceModel) => Promise<Device[]>
25
+ stopScan: () => Promise<void>
26
+ }
27
+
28
+ function dedupeKey(device: Device, dedupe: BluetoothScanDedupe): string {
29
+ if (typeof dedupe === "function") {
30
+ return dedupe(device)
31
+ }
32
+ if (dedupe === "name") {
33
+ return `${device.model}:${device.name}`
34
+ }
35
+ return device.id
36
+ }
37
+
38
+ function dedupeDevices(devices: Device[], dedupe: BluetoothScanDedupe): Device[] {
39
+ const seen = new Set<string>()
40
+ const nextDevices: Device[] = []
41
+
42
+ devices.forEach((device) => {
43
+ const key = dedupeKey(device, dedupe)
44
+ if (seen.has(key)) {
45
+ return
46
+ }
47
+ seen.add(key)
48
+ nextDevices.push(device)
49
+ })
50
+
51
+ return nextDevices
52
+ }
53
+
54
+ function hasDevice(devices: Device[], selectedDevice: Device | null, dedupe: BluetoothScanDedupe): boolean {
55
+ if (!selectedDevice) {
56
+ return true
57
+ }
58
+ const selectedKey = dedupeKey(selectedDevice, dedupe)
59
+ return devices.some((device) => dedupeKey(device, dedupe) === selectedKey)
60
+ }
61
+
62
+ export function useBluetoothScan(options: UseBluetoothScanOptions = {}): BluetoothScanHookResult {
63
+ const [devices, setDevices] = useState<Device[]>([])
64
+ const [error, setError] = useState<unknown | null>(null)
65
+ const [model, setModelState] = useState<DeviceModel>(options.model ?? DeviceModels.MentraLive)
66
+ const [scanning, setScanning] = useState(false)
67
+ const [selectedDevice, selectDevice] = useState<Device | null>(null)
68
+ const activeScanRef = useRef(0)
69
+ const dedupeRef = useRef<BluetoothScanDedupe>(options.dedupe ?? "id")
70
+ const onErrorRef = useRef(options.onError)
71
+ const scanningRef = useRef(false)
72
+ const timeoutMsRef = useRef(options.timeoutMs)
73
+
74
+ useEffect(() => {
75
+ dedupeRef.current = options.dedupe ?? "id"
76
+ onErrorRef.current = options.onError
77
+ timeoutMsRef.current = options.timeoutMs
78
+ }, [options.dedupe, options.onError, options.timeoutMs])
79
+
80
+ useEffect(() => {
81
+ scanningRef.current = scanning
82
+ }, [scanning])
83
+
84
+ useEffect(() => {
85
+ if (!hasDevice(devices, selectedDevice, dedupeRef.current)) {
86
+ selectDevice(null)
87
+ }
88
+ }, [devices, selectedDevice])
89
+
90
+ useEffect(() => {
91
+ return () => {
92
+ if (!scanningRef.current) {
93
+ return
94
+ }
95
+ activeScanRef.current += 1
96
+ void BluetoothSdk.stopScan().catch(() => undefined)
97
+ }
98
+ }, [])
99
+
100
+ function clearResults() {
101
+ setDevices([])
102
+ selectDevice(null)
103
+ }
104
+
105
+ function setModel(nextModel: DeviceModel) {
106
+ setModelState(nextModel)
107
+ clearResults()
108
+ }
109
+
110
+ async function startScan(nextModel?: DeviceModel): Promise<Device[]> {
111
+ const scanId = activeScanRef.current + 1
112
+ activeScanRef.current = scanId
113
+ const scanModel = nextModel ?? model
114
+ if (nextModel && nextModel !== model) {
115
+ setModelState(nextModel)
116
+ }
117
+
118
+ setError(null)
119
+ setScanning(true)
120
+ scanningRef.current = true
121
+ setDevices([])
122
+ selectDevice(null)
123
+
124
+ try {
125
+ const nextDevices = await BluetoothSdk.scan(scanModel, {
126
+ ...(timeoutMsRef.current == null ? {} : {timeoutMs: timeoutMsRef.current}),
127
+ onResults: (results) => {
128
+ if (activeScanRef.current !== scanId) {
129
+ return
130
+ }
131
+ setDevices(dedupeDevices(results, dedupeRef.current))
132
+ },
133
+ })
134
+ const finalDevices = dedupeDevices(nextDevices, dedupeRef.current)
135
+ if (activeScanRef.current === scanId) {
136
+ setDevices(finalDevices)
137
+ setError(null)
138
+ }
139
+ return finalDevices
140
+ } catch (nextError) {
141
+ if (activeScanRef.current === scanId) {
142
+ setError(nextError)
143
+ onErrorRef.current?.(nextError)
144
+ }
145
+ throw nextError
146
+ } finally {
147
+ if (activeScanRef.current === scanId) {
148
+ setScanning(false)
149
+ scanningRef.current = false
150
+ }
151
+ }
152
+ }
153
+
154
+ async function stopScan() {
155
+ activeScanRef.current += 1
156
+ setScanning(false)
157
+ scanningRef.current = false
158
+ await BluetoothSdk.stopScan()
159
+ }
160
+
161
+ return {
162
+ clearResults,
163
+ devices,
164
+ error,
165
+ model,
166
+ scanning,
167
+ selectedDevice,
168
+ selectDevice,
169
+ setModel,
170
+ startScan,
171
+ stopScan,
172
+ }
173
+ }
@@ -0,0 +1,180 @@
1
+ import {useEffect, useRef, useState} from "react"
2
+
3
+ import BluetoothSdk from "../index"
4
+ import {
5
+ createDisconnectedGlassesStatus,
6
+ isConnectedGlassesConnectionStatus,
7
+ isReadyGlassesConnectionStatus,
8
+ } from "../BluetoothSdk.types"
9
+ import type {
10
+ BatteryStatusEvent,
11
+ HotspotStatus,
12
+ HotspotStatusChangeEvent,
13
+ PublicBluetoothStatus,
14
+ PublicGlassesStatus,
15
+ WifiStatus,
16
+ WifiStatusChangeEvent,
17
+ } from "../BluetoothSdk.types"
18
+
19
+ export type UseBluetoothStatusOptions = {
20
+ enabled?: boolean
21
+ onError?: (error: unknown) => void
22
+ }
23
+
24
+ export type BluetoothStatusHookResult = {
25
+ bluetoothStatus: Partial<PublicBluetoothStatus>
26
+ connected: boolean
27
+ error: unknown | null
28
+ glassesStatus: Partial<PublicGlassesStatus>
29
+ loading: boolean
30
+ ready: boolean
31
+ refresh: () => Promise<void>
32
+ }
33
+
34
+ function wifiStatusFromEvent(event: WifiStatusChangeEvent): WifiStatus {
35
+ switch (event.state) {
36
+ case "connected":
37
+ return {state: "connected", ssid: event.ssid, localIp: event.localIp}
38
+ case "disconnected":
39
+ return {state: "disconnected"}
40
+ }
41
+ }
42
+
43
+ function hotspotStatusFromEvent(event: HotspotStatusChangeEvent): HotspotStatus {
44
+ if (event.state === "enabled") {
45
+ return {
46
+ state: "enabled",
47
+ ssid: event.ssid,
48
+ password: event.password,
49
+ localIp: event.localIp,
50
+ }
51
+ }
52
+ return {state: event.state}
53
+ }
54
+
55
+ function mergeGlassesStatus(
56
+ current: Partial<PublicGlassesStatus>,
57
+ changed: Partial<PublicGlassesStatus>,
58
+ ): Partial<PublicGlassesStatus> {
59
+ if (changed.connection?.state === "disconnected") {
60
+ return {...createDisconnectedGlassesStatus(), ...changed}
61
+ }
62
+ return {...current, ...changed}
63
+ }
64
+
65
+ export function useBluetoothStatus(options: UseBluetoothStatusOptions = {}): BluetoothStatusHookResult {
66
+ const enabled = options.enabled ?? true
67
+ const onErrorRef = useRef(options.onError)
68
+ const [bluetoothStatus, setBluetoothStatus] = useState<Partial<PublicBluetoothStatus>>({})
69
+ const [error, setError] = useState<unknown | null>(null)
70
+ const [glassesStatus, setGlassesStatus] = useState<Partial<PublicGlassesStatus>>(() =>
71
+ createDisconnectedGlassesStatus(),
72
+ )
73
+ const [loading, setLoading] = useState(enabled)
74
+
75
+ useEffect(() => {
76
+ onErrorRef.current = options.onError
77
+ }, [options.onError])
78
+
79
+ async function refresh() {
80
+ setLoading(true)
81
+ try {
82
+ const [nextGlassesStatus, nextBluetoothStatus] = await Promise.all([
83
+ BluetoothSdk.getGlassesStatus(),
84
+ BluetoothSdk.getBluetoothStatus(),
85
+ ])
86
+ setGlassesStatus(nextGlassesStatus)
87
+ setBluetoothStatus(nextBluetoothStatus)
88
+ setError(null)
89
+ } catch (nextError) {
90
+ setError(nextError)
91
+ onErrorRef.current?.(nextError)
92
+ } finally {
93
+ setLoading(false)
94
+ }
95
+ }
96
+
97
+ useEffect(() => {
98
+ if (!enabled) {
99
+ setLoading(false)
100
+ return undefined
101
+ }
102
+
103
+ let mounted = true
104
+
105
+ const loadInitialStatus = async () => {
106
+ setLoading(true)
107
+ try {
108
+ const [nextGlassesStatus, nextBluetoothStatus] = await Promise.all([
109
+ BluetoothSdk.getGlassesStatus(),
110
+ BluetoothSdk.getBluetoothStatus(),
111
+ ])
112
+ if (!mounted) {
113
+ return
114
+ }
115
+ setGlassesStatus(nextGlassesStatus)
116
+ setBluetoothStatus(nextBluetoothStatus)
117
+ setError(null)
118
+ } catch (nextError) {
119
+ if (!mounted) {
120
+ return
121
+ }
122
+ setError(nextError)
123
+ onErrorRef.current?.(nextError)
124
+ } finally {
125
+ if (mounted) {
126
+ setLoading(false)
127
+ }
128
+ }
129
+ }
130
+
131
+ void loadInitialStatus()
132
+
133
+ const removeGlasses = BluetoothSdk.onGlassesStatus((changed) => {
134
+ setGlassesStatus((current) => mergeGlassesStatus(current, changed))
135
+ })
136
+ const removeBluetooth = BluetoothSdk.onBluetoothStatus((changed) => {
137
+ setBluetoothStatus((current) => ({...current, ...changed}))
138
+ })
139
+ const batterySubscription = BluetoothSdk.addListener("battery_status", (event: BatteryStatusEvent) => {
140
+ setGlassesStatus((current) => ({
141
+ ...current,
142
+ batteryLevel: event.level,
143
+ charging: event.charging,
144
+ }))
145
+ })
146
+ const wifiSubscription = BluetoothSdk.addListener("wifi_status_change", (event) => {
147
+ setGlassesStatus((current) => ({...current, wifi: wifiStatusFromEvent(event)}))
148
+ })
149
+ const hotspotSubscription = BluetoothSdk.addListener("hotspot_status_change", (event) => {
150
+ setGlassesStatus((current) => ({...current, hotspot: hotspotStatusFromEvent(event)}))
151
+ })
152
+ const hotspotErrorSubscription = BluetoothSdk.addListener("hotspot_error", () => {
153
+ setGlassesStatus((current) => ({...current, hotspot: {state: "disabled"}}))
154
+ })
155
+
156
+ return () => {
157
+ mounted = false
158
+ removeGlasses()
159
+ removeBluetooth()
160
+ batterySubscription.remove()
161
+ wifiSubscription.remove()
162
+ hotspotSubscription.remove()
163
+ hotspotErrorSubscription.remove()
164
+ }
165
+ }, [enabled])
166
+
167
+ const connection = glassesStatus.connection
168
+ const connected = connection ? isConnectedGlassesConnectionStatus(connection) : false
169
+ const ready = connection ? isReadyGlassesConnectionStatus(connection) : false
170
+
171
+ return {
172
+ bluetoothStatus,
173
+ connected,
174
+ error,
175
+ glassesStatus,
176
+ loading,
177
+ ready,
178
+ refresh,
179
+ }
180
+ }
@@ -0,0 +1,194 @@
1
+ import {useEffect, useRef, useState} from "react"
2
+
3
+ import BluetoothSdk from "../index"
4
+ import type {ConnectOptions, Device, DeviceModel} from "../BluetoothSdk.types"
5
+
6
+ import {useBluetoothScan, type BluetoothScanHookResult} from "./useBluetoothScan"
7
+ import {useBluetoothStatus, type BluetoothStatusHookResult} from "./useBluetoothStatus"
8
+
9
+ export type DefaultDeviceStorage = {
10
+ load: () => Promise<Device | null>
11
+ save: (device: Device | null) => Promise<void>
12
+ }
13
+
14
+ export type GlassesConnectionAction =
15
+ | "idle"
16
+ | "scanning"
17
+ | "connecting"
18
+ | "disconnecting"
19
+ | "forgetting"
20
+
21
+ export type UseGlassesConnectionOptions = {
22
+ autoConnectDefault?: boolean
23
+ defaultDeviceStorage?: DefaultDeviceStorage
24
+ onError?: (error: unknown) => void
25
+ scanModel?: DeviceModel
26
+ scanTimeoutMs?: number
27
+ }
28
+
29
+ export type GlassesConnectionHookResult = BluetoothStatusHookResult & {
30
+ action: GlassesConnectionAction
31
+ busy: boolean
32
+ clearDefaultDevice: () => Promise<void>
33
+ connect: (device?: Device, options?: ConnectOptions) => Promise<void>
34
+ connectDefault: (options?: ConnectOptions) => Promise<void>
35
+ defaultDevice: Device | null
36
+ disconnect: () => Promise<void>
37
+ forget: () => Promise<void>
38
+ scan: BluetoothScanHookResult
39
+ setDefaultDevice: (device: Device | null) => Promise<void>
40
+ }
41
+
42
+ export function useGlassesConnection(
43
+ options: UseGlassesConnectionOptions = {},
44
+ ): GlassesConnectionHookResult {
45
+ const status = useBluetoothStatus({onError: options.onError})
46
+ const scan = useBluetoothScan({
47
+ model: options.scanModel,
48
+ onError: options.onError,
49
+ timeoutMs: options.scanTimeoutMs,
50
+ })
51
+ const [action, setAction] = useState<GlassesConnectionAction>("idle")
52
+ const [defaultDevice, setDefaultDeviceState] = useState<Device | null>(null)
53
+ const [operationError, setOperationError] = useState<unknown | null>(null)
54
+ const autoConnectAttemptedRef = useRef(false)
55
+ const defaultDeviceStorageRef = useRef(options.defaultDeviceStorage)
56
+ const onErrorRef = useRef(options.onError)
57
+
58
+ useEffect(() => {
59
+ defaultDeviceStorageRef.current = options.defaultDeviceStorage
60
+ onErrorRef.current = options.onError
61
+ }, [options.defaultDeviceStorage, options.onError])
62
+
63
+ useEffect(() => {
64
+ let mounted = true
65
+
66
+ const loadDefaultDevice = async () => {
67
+ try {
68
+ const [nativeDefaultDevice, storedDefaultDevice] = await Promise.all([
69
+ BluetoothSdk.getDefaultDevice(),
70
+ defaultDeviceStorageRef.current?.load() ?? Promise.resolve(null),
71
+ ])
72
+ if (!mounted) {
73
+ return
74
+ }
75
+ const nextDefaultDevice = storedDefaultDevice ?? nativeDefaultDevice
76
+ if (nextDefaultDevice) {
77
+ await BluetoothSdk.setDefaultDevice(nextDefaultDevice)
78
+ }
79
+ if (mounted) {
80
+ setDefaultDeviceState(nextDefaultDevice)
81
+ setOperationError(null)
82
+ }
83
+ } catch (nextError) {
84
+ if (!mounted) {
85
+ return
86
+ }
87
+ setOperationError(nextError)
88
+ onErrorRef.current?.(nextError)
89
+ }
90
+ }
91
+
92
+ void loadDefaultDevice()
93
+
94
+ return () => {
95
+ mounted = false
96
+ }
97
+ }, [])
98
+
99
+ useEffect(() => {
100
+ if (!options.autoConnectDefault || autoConnectAttemptedRef.current || status.connected || !defaultDevice) {
101
+ return
102
+ }
103
+
104
+ autoConnectAttemptedRef.current = true
105
+ void connectDefault().catch(() => undefined)
106
+ }, [defaultDevice, options.autoConnectDefault, status.connected])
107
+
108
+ async function runConnectionAction<T>(
109
+ nextAction: Exclude<GlassesConnectionAction, "idle" | "scanning">,
110
+ operation: () => Promise<T>,
111
+ ): Promise<T> {
112
+ setAction(nextAction)
113
+ setOperationError(null)
114
+ try {
115
+ const result = await operation()
116
+ setOperationError(null)
117
+ return result
118
+ } catch (nextError) {
119
+ setOperationError(nextError)
120
+ onErrorRef.current?.(nextError)
121
+ throw nextError
122
+ } finally {
123
+ setAction("idle")
124
+ }
125
+ }
126
+
127
+ async function setDefaultDevice(device: Device | null) {
128
+ await runConnectionAction("connecting", async () => {
129
+ await BluetoothSdk.setDefaultDevice(device)
130
+ await defaultDeviceStorageRef.current?.save(device)
131
+ setDefaultDeviceState(device)
132
+ })
133
+ }
134
+
135
+ async function clearDefaultDevice() {
136
+ await runConnectionAction("forgetting", async () => {
137
+ await BluetoothSdk.clearDefaultDevice()
138
+ await defaultDeviceStorageRef.current?.save(null)
139
+ setDefaultDeviceState(null)
140
+ scan.selectDevice(null)
141
+ })
142
+ }
143
+
144
+ async function connect(device?: Device, connectOptions?: ConnectOptions) {
145
+ await runConnectionAction("connecting", async () => {
146
+ const targetDevice = device ?? scan.selectedDevice
147
+ if (targetDevice) {
148
+ await BluetoothSdk.connect(targetDevice, connectOptions)
149
+ if (connectOptions?.saveAsDefault !== false) {
150
+ await defaultDeviceStorageRef.current?.save(targetDevice)
151
+ setDefaultDeviceState(targetDevice)
152
+ }
153
+ return
154
+ }
155
+ await BluetoothSdk.connectDefault(connectOptions)
156
+ })
157
+ }
158
+
159
+ async function connectDefault(connectOptions?: ConnectOptions) {
160
+ await runConnectionAction("connecting", async () => {
161
+ await BluetoothSdk.connectDefault(connectOptions)
162
+ })
163
+ }
164
+
165
+ async function disconnect() {
166
+ await runConnectionAction("disconnecting", async () => {
167
+ await BluetoothSdk.disconnect()
168
+ })
169
+ }
170
+
171
+ async function forget() {
172
+ await runConnectionAction("forgetting", async () => {
173
+ await BluetoothSdk.forget()
174
+ scan.clearResults()
175
+ })
176
+ }
177
+
178
+ const busy = action !== "idle" || scan.scanning || status.loading
179
+
180
+ return {
181
+ ...status,
182
+ action: scan.scanning ? "scanning" : action,
183
+ busy,
184
+ clearDefaultDevice,
185
+ connect,
186
+ connectDefault,
187
+ defaultDevice,
188
+ disconnect,
189
+ error: operationError ?? scan.error ?? status.error,
190
+ forget,
191
+ scan,
192
+ setDefaultDevice,
193
+ }
194
+ }
@@ -1 +0,0 @@
1
- {"version":3,"file":"BluetoothSdkModule.d.ts","sourceRoot":"","sources":["../src/BluetoothSdkModule.ts"],"names":[],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"BluetoothSdkModule.js","sourceRoot":"","sources":["../src/BluetoothSdkModule.ts"],"names":[],"mappings":"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","sourcesContent":["import {NativeModule, requireNativeModule} from \"expo\"\n\nimport {\n BluetoothSettingsUpdate,\n BluetoothSdkModuleEvents,\n BluetoothStatus,\n ButtonPhotoSize,\n CameraFov,\n CameraFovSetting,\n ConnectFirstOptions,\n ConnectOptions,\n DashboardMenuItem,\n Device,\n DeviceModel,\n GalleryMode,\n GlassesMediaVolumeGetResult,\n GlassesMediaVolumeSetResult,\n GlassesStatus,\n MicPreference,\n ObservableStoreCategory,\n PhotoCompression,\n PhotoSize,\n RgbLedAction,\n RgbLedColor,\n StreamKeepAliveRequest,\n StreamStartRequest,\n} from \"./BluetoothSdk.types\"\n\ntype GlassesListener = (changed: Partial<GlassesStatus>) => void\ntype BluetoothStatusListener = (changed: Partial<BluetoothStatus>) => void\ntype MaybePromise<T> = T | Promise<T>\n\ndeclare class BluetoothSdkModule extends NativeModule<BluetoothSdkModuleEvents> {\n // Observable Store Functions (native)\n getGlassesStatus(): Promise<GlassesStatus>\n getBluetoothStatus(): Promise<BluetoothStatus>\n getDefaultDevice(): Promise<Device | null>\n update(category: ObservableStoreCategory, values: object): Promise<void>\n\n // Display Commands\n displayEvent(params: Record<string, unknown>): Promise<void>\n displayText(text: string, x?: number, y?: number, size?: number): Promise<void>\n clearDisplay(): Promise<void>\n\n // Connection Commands\n requestStatus(): Promise<void>\n connectDefault(options?: ConnectOptions): Promise<void>\n connectDefaultWithOptions(options: Required<ConnectOptions>): Promise<void>\n setDefaultDevice(device: Device | null): Promise<void>\n clearDefaultDevice(): Promise<void>\n startScan(model: DeviceModel): Promise<void>\n connectFirst(model: DeviceModel, options?: ConnectFirstOptions): Promise<Device>\n connect(device: Device, options?: ConnectOptions): Promise<void>\n connectWithOptions(device: Device, options: Required<ConnectOptions>): Promise<void>\n cancelConnectionAttempt(): Promise<void>\n connectDefaultController(): Promise<void>\n disconnectController(): Promise<void>\n connectSimulated(): Promise<void>\n disconnect(): Promise<void>\n forget(): Promise<void>\n forgetController(): Promise<void>\n showDashboard(): Promise<void>\n setBrightness(level: number, autoMode?: boolean | null): Promise<void>\n setAutoBrightness(enabled: boolean): Promise<void>\n setDashboardPosition(height: number, depth: number): Promise<void>\n setDashboardMenu(items: DashboardMenuItem[]): Promise<void>\n setHeadUpAngle(angleDegrees: number): Promise<void>\n setScreenDisabled(disabled: boolean): Promise<void>\n ping(): Promise<void>\n dbg1(): Promise<void>\n dbg2(): Promise<void>\n\n // Incident Reporting\n sendIncidentId(incidentId: string, apiBaseUrl?: string | null): Promise<void>\n\n // WiFi Commands\n requestWifiScan(): Promise<void>\n sendWifiCredentials(ssid: string, password: string): Promise<void>\n forgetWifiNetwork(ssid: string): Promise<void>\n setHotspotState(enabled: boolean): Promise<void>\n /** Logs current WiFi frequency (MHz) and 5 GHz band to Android logcat. */\n logCurrentWifiFrequency(): Promise<void>\n\n // Gallery Commands\n setGalleryMode(mode: GalleryMode): Promise<void>\n setButtonPhotoSettings(size: ButtonPhotoSize): Promise<void>\n setButtonVideoRecordingSettings(width: number, height: number, fps: number): Promise<void>\n setButtonCameraLed(enabled: boolean): Promise<void>\n setButtonMaxRecordingTime(minutes: number): Promise<void>\n setCameraFov(fov: CameraFov): Promise<void>\n queryGalleryStatus(): Promise<void>\n photoRequest(\n requestId: string,\n appId: string,\n size: PhotoSize,\n webhookUrl: string | null,\n authToken: string | null,\n compress: PhotoCompression,\n flash: boolean,\n sound: boolean,\n ): Promise<void>\n\n // OTA Commands\n sendOtaStart(): Promise<void>\n sendOtaQueryStatus(): Promise<void>\n\n // Version Info Commands\n requestVersionInfo(): Promise<void>\n\n // Video Recording Commands\n startVideoRecording(requestId: string, save: boolean, flash: boolean, sound: boolean): Promise<void>\n stopVideoRecording(requestId: string): Promise<void>\n\n // Stream Commands\n startStream(params: StreamStartRequest): Promise<void>\n stopStream(): Promise<void>\n keepStreamAlive(params: StreamKeepAliveRequest): Promise<void>\n\n // Microphone Commands\n setMicState(\n enabled: boolean,\n useGlassesMic?: boolean,\n bypassVad?: boolean,\n sendTranscript?: boolean,\n sendLc3Data?: boolean,\n ): Promise<void>\n setPreferredMic(preferredMic: MicPreference): Promise<void>\n restartTranscriber(): Promise<void>\n\n // Audio Playback Monitoring\n // Notify native side when our app starts/stops playing audio\n // Used to suspend LC3 mic during audio playback to avoid MCU overload\n setOwnAppAudioPlaying(playing: boolean): Promise<void>\n\n /** Mentra Live only: K900 `cs_getvol` / `sr_getvol`. */\n getGlassesMediaVolume(): Promise<GlassesMediaVolumeGetResult>\n /** Mentra Live only: K900 `cs_vol` / `sr_vol`; level clamped 0–15 on native. */\n setGlassesMediaVolume(level: number): Promise<GlassesMediaVolumeSetResult>\n\n // RGB LED Control\n rgbLedControl(\n requestId: string,\n packageName: string | null,\n action: RgbLedAction,\n color: RgbLedColor | null,\n ontime: number,\n offtime: number,\n count: number,\n ): Promise<void>\n\n // STT Commands\n setSttModelDetails(path: string, languageCode: string): Promise<void>\n getSttModelPath(): Promise<string>\n checkSttModelAvailable(): Promise<boolean>\n validateSttModel(path: string): Promise<boolean>\n extractTarBz2(sourcePath: string, destinationPath: string): Promise<boolean>\n\n // Helper methods for type-safe observable store access\n updateGlasses(values: Partial<GlassesStatus>): Promise<void>\n updateBluetoothSettings(values: BluetoothSettingsUpdate): Promise<void>\n onGlassesStatus(callback: GlassesListener): () => void\n onBluetoothStatus(callback: BluetoothStatusListener): () => void\n\n // Process resident-set-size in MB. iOS-only; Android stub returns 0.\n getMemoryMB(): number\n}\n\n// This call loads the native module object from the JSI.\n// NativeModule<BluetoothSdkModuleEvents> already extends EventEmitter<BluetoothSdkModuleEvents>\nconst NativeBluetoothSdkModule = requireNativeModule<BluetoothSdkModule>(\"BluetoothSdk\")\n\nconst DEFAULT_CONNECT_OPTIONS: Required<ConnectOptions> = {\n saveAsDefault: true,\n cancelExistingConnectionAttempt: true,\n}\n\nconst DEFAULT_CONNECT_FIRST_TIMEOUT_MS = 15_000\n\nconst CAMERA_FOV_SETTINGS: Record<CameraFov, CameraFovSetting> = {\n standard: {fov: 118, roi_position: 0},\n wide: {fov: 118, roi_position: 0},\n}\n\nfunction findSearchResult(status: Partial<BluetoothStatus>, model: DeviceModel): Device | null {\n return status.searchResults?.find((device) => device.model === model) ?? null\n}\n\nfunction dashboardMenuItemToNative(item: DashboardMenuItem): Record<string, unknown> {\n return {\n ...(item.values ?? {}),\n title: item.title,\n packageName: item.packageName,\n }\n}\n\nfunction adaptConnectionStatusToNative(connection: GlassesStatus[\"connection\"]): Record<string, unknown> {\n switch (connection.state) {\n case \"connected\":\n return {connectionState: \"CONNECTED\", connected: true, fullyBooted: connection.fullyBooted}\n case \"scanning\":\n return {connectionState: \"SCANNING\", connected: false, fullyBooted: false}\n case \"connecting\":\n return {connectionState: \"CONNECTING\", connected: false, fullyBooted: false}\n case \"bonding\":\n return {connectionState: \"BONDING\", connected: false, fullyBooted: false}\n case \"disconnected\":\n return {connectionState: \"DISCONNECTED\", connected: false, fullyBooted: false}\n }\n}\n\nfunction adaptGlassesUpdateToNative(values: Partial<GlassesStatus>): Record<string, unknown> {\n const {wifi, hotspot, connection, ...rest} = values\n let update: Record<string, unknown> = {...rest}\n if (connection) {\n update = {\n ...update,\n ...adaptConnectionStatusToNative(connection),\n }\n }\n if (wifi?.state === \"connected\") {\n update = {\n ...update,\n wifiConnected: true,\n wifiSsid: wifi.ssid,\n wifiLocalIp: wifi.localIp ?? \"\",\n }\n } else if (wifi?.state === \"disconnected\") {\n update = {\n ...update,\n wifiConnected: false,\n wifiSsid: \"\",\n wifiLocalIp: \"\",\n }\n }\n if (hotspot?.state === \"enabled\") {\n update = {\n ...update,\n hotspotEnabled: true,\n hotspotSsid: hotspot.ssid,\n hotspotPassword: hotspot.password,\n hotspotGatewayIp: hotspot.localIp,\n }\n } else if (hotspot?.state === \"disabled\") {\n update = {\n ...update,\n hotspotEnabled: false,\n hotspotSsid: \"\",\n hotspotPassword: \"\",\n hotspotGatewayIp: \"\",\n }\n }\n return update\n}\n\n// Add helper methods to the module\nconst nativeGetGlassesStatus = NativeBluetoothSdkModule.getGlassesStatus.bind(\n NativeBluetoothSdkModule,\n) as () => MaybePromise<GlassesStatus>\nNativeBluetoothSdkModule.getGlassesStatus = function () {\n return Promise.resolve(nativeGetGlassesStatus())\n}\n\nconst nativeGetBluetoothStatus = NativeBluetoothSdkModule.getBluetoothStatus.bind(NativeBluetoothSdkModule) as () => MaybePromise<BluetoothStatus>\nNativeBluetoothSdkModule.getBluetoothStatus = function () {\n return Promise.resolve(nativeGetBluetoothStatus())\n}\n\nconst nativeGetDefaultDevice = NativeBluetoothSdkModule.getDefaultDevice.bind(\n NativeBluetoothSdkModule,\n) as () => MaybePromise<Device | null>\nNativeBluetoothSdkModule.getDefaultDevice = function () {\n return Promise.resolve(nativeGetDefaultDevice())\n}\n\nconst nativeSetMicState = NativeBluetoothSdkModule.setMicState.bind(NativeBluetoothSdkModule) as (\n enabled: boolean,\n useGlassesMic: boolean,\n bypassVad: boolean,\n sendTranscript: boolean,\n sendLc3Data: boolean,\n) => MaybePromise<void>\n\nconst nativeDisplayText = NativeBluetoothSdkModule.displayText.bind(NativeBluetoothSdkModule) as (\n text: string,\n x: number,\n y: number,\n size: number,\n) => MaybePromise<void>\n\nNativeBluetoothSdkModule.updateGlasses = function (values: Partial<GlassesStatus>) {\n return this.update(\"glasses\", adaptGlassesUpdateToNative(values))\n}\n\nNativeBluetoothSdkModule.updateBluetoothSettings = function (values: BluetoothSettingsUpdate) {\n return this.update(\"bluetooth\", values)\n}\n\nNativeBluetoothSdkModule.displayText = function (text: string, x?: number, y?: number, size?: number) {\n return Promise.resolve(nativeDisplayText(text, x ?? 0, y ?? 0, size ?? 24))\n}\n\nNativeBluetoothSdkModule.setBrightness = function (level: number, autoMode?: boolean | null) {\n return this.updateBluetoothSettings({\n ...(autoMode == null ? {} : {auto_brightness: autoMode}),\n brightness: level,\n })\n}\n\nNativeBluetoothSdkModule.setAutoBrightness = function (enabled: boolean) {\n return this.updateBluetoothSettings({auto_brightness: enabled})\n}\n\nNativeBluetoothSdkModule.setDashboardPosition = function (height: number, depth: number) {\n return this.updateBluetoothSettings({\n dashboard_height: height,\n dashboard_depth: depth,\n })\n}\n\nNativeBluetoothSdkModule.setDashboardMenu = function (items: DashboardMenuItem[]) {\n return this.updateBluetoothSettings({menu_apps: items.map(dashboardMenuItemToNative)})\n}\n\nNativeBluetoothSdkModule.setHeadUpAngle = function (angleDegrees: number) {\n return this.updateBluetoothSettings({head_up_angle: angleDegrees})\n}\n\nNativeBluetoothSdkModule.setScreenDisabled = function (disabled: boolean) {\n return this.updateBluetoothSettings({screen_disabled: disabled})\n}\n\nNativeBluetoothSdkModule.setButtonPhotoSettings = function (size: ButtonPhotoSize) {\n return this.updateBluetoothSettings({button_photo_size: size})\n}\n\nNativeBluetoothSdkModule.setButtonVideoRecordingSettings = function (width: number, height: number, fps: number) {\n return this.updateBluetoothSettings({\n button_video_width: width,\n button_video_height: height,\n button_video_fps: fps,\n })\n}\n\nNativeBluetoothSdkModule.setButtonCameraLed = function (enabled: boolean) {\n return this.updateBluetoothSettings({button_camera_led: enabled})\n}\n\nNativeBluetoothSdkModule.setButtonMaxRecordingTime = function (minutes: number) {\n return this.updateBluetoothSettings({button_max_recording_time: minutes})\n}\n\nNativeBluetoothSdkModule.setCameraFov = function (fov: CameraFov) {\n return this.updateBluetoothSettings({camera_fov: CAMERA_FOV_SETTINGS[fov]})\n}\n\nNativeBluetoothSdkModule.setMicState = function (\n enabled: boolean,\n useGlassesMic?: boolean,\n bypassVad?: boolean,\n sendTranscript?: boolean,\n sendLc3Data?: boolean,\n) {\n return Promise.resolve(\n nativeSetMicState(\n enabled,\n useGlassesMic ?? true,\n bypassVad ?? false,\n sendTranscript ?? false,\n sendLc3Data ?? false,\n ),\n )\n}\n\nNativeBluetoothSdkModule.setPreferredMic = function (preferredMic: MicPreference) {\n return this.updateBluetoothSettings({preferred_mic: preferredMic})\n}\n\nNativeBluetoothSdkModule.onGlassesStatus = function (callback: GlassesListener) {\n const subscription = this.addListener(\"glasses_status\", callback)\n return () => subscription.remove()\n}\n\nNativeBluetoothSdkModule.onBluetoothStatus = function (callback: BluetoothStatusListener) {\n const subscription = this.addListener(\"bluetooth_status\", callback)\n return () => subscription.remove()\n}\n\nconst nativeConnectDefault = NativeBluetoothSdkModule.connectDefault.bind(NativeBluetoothSdkModule)\nNativeBluetoothSdkModule.connectDefault = function (options?: ConnectOptions) {\n if (!options) {\n return nativeConnectDefault()\n }\n return this.connectDefaultWithOptions({...DEFAULT_CONNECT_OPTIONS, ...options})\n}\n\nNativeBluetoothSdkModule.connect = function (device: Device, options?: ConnectOptions) {\n return this.connectWithOptions(device, {...DEFAULT_CONNECT_OPTIONS, ...options})\n}\n\nNativeBluetoothSdkModule.connectFirst = async function (model: DeviceModel, options?: ConnectFirstOptions) {\n const {timeoutMs = DEFAULT_CONNECT_FIRST_TIMEOUT_MS, ...connectOptions} = options ?? {}\n\n const device = await new Promise<Device>((resolve, reject) => {\n let timeout: ReturnType<typeof setTimeout> | null = null\n let removeBluetoothListener = () => {}\n let settled = false\n\n const cleanup = () => {\n if (timeout) {\n clearTimeout(timeout)\n }\n removeBluetoothListener()\n }\n\n const settle = (error: Error | null, result?: Device) => {\n if (settled) {\n return\n }\n settled = true\n cleanup()\n if (error) {\n reject(error)\n } else if (result) {\n resolve(result)\n }\n }\n\n const handleBluetoothStatus = (status: Partial<BluetoothStatus>) => {\n const result = findSearchResult(status, model)\n if (result) {\n settle(null, result)\n }\n }\n\n removeBluetoothListener = this.onBluetoothStatus(handleBluetoothStatus)\n\n if (Number.isFinite(timeoutMs) && timeoutMs > 0) {\n timeout = setTimeout(() => {\n settle(new Error(`Timed out after ${timeoutMs}ms while scanning for ${model}.`))\n }, timeoutMs)\n }\n\n Promise.resolve(this.startScan(model))\n .then(() => this.getBluetoothStatus())\n .then(handleBluetoothStatus)\n .catch((error) => settle(error instanceof Error ? error : new Error(String(error))))\n })\n\n await this.connect(device, connectOptions)\n return device\n}\n\nexport default NativeBluetoothSdkModule\n"]}