@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.
- package/README.md +75 -19
- package/android/src/main/java/com/mentra/bluetoothsdk/BluetoothSdkModule.kt +13 -13
- package/android/src/main/java/com/mentra/bluetoothsdk/Bridge.kt +42 -18
- package/android/src/main/java/com/mentra/bluetoothsdk/DeviceManager.kt +19 -21
- package/android/src/main/java/com/mentra/bluetoothsdk/DeviceStore.kt +4 -4
- package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothModels.kt +118 -103
- package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothSdk.kt +110 -38
- package/android/src/main/java/com/mentra/bluetoothsdk/controllers/ControllerManager.kt +4 -4
- package/android/src/main/java/com/mentra/bluetoothsdk/controllers/R1.kt +2 -2
- package/android/src/main/java/com/mentra/bluetoothsdk/services/PhoneMic.kt +6 -6
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G1.java +1 -1
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G2.kt +3 -3
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Mach1.java +1 -1
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraLive.java +18 -18
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraNex.kt +1 -1
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/SGCManager.kt +4 -4
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Simulated.kt +2 -2
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/Constants.kt +6 -6
- package/app.plugin.js +3 -1
- package/build/BluetoothSdk.types.d.ts +126 -27
- package/build/BluetoothSdk.types.d.ts.map +1 -1
- package/build/BluetoothSdk.types.js.map +1 -1
- package/build/_internal.d.ts +12 -0
- package/build/_internal.d.ts.map +1 -0
- package/build/_internal.js +11 -0
- package/build/_internal.js.map +1 -0
- package/build/{BluetoothSdkModule.d.ts → _private/BluetoothSdkModule.d.ts} +19 -8
- package/build/_private/BluetoothSdkModule.d.ts.map +1 -0
- package/build/{BluetoothSdkModule.js → _private/BluetoothSdkModule.js} +41 -26
- package/build/_private/BluetoothSdkModule.js.map +1 -0
- package/build/index.d.ts +4 -2
- package/build/index.d.ts.map +1 -1
- package/build/index.js +3 -4
- package/build/index.js.map +1 -1
- package/build/react/index.d.ts +5 -0
- package/build/react/index.d.ts.map +1 -0
- package/build/react/index.js +5 -0
- package/build/react/index.js.map +1 -0
- package/build/react/useBluetoothEvent.d.ts +6 -0
- package/build/react/useBluetoothEvent.d.ts.map +1 -0
- package/build/react/useBluetoothEvent.js +21 -0
- package/build/react/useBluetoothEvent.js.map +1 -0
- package/build/react/useBluetoothScan.d.ts +22 -0
- package/build/react/useBluetoothScan.d.ts.map +1 -0
- package/build/react/useBluetoothScan.js +135 -0
- package/build/react/useBluetoothScan.js.map +1 -0
- package/build/react/useBluetoothStatus.d.ts +16 -0
- package/build/react/useBluetoothStatus.d.ts.map +1 -0
- package/build/react/useBluetoothStatus.js +137 -0
- package/build/react/useBluetoothStatus.js.map +1 -0
- package/build/react/useGlassesConnection.d.ts +29 -0
- package/build/react/useGlassesConnection.d.ts.map +1 -0
- package/build/react/useGlassesConnection.js +140 -0
- package/build/react/useGlassesConnection.js.map +1 -0
- package/ios/BluetoothSdkModule.swift +14 -9
- package/ios/Source/Bridge.swift +44 -12
- package/ios/Source/DeviceManager.swift +27 -26
- package/ios/Source/DeviceStore.swift +4 -4
- package/ios/Source/MentraBluetoothSDK.swift +250 -132
- package/ios/Source/controllers/ControllerManager.swift +5 -5
- package/ios/Source/controllers/R1.swift +3 -3
- package/ios/Source/services/PhoneMic.swift +5 -5
- package/ios/Source/sgcs/Frame.swift +1 -1
- package/ios/Source/sgcs/G1.swift +1 -1
- package/ios/Source/sgcs/G2.swift +3 -3
- package/ios/Source/sgcs/Mach1.swift +1 -1
- package/ios/Source/sgcs/MentraLive.swift +31 -33
- package/ios/Source/sgcs/MentraNex.swift +2 -2
- package/ios/Source/sgcs/SGCManager.swift +5 -5
- package/ios/Source/sgcs/Simulated.swift +3 -3
- package/ios/Source/utils/Constants.swift +6 -6
- package/ios/Source/utils/JSCExperiment.swift +8 -8
- package/ios/Source/utils/TarBz2Extractor.swift +2 -2
- package/package.json +19 -1
- package/src/BluetoothSdk.types.ts +186 -28
- package/src/_internal.ts +11 -0
- package/src/{BluetoothSdkModule.ts → _private/BluetoothSdkModule.ts} +71 -38
- package/src/index.ts +80 -4
- package/src/react/index.ts +22 -0
- package/src/react/useBluetoothEvent.ts +38 -0
- package/src/react/useBluetoothScan.ts +173 -0
- package/src/react/useBluetoothStatus.ts +180 -0
- package/src/react/useGlassesConnection.ts +194 -0
- package/build/BluetoothSdkModule.d.ts.map +0 -1
- 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"]}
|