@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
|
@@ -6,13 +6,22 @@ const DEFAULT_CONNECT_OPTIONS = {
|
|
|
6
6
|
saveAsDefault: true,
|
|
7
7
|
cancelExistingConnectionAttempt: true,
|
|
8
8
|
};
|
|
9
|
-
const
|
|
9
|
+
const DEFAULT_SCAN_TIMEOUT_MS = 15_000;
|
|
10
10
|
const CAMERA_FOV_SETTINGS = {
|
|
11
|
-
standard: { fov: 118,
|
|
12
|
-
wide: { fov: 118,
|
|
11
|
+
standard: { fov: 118, roiPosition: 0 },
|
|
12
|
+
wide: { fov: 118, roiPosition: 0 },
|
|
13
13
|
};
|
|
14
|
-
function
|
|
15
|
-
return status.searchResults?.
|
|
14
|
+
function searchResultsForModel(status, model) {
|
|
15
|
+
return status.searchResults?.filter((device) => device.model === model) ?? [];
|
|
16
|
+
}
|
|
17
|
+
function normalizeScanArgs(modelOrOptions, options) {
|
|
18
|
+
if (typeof modelOrOptions === "string") {
|
|
19
|
+
return { model: modelOrOptions, ...options };
|
|
20
|
+
}
|
|
21
|
+
return modelOrOptions;
|
|
22
|
+
}
|
|
23
|
+
function normalizeTimeoutMs(timeoutMs, defaultTimeoutMs) {
|
|
24
|
+
return typeof timeoutMs === "number" && Number.isFinite(timeoutMs) && timeoutMs > 0 ? timeoutMs : defaultTimeoutMs;
|
|
16
25
|
}
|
|
17
26
|
function dashboardMenuItemToNative(item) {
|
|
18
27
|
return {
|
|
@@ -131,11 +140,11 @@ NativeBluetoothSdkModule.setScreenDisabled = function (disabled) {
|
|
|
131
140
|
NativeBluetoothSdkModule.setButtonPhotoSettings = function (size) {
|
|
132
141
|
return this.updateBluetoothSettings({ button_photo_size: size });
|
|
133
142
|
};
|
|
134
|
-
NativeBluetoothSdkModule.setButtonVideoRecordingSettings = function (width, height,
|
|
143
|
+
NativeBluetoothSdkModule.setButtonVideoRecordingSettings = function (width, height, frameRate) {
|
|
135
144
|
return this.updateBluetoothSettings({
|
|
136
145
|
button_video_width: width,
|
|
137
146
|
button_video_height: height,
|
|
138
|
-
button_video_fps:
|
|
147
|
+
button_video_fps: frameRate,
|
|
139
148
|
});
|
|
140
149
|
};
|
|
141
150
|
NativeBluetoothSdkModule.setButtonCameraLed = function (enabled) {
|
|
@@ -171,19 +180,29 @@ NativeBluetoothSdkModule.connectDefault = function (options) {
|
|
|
171
180
|
NativeBluetoothSdkModule.connect = function (device, options) {
|
|
172
181
|
return this.connectWithOptions(device, { ...DEFAULT_CONNECT_OPTIONS, ...options });
|
|
173
182
|
};
|
|
174
|
-
NativeBluetoothSdkModule.
|
|
175
|
-
const
|
|
176
|
-
const
|
|
183
|
+
NativeBluetoothSdkModule.scan = async function (modelOrOptions, options) {
|
|
184
|
+
const scanOptions = normalizeScanArgs(modelOrOptions, options);
|
|
185
|
+
const timeoutMs = normalizeTimeoutMs(scanOptions.timeoutMs ?? scanOptions.timeout, DEFAULT_SCAN_TIMEOUT_MS);
|
|
186
|
+
let latestResults = [];
|
|
187
|
+
return new Promise((resolve, reject) => {
|
|
177
188
|
let timeout = null;
|
|
178
189
|
let removeBluetoothListener = () => { };
|
|
179
190
|
let settled = false;
|
|
191
|
+
let scanStarted = false;
|
|
192
|
+
const emitResults = (devices) => {
|
|
193
|
+
latestResults = devices;
|
|
194
|
+
scanOptions.onResults?.([...devices]);
|
|
195
|
+
};
|
|
180
196
|
const cleanup = () => {
|
|
181
197
|
if (timeout) {
|
|
182
198
|
clearTimeout(timeout);
|
|
183
199
|
}
|
|
184
200
|
removeBluetoothListener();
|
|
201
|
+
if (scanStarted) {
|
|
202
|
+
void Promise.resolve(this.stopScan()).catch(() => undefined);
|
|
203
|
+
}
|
|
185
204
|
};
|
|
186
|
-
const settle = (error
|
|
205
|
+
const settle = (error) => {
|
|
187
206
|
if (settled) {
|
|
188
207
|
return;
|
|
189
208
|
}
|
|
@@ -192,29 +211,25 @@ NativeBluetoothSdkModule.connectFirst = async function (model, options) {
|
|
|
192
211
|
if (error) {
|
|
193
212
|
reject(error);
|
|
194
213
|
}
|
|
195
|
-
else
|
|
196
|
-
resolve(
|
|
214
|
+
else {
|
|
215
|
+
resolve([...latestResults]);
|
|
197
216
|
}
|
|
198
217
|
};
|
|
199
218
|
const handleBluetoothStatus = (status) => {
|
|
200
|
-
|
|
201
|
-
if (result) {
|
|
202
|
-
settle(null, result);
|
|
203
|
-
}
|
|
219
|
+
emitResults(searchResultsForModel(status, scanOptions.model));
|
|
204
220
|
};
|
|
205
221
|
removeBluetoothListener = this.onBluetoothStatus(handleBluetoothStatus);
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
222
|
+
emitResults([]);
|
|
223
|
+
timeout = setTimeout(() => settle(), timeoutMs);
|
|
224
|
+
Promise.resolve(this.startScan(scanOptions.model))
|
|
225
|
+
.then(() => {
|
|
226
|
+
scanStarted = true;
|
|
227
|
+
return this.getBluetoothStatus();
|
|
228
|
+
})
|
|
213
229
|
.then(handleBluetoothStatus)
|
|
214
230
|
.catch((error) => settle(error instanceof Error ? error : new Error(String(error))));
|
|
215
231
|
});
|
|
216
|
-
await this.connect(device, connectOptions);
|
|
217
|
-
return device;
|
|
218
232
|
};
|
|
219
233
|
export default NativeBluetoothSdkModule;
|
|
234
|
+
export const BluetoothSdk = NativeBluetoothSdkModule;
|
|
220
235
|
//# sourceMappingURL=BluetoothSdkModule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BluetoothSdkModule.js","sourceRoot":"","sources":["../../src/_private/BluetoothSdkModule.ts"],"names":[],"mappings":"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","sourcesContent":["import {NativeModule, requireNativeModule} from \"expo\"\n\nimport {\n BluetoothSettingsUpdate,\n BluetoothSdkPublicModule,\n BluetoothSdkModuleEvents,\n BluetoothStatus,\n ButtonPhotoSize,\n CameraFov,\n CameraFovSetting,\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 ScanModelOptions,\n ScanOptions,\n StreamKeepAliveRequest,\n StreamStartRequest,\n} from \"../BluetoothSdk.types\"\n\n/**\n * Private React Native native-module facade.\n *\n * This file intentionally lives under `_private` so the package root can expose\n * a small SDK surface while MentraOS uses its monorepo-only internal alias\n * during migration.\n */\n\ntype GlassesListener = (changed: Partial<GlassesStatus>) => void\ntype BluetoothStatusListener = (changed: Partial<BluetoothStatus>) => void\ntype MaybePromise<T> = T | Promise<T>\n\ndeclare class BluetoothSdkNativeModule 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 stopScan(): Promise<void>\n scan(options: ScanOptions): Promise<Device[]>\n scan(model: DeviceModel, options?: ScanModelOptions): 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, frameRate: 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 requestPhoto(\n requestId: string,\n appId: string,\n size: PhotoSize,\n webhookUrl: string | null,\n authToken: string | null,\n compress: PhotoCompression,\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, 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 onDurationMs: number,\n offDurationMs: 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\nexport type BluetoothSdkInternalModule = BluetoothSdkNativeModule\n\n// This call loads the native module object from the JSI.\n// NativeModule<BluetoothSdkModuleEvents> already extends EventEmitter<BluetoothSdkModuleEvents>\nconst NativeBluetoothSdkModule = requireNativeModule<BluetoothSdkNativeModule>(\"BluetoothSdk\")\n\nconst DEFAULT_CONNECT_OPTIONS: Required<ConnectOptions> = {\n saveAsDefault: true,\n cancelExistingConnectionAttempt: true,\n}\n\nconst DEFAULT_SCAN_TIMEOUT_MS = 15_000\n\nconst CAMERA_FOV_SETTINGS: Record<CameraFov, CameraFovSetting> = {\n standard: {fov: 118, roiPosition: 0},\n wide: {fov: 118, roiPosition: 0},\n}\n\nfunction searchResultsForModel(status: Partial<BluetoothStatus>, model: DeviceModel): Device[] {\n return status.searchResults?.filter((device) => device.model === model) ?? []\n}\n\nfunction normalizeScanArgs(modelOrOptions: DeviceModel | ScanOptions, options?: ScanModelOptions): ScanOptions {\n if (typeof modelOrOptions === \"string\") {\n return {model: modelOrOptions, ...options}\n }\n return modelOrOptions\n}\n\nfunction normalizeTimeoutMs(timeoutMs: number | undefined, defaultTimeoutMs: number): number {\n return typeof timeoutMs === \"number\" && Number.isFinite(timeoutMs) && timeoutMs > 0 ? timeoutMs : defaultTimeoutMs\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, frameRate: number) {\n return this.updateBluetoothSettings({\n button_video_width: width,\n button_video_height: height,\n button_video_fps: frameRate,\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.scan = async function (\n modelOrOptions: DeviceModel | ScanOptions,\n options?: ScanModelOptions,\n) {\n const scanOptions = normalizeScanArgs(modelOrOptions, options)\n const timeoutMs = normalizeTimeoutMs(scanOptions.timeoutMs ?? scanOptions.timeout, DEFAULT_SCAN_TIMEOUT_MS)\n let latestResults: Device[] = []\n\n return new Promise<Device[]>((resolve, reject) => {\n let timeout: ReturnType<typeof setTimeout> | null = null\n let removeBluetoothListener = () => {}\n let settled = false\n let scanStarted = false\n\n const emitResults = (devices: Device[]) => {\n latestResults = devices\n scanOptions.onResults?.([...devices])\n }\n\n const cleanup = () => {\n if (timeout) {\n clearTimeout(timeout)\n }\n removeBluetoothListener()\n if (scanStarted) {\n void Promise.resolve(this.stopScan()).catch(() => undefined)\n }\n }\n\n const settle = (error?: Error) => {\n if (settled) {\n return\n }\n settled = true\n cleanup()\n if (error) {\n reject(error)\n } else {\n resolve([...latestResults])\n }\n }\n\n const handleBluetoothStatus = (status: Partial<BluetoothStatus>) => {\n emitResults(searchResultsForModel(status, scanOptions.model))\n }\n\n removeBluetoothListener = this.onBluetoothStatus(handleBluetoothStatus)\n emitResults([])\n\n timeout = setTimeout(() => settle(), timeoutMs)\n\n Promise.resolve(this.startScan(scanOptions.model))\n .then(() => {\n scanStarted = true\n return this.getBluetoothStatus()\n })\n .then(handleBluetoothStatus)\n .catch((error) => settle(error instanceof Error ? error : new Error(String(error))))\n })\n}\n\nexport default NativeBluetoothSdkModule\nexport const BluetoothSdk = NativeBluetoothSdkModule as BluetoothSdkPublicModule\n"]}
|
package/build/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
export
|
|
1
|
+
import { BluetoothSdk } from "./_private/BluetoothSdkModule";
|
|
2
|
+
export default BluetoothSdk;
|
|
3
|
+
export { DeviceModels, createDisconnectedGlassesStatus, isBusyGlassesConnectionStatus, isConnectedGlassesConnectionStatus, isConnectedWifiStatus, isEnabledHotspotStatus, isReadyGlassesConnectionStatus, } from "./BluetoothSdk.types";
|
|
4
|
+
export type { AudioConnectedEvent, AudioDisconnectedEvent, AudioPairingNeededEvent, BatteryStatusEvent, BluetoothSdkEvent, BluetoothSdkEventListener, BluetoothSdkEventMap, BluetoothSdkEventName, BluetoothSdkPublicModule as BluetoothSdkModule, BluetoothSdkSubscription, ButtonPhotoSize, ButtonPressEvent, CameraFov, CompatibleGlassesSearchStopEvent, ConnectOptions, ConnectedGlassesConnectionStatus, ConnectedWifiStatus, Device, DeviceModel, EnabledHotspotStatus, GalleryMode, GalleryStatusEvent, GlassesConnectionStatus, GlassesMediaVolumeGetResult, GlassesMediaVolumeSetResult, GlassesNotReadyEvent, HeadUpEvent, HotspotErrorEvent, HotspotStatus, HotspotStatusChangeEvent, KeepAliveAckEvent, LocalTranscriptionEvent, LogEvent, MicLc3Event, MicMode, MicPcmEvent, MicPreference, PairFailureEvent, PhotoCompression, PhotoResponseEvent, PhotoSize, PublicBluetoothStatus as BluetoothStatus, PublicGlassesStatus as GlassesStatus, RgbLedAction, RgbLedColor, RgbLedControlResponseEvent, ScanModelOptions, ScanOptions, ScanResultsCallback, StreamAudioConfig, StreamKeepAliveRequest, StreamStartRequest, StreamStatusEvent, StreamStatusLifecycleState, StreamStatusReconnectState, StreamStatusState, StreamVideoConfig, SwipeVolumeStatusEvent, SwitchStatusEvent, TouchEvent, VadStatusEvent, WifiSearchResult, WifiStatus, WifiStatusChangeEvent, } from "./BluetoothSdk.types";
|
|
3
5
|
//# sourceMappingURL=index.d.ts.map
|
package/build/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,YAAY,EAAC,MAAM,+BAA+B,CAAA;AAE1D,eAAe,YAAY,CAAA;AAE3B,OAAO,EACL,YAAY,EACZ,+BAA+B,EAC/B,6BAA6B,EAC7B,kCAAkC,EAClC,qBAAqB,EACrB,sBAAsB,EACtB,8BAA8B,GAC/B,MAAM,sBAAsB,CAAA;AAE7B,YAAY,EACV,mBAAmB,EACnB,sBAAsB,EACtB,uBAAuB,EACvB,kBAAkB,EAClB,iBAAiB,EACjB,yBAAyB,EACzB,oBAAoB,EACpB,qBAAqB,EACrB,wBAAwB,IAAI,kBAAkB,EAC9C,wBAAwB,EACxB,eAAe,EACf,gBAAgB,EAChB,SAAS,EACT,gCAAgC,EAChC,cAAc,EACd,gCAAgC,EAChC,mBAAmB,EACnB,MAAM,EACN,WAAW,EACX,oBAAoB,EACpB,WAAW,EACX,kBAAkB,EAClB,uBAAuB,EACvB,2BAA2B,EAC3B,2BAA2B,EAC3B,oBAAoB,EACpB,WAAW,EACX,iBAAiB,EACjB,aAAa,EACb,wBAAwB,EACxB,iBAAiB,EACjB,uBAAuB,EACvB,QAAQ,EACR,WAAW,EACX,OAAO,EACP,WAAW,EACX,aAAa,EACb,gBAAgB,EAChB,gBAAgB,EAChB,kBAAkB,EAClB,SAAS,EACT,qBAAqB,IAAI,eAAe,EACxC,mBAAmB,IAAI,aAAa,EACpC,YAAY,EACZ,WAAW,EACX,0BAA0B,EAC1B,gBAAgB,EAChB,WAAW,EACX,mBAAmB,EACnB,iBAAiB,EACjB,sBAAsB,EACtB,kBAAkB,EAClB,iBAAiB,EACjB,0BAA0B,EAC1B,0BAA0B,EAC1B,iBAAiB,EACjB,iBAAiB,EACjB,sBAAsB,EACtB,iBAAiB,EACjB,UAAU,EACV,cAAc,EACd,gBAAgB,EAChB,UAAU,EACV,qBAAqB,GACtB,MAAM,sBAAsB,CAAA"}
|
package/build/index.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export {
|
|
4
|
-
export * from "./BluetoothSdk.types";
|
|
1
|
+
import { BluetoothSdk } from "./_private/BluetoothSdkModule";
|
|
2
|
+
export default BluetoothSdk;
|
|
3
|
+
export { DeviceModels, createDisconnectedGlassesStatus, isBusyGlassesConnectionStatus, isConnectedGlassesConnectionStatus, isConnectedWifiStatus, isEnabledHotspotStatus, isReadyGlassesConnectionStatus, } from "./BluetoothSdk.types";
|
|
5
4
|
//# sourceMappingURL=index.js.map
|
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,YAAY,EAAC,MAAM,+BAA+B,CAAA;AAE1D,eAAe,YAAY,CAAA;AAE3B,OAAO,EACL,YAAY,EACZ,+BAA+B,EAC/B,6BAA6B,EAC7B,kCAAkC,EAClC,qBAAqB,EACrB,sBAAsB,EACtB,8BAA8B,GAC/B,MAAM,sBAAsB,CAAA","sourcesContent":["import {BluetoothSdk} from \"./_private/BluetoothSdkModule\"\n\nexport default BluetoothSdk\n\nexport {\n DeviceModels,\n createDisconnectedGlassesStatus,\n isBusyGlassesConnectionStatus,\n isConnectedGlassesConnectionStatus,\n isConnectedWifiStatus,\n isEnabledHotspotStatus,\n isReadyGlassesConnectionStatus,\n} from \"./BluetoothSdk.types\"\n\nexport type {\n AudioConnectedEvent,\n AudioDisconnectedEvent,\n AudioPairingNeededEvent,\n BatteryStatusEvent,\n BluetoothSdkEvent,\n BluetoothSdkEventListener,\n BluetoothSdkEventMap,\n BluetoothSdkEventName,\n BluetoothSdkPublicModule as BluetoothSdkModule,\n BluetoothSdkSubscription,\n ButtonPhotoSize,\n ButtonPressEvent,\n CameraFov,\n CompatibleGlassesSearchStopEvent,\n ConnectOptions,\n ConnectedGlassesConnectionStatus,\n ConnectedWifiStatus,\n Device,\n DeviceModel,\n EnabledHotspotStatus,\n GalleryMode,\n GalleryStatusEvent,\n GlassesConnectionStatus,\n GlassesMediaVolumeGetResult,\n GlassesMediaVolumeSetResult,\n GlassesNotReadyEvent,\n HeadUpEvent,\n HotspotErrorEvent,\n HotspotStatus,\n HotspotStatusChangeEvent,\n KeepAliveAckEvent,\n LocalTranscriptionEvent,\n LogEvent,\n MicLc3Event,\n MicMode,\n MicPcmEvent,\n MicPreference,\n PairFailureEvent,\n PhotoCompression,\n PhotoResponseEvent,\n PhotoSize,\n PublicBluetoothStatus as BluetoothStatus,\n PublicGlassesStatus as GlassesStatus,\n RgbLedAction,\n RgbLedColor,\n RgbLedControlResponseEvent,\n ScanModelOptions,\n ScanOptions,\n ScanResultsCallback,\n StreamAudioConfig,\n StreamKeepAliveRequest,\n StreamStartRequest,\n StreamStatusEvent,\n StreamStatusLifecycleState,\n StreamStatusReconnectState,\n StreamStatusState,\n StreamVideoConfig,\n SwipeVolumeStatusEvent,\n SwitchStatusEvent,\n TouchEvent,\n VadStatusEvent,\n WifiSearchResult,\n WifiStatus,\n WifiStatusChangeEvent,\n} from \"./BluetoothSdk.types\"\n"]}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { useBluetoothEvent, type UseBluetoothEventOptions, } from "./useBluetoothEvent";
|
|
2
|
+
export { useBluetoothScan, type BluetoothScanDedupe, type BluetoothScanHookResult, type UseBluetoothScanOptions, } from "./useBluetoothScan";
|
|
3
|
+
export { useBluetoothStatus, type BluetoothStatusHookResult, type UseBluetoothStatusOptions, } from "./useBluetoothStatus";
|
|
4
|
+
export { useGlassesConnection, type DefaultDeviceStorage, type GlassesConnectionAction, type GlassesConnectionHookResult, type UseGlassesConnectionOptions, } from "./useGlassesConnection";
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,KAAK,wBAAwB,GAC9B,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EACL,gBAAgB,EAChB,KAAK,mBAAmB,EACxB,KAAK,uBAAuB,EAC5B,KAAK,uBAAuB,GAC7B,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EACL,kBAAkB,EAClB,KAAK,yBAAyB,EAC9B,KAAK,yBAAyB,GAC/B,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EACL,oBAAoB,EACpB,KAAK,oBAAoB,EACzB,KAAK,uBAAuB,EAC5B,KAAK,2BAA2B,EAChC,KAAK,2BAA2B,GACjC,MAAM,wBAAwB,CAAA"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { useBluetoothEvent, } from "./useBluetoothEvent";
|
|
2
|
+
export { useBluetoothScan, } from "./useBluetoothScan";
|
|
3
|
+
export { useBluetoothStatus, } from "./useBluetoothStatus";
|
|
4
|
+
export { useGlassesConnection, } from "./useGlassesConnection";
|
|
5
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,GAElB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EACL,gBAAgB,GAIjB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EACL,kBAAkB,GAGnB,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EACL,oBAAoB,GAKrB,MAAM,wBAAwB,CAAA","sourcesContent":["export {\n useBluetoothEvent,\n type UseBluetoothEventOptions,\n} from \"./useBluetoothEvent\"\nexport {\n useBluetoothScan,\n type BluetoothScanDedupe,\n type BluetoothScanHookResult,\n type UseBluetoothScanOptions,\n} from \"./useBluetoothScan\"\nexport {\n useBluetoothStatus,\n type BluetoothStatusHookResult,\n type UseBluetoothStatusOptions,\n} from \"./useBluetoothStatus\"\nexport {\n useGlassesConnection,\n type DefaultDeviceStorage,\n type GlassesConnectionAction,\n type GlassesConnectionHookResult,\n type UseGlassesConnectionOptions,\n} from \"./useGlassesConnection\"\n"]}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { BluetoothSdkEventListener, BluetoothSdkEventName } from "../BluetoothSdk.types";
|
|
2
|
+
export type UseBluetoothEventOptions = {
|
|
3
|
+
enabled?: boolean;
|
|
4
|
+
};
|
|
5
|
+
export declare function useBluetoothEvent<EventName extends BluetoothSdkEventName>(eventName: EventName, listener: BluetoothSdkEventListener<EventName>, options?: UseBluetoothEventOptions): void;
|
|
6
|
+
//# sourceMappingURL=useBluetoothEvent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useBluetoothEvent.d.ts","sourceRoot":"","sources":["../../src/react/useBluetoothEvent.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,yBAAyB,EACzB,qBAAqB,EACtB,MAAM,uBAAuB,CAAA;AAE9B,MAAM,MAAM,wBAAwB,GAAG;IACrC,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB,CAAA;AAED,wBAAgB,iBAAiB,CAAC,SAAS,SAAS,qBAAqB,EACvE,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,yBAAyB,CAAC,SAAS,CAAC,EAC9C,OAAO,GAAE,wBAA6B,GACrC,IAAI,CAqBN"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { useEffect, useRef } from "react";
|
|
2
|
+
import BluetoothSdk from "../index";
|
|
3
|
+
export function useBluetoothEvent(eventName, listener, options = {}) {
|
|
4
|
+
const enabled = options.enabled ?? true;
|
|
5
|
+
const listenerRef = useRef(listener);
|
|
6
|
+
useEffect(() => {
|
|
7
|
+
listenerRef.current = listener;
|
|
8
|
+
}, [listener]);
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
if (!enabled) {
|
|
11
|
+
return undefined;
|
|
12
|
+
}
|
|
13
|
+
const subscription = BluetoothSdk.addListener(eventName, (event) => {
|
|
14
|
+
listenerRef.current(event);
|
|
15
|
+
});
|
|
16
|
+
return () => {
|
|
17
|
+
subscription.remove();
|
|
18
|
+
};
|
|
19
|
+
}, [enabled, eventName]);
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=useBluetoothEvent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useBluetoothEvent.js","sourceRoot":"","sources":["../../src/react/useBluetoothEvent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAE,MAAM,EAAC,MAAM,OAAO,CAAA;AAEvC,OAAO,YAAY,MAAM,UAAU,CAAA;AAUnC,MAAM,UAAU,iBAAiB,CAC/B,SAAoB,EACpB,QAA8C,EAC9C,UAAoC,EAAE;IAEtC,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,IAAI,CAAA;IACvC,MAAM,WAAW,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAA;IAEpC,SAAS,CAAC,GAAG,EAAE;QACb,WAAW,CAAC,OAAO,GAAG,QAAQ,CAAA;IAChC,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAA;IAEd,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,SAAS,CAAA;QAClB,CAAC;QAED,MAAM,YAAY,GAAG,YAAY,CAAC,WAAW,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE;YACjE,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;QAC5B,CAAC,CAAC,CAAA;QAEF,OAAO,GAAG,EAAE;YACV,YAAY,CAAC,MAAM,EAAE,CAAA;QACvB,CAAC,CAAA;IACH,CAAC,EAAE,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC,CAAA;AAC1B,CAAC","sourcesContent":["import {useEffect, useRef} from \"react\"\n\nimport BluetoothSdk from \"../index\"\nimport type {\n BluetoothSdkEventListener,\n BluetoothSdkEventName,\n} from \"../BluetoothSdk.types\"\n\nexport type UseBluetoothEventOptions = {\n enabled?: boolean\n}\n\nexport function useBluetoothEvent<EventName extends BluetoothSdkEventName>(\n eventName: EventName,\n listener: BluetoothSdkEventListener<EventName>,\n options: UseBluetoothEventOptions = {},\n): void {\n const enabled = options.enabled ?? true\n const listenerRef = useRef(listener)\n\n useEffect(() => {\n listenerRef.current = listener\n }, [listener])\n\n useEffect(() => {\n if (!enabled) {\n return undefined\n }\n\n const subscription = BluetoothSdk.addListener(eventName, (event) => {\n listenerRef.current(event)\n })\n\n return () => {\n subscription.remove()\n }\n }, [enabled, eventName])\n}\n"]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Device, DeviceModel } from "../BluetoothSdk.types";
|
|
2
|
+
export type BluetoothScanDedupe = "id" | "name" | ((device: Device) => string);
|
|
3
|
+
export type UseBluetoothScanOptions = {
|
|
4
|
+
dedupe?: BluetoothScanDedupe;
|
|
5
|
+
model?: DeviceModel;
|
|
6
|
+
onError?: (error: unknown) => void;
|
|
7
|
+
timeoutMs?: number;
|
|
8
|
+
};
|
|
9
|
+
export type BluetoothScanHookResult = {
|
|
10
|
+
clearResults: () => void;
|
|
11
|
+
devices: Device[];
|
|
12
|
+
error: unknown | null;
|
|
13
|
+
model: DeviceModel;
|
|
14
|
+
scanning: boolean;
|
|
15
|
+
selectedDevice: Device | null;
|
|
16
|
+
selectDevice: (device: Device | null) => void;
|
|
17
|
+
setModel: (model: DeviceModel) => void;
|
|
18
|
+
startScan: (model?: DeviceModel) => Promise<Device[]>;
|
|
19
|
+
stopScan: () => Promise<void>;
|
|
20
|
+
};
|
|
21
|
+
export declare function useBluetoothScan(options?: UseBluetoothScanOptions): BluetoothScanHookResult;
|
|
22
|
+
//# sourceMappingURL=useBluetoothScan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useBluetoothScan.d.ts","sourceRoot":"","sources":["../../src/react/useBluetoothScan.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,MAAM,EAAE,WAAW,EAAC,MAAM,uBAAuB,CAAA;AAE9D,MAAM,MAAM,mBAAmB,GAAG,IAAI,GAAG,MAAM,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAAC,CAAA;AAE9E,MAAM,MAAM,uBAAuB,GAAG;IACpC,MAAM,CAAC,EAAE,mBAAmB,CAAA;IAC5B,KAAK,CAAC,EAAE,WAAW,CAAA;IACnB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;IAClC,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,uBAAuB,GAAG;IACpC,YAAY,EAAE,MAAM,IAAI,CAAA;IACxB,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,KAAK,EAAE,OAAO,GAAG,IAAI,CAAA;IACrB,KAAK,EAAE,WAAW,CAAA;IAClB,QAAQ,EAAE,OAAO,CAAA;IACjB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAA;IAC7C,QAAQ,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAA;IACtC,SAAS,EAAE,CAAC,KAAK,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;IACrD,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC9B,CAAA;AAoCD,wBAAgB,gBAAgB,CAAC,OAAO,GAAE,uBAA4B,GAAG,uBAAuB,CA+G/F"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { useEffect, useRef, useState } from "react";
|
|
2
|
+
import BluetoothSdk, { DeviceModels } from "../index";
|
|
3
|
+
function dedupeKey(device, dedupe) {
|
|
4
|
+
if (typeof dedupe === "function") {
|
|
5
|
+
return dedupe(device);
|
|
6
|
+
}
|
|
7
|
+
if (dedupe === "name") {
|
|
8
|
+
return `${device.model}:${device.name}`;
|
|
9
|
+
}
|
|
10
|
+
return device.id;
|
|
11
|
+
}
|
|
12
|
+
function dedupeDevices(devices, dedupe) {
|
|
13
|
+
const seen = new Set();
|
|
14
|
+
const nextDevices = [];
|
|
15
|
+
devices.forEach((device) => {
|
|
16
|
+
const key = dedupeKey(device, dedupe);
|
|
17
|
+
if (seen.has(key)) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
seen.add(key);
|
|
21
|
+
nextDevices.push(device);
|
|
22
|
+
});
|
|
23
|
+
return nextDevices;
|
|
24
|
+
}
|
|
25
|
+
function hasDevice(devices, selectedDevice, dedupe) {
|
|
26
|
+
if (!selectedDevice) {
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
const selectedKey = dedupeKey(selectedDevice, dedupe);
|
|
30
|
+
return devices.some((device) => dedupeKey(device, dedupe) === selectedKey);
|
|
31
|
+
}
|
|
32
|
+
export function useBluetoothScan(options = {}) {
|
|
33
|
+
const [devices, setDevices] = useState([]);
|
|
34
|
+
const [error, setError] = useState(null);
|
|
35
|
+
const [model, setModelState] = useState(options.model ?? DeviceModels.MentraLive);
|
|
36
|
+
const [scanning, setScanning] = useState(false);
|
|
37
|
+
const [selectedDevice, selectDevice] = useState(null);
|
|
38
|
+
const activeScanRef = useRef(0);
|
|
39
|
+
const dedupeRef = useRef(options.dedupe ?? "id");
|
|
40
|
+
const onErrorRef = useRef(options.onError);
|
|
41
|
+
const scanningRef = useRef(false);
|
|
42
|
+
const timeoutMsRef = useRef(options.timeoutMs);
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
dedupeRef.current = options.dedupe ?? "id";
|
|
45
|
+
onErrorRef.current = options.onError;
|
|
46
|
+
timeoutMsRef.current = options.timeoutMs;
|
|
47
|
+
}, [options.dedupe, options.onError, options.timeoutMs]);
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
scanningRef.current = scanning;
|
|
50
|
+
}, [scanning]);
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
if (!hasDevice(devices, selectedDevice, dedupeRef.current)) {
|
|
53
|
+
selectDevice(null);
|
|
54
|
+
}
|
|
55
|
+
}, [devices, selectedDevice]);
|
|
56
|
+
useEffect(() => {
|
|
57
|
+
return () => {
|
|
58
|
+
if (!scanningRef.current) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
activeScanRef.current += 1;
|
|
62
|
+
void BluetoothSdk.stopScan().catch(() => undefined);
|
|
63
|
+
};
|
|
64
|
+
}, []);
|
|
65
|
+
function clearResults() {
|
|
66
|
+
setDevices([]);
|
|
67
|
+
selectDevice(null);
|
|
68
|
+
}
|
|
69
|
+
function setModel(nextModel) {
|
|
70
|
+
setModelState(nextModel);
|
|
71
|
+
clearResults();
|
|
72
|
+
}
|
|
73
|
+
async function startScan(nextModel) {
|
|
74
|
+
const scanId = activeScanRef.current + 1;
|
|
75
|
+
activeScanRef.current = scanId;
|
|
76
|
+
const scanModel = nextModel ?? model;
|
|
77
|
+
if (nextModel && nextModel !== model) {
|
|
78
|
+
setModelState(nextModel);
|
|
79
|
+
}
|
|
80
|
+
setError(null);
|
|
81
|
+
setScanning(true);
|
|
82
|
+
scanningRef.current = true;
|
|
83
|
+
setDevices([]);
|
|
84
|
+
selectDevice(null);
|
|
85
|
+
try {
|
|
86
|
+
const nextDevices = await BluetoothSdk.scan(scanModel, {
|
|
87
|
+
...(timeoutMsRef.current == null ? {} : { timeoutMs: timeoutMsRef.current }),
|
|
88
|
+
onResults: (results) => {
|
|
89
|
+
if (activeScanRef.current !== scanId) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
setDevices(dedupeDevices(results, dedupeRef.current));
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
const finalDevices = dedupeDevices(nextDevices, dedupeRef.current);
|
|
96
|
+
if (activeScanRef.current === scanId) {
|
|
97
|
+
setDevices(finalDevices);
|
|
98
|
+
setError(null);
|
|
99
|
+
}
|
|
100
|
+
return finalDevices;
|
|
101
|
+
}
|
|
102
|
+
catch (nextError) {
|
|
103
|
+
if (activeScanRef.current === scanId) {
|
|
104
|
+
setError(nextError);
|
|
105
|
+
onErrorRef.current?.(nextError);
|
|
106
|
+
}
|
|
107
|
+
throw nextError;
|
|
108
|
+
}
|
|
109
|
+
finally {
|
|
110
|
+
if (activeScanRef.current === scanId) {
|
|
111
|
+
setScanning(false);
|
|
112
|
+
scanningRef.current = false;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
async function stopScan() {
|
|
117
|
+
activeScanRef.current += 1;
|
|
118
|
+
setScanning(false);
|
|
119
|
+
scanningRef.current = false;
|
|
120
|
+
await BluetoothSdk.stopScan();
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
clearResults,
|
|
124
|
+
devices,
|
|
125
|
+
error,
|
|
126
|
+
model,
|
|
127
|
+
scanning,
|
|
128
|
+
selectedDevice,
|
|
129
|
+
selectDevice,
|
|
130
|
+
setModel,
|
|
131
|
+
startScan,
|
|
132
|
+
stopScan,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=useBluetoothScan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useBluetoothScan.js","sourceRoot":"","sources":["../../src/react/useBluetoothScan.ts"],"names":[],"mappings":"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","sourcesContent":["import {useEffect, useRef, useState} from \"react\"\n\nimport BluetoothSdk, {DeviceModels} from \"../index\"\nimport type {Device, DeviceModel} from \"../BluetoothSdk.types\"\n\nexport type BluetoothScanDedupe = \"id\" | \"name\" | ((device: Device) => string)\n\nexport type UseBluetoothScanOptions = {\n dedupe?: BluetoothScanDedupe\n model?: DeviceModel\n onError?: (error: unknown) => void\n timeoutMs?: number\n}\n\nexport type BluetoothScanHookResult = {\n clearResults: () => void\n devices: Device[]\n error: unknown | null\n model: DeviceModel\n scanning: boolean\n selectedDevice: Device | null\n selectDevice: (device: Device | null) => void\n setModel: (model: DeviceModel) => void\n startScan: (model?: DeviceModel) => Promise<Device[]>\n stopScan: () => Promise<void>\n}\n\nfunction dedupeKey(device: Device, dedupe: BluetoothScanDedupe): string {\n if (typeof dedupe === \"function\") {\n return dedupe(device)\n }\n if (dedupe === \"name\") {\n return `${device.model}:${device.name}`\n }\n return device.id\n}\n\nfunction dedupeDevices(devices: Device[], dedupe: BluetoothScanDedupe): Device[] {\n const seen = new Set<string>()\n const nextDevices: Device[] = []\n\n devices.forEach((device) => {\n const key = dedupeKey(device, dedupe)\n if (seen.has(key)) {\n return\n }\n seen.add(key)\n nextDevices.push(device)\n })\n\n return nextDevices\n}\n\nfunction hasDevice(devices: Device[], selectedDevice: Device | null, dedupe: BluetoothScanDedupe): boolean {\n if (!selectedDevice) {\n return true\n }\n const selectedKey = dedupeKey(selectedDevice, dedupe)\n return devices.some((device) => dedupeKey(device, dedupe) === selectedKey)\n}\n\nexport function useBluetoothScan(options: UseBluetoothScanOptions = {}): BluetoothScanHookResult {\n const [devices, setDevices] = useState<Device[]>([])\n const [error, setError] = useState<unknown | null>(null)\n const [model, setModelState] = useState<DeviceModel>(options.model ?? DeviceModels.MentraLive)\n const [scanning, setScanning] = useState(false)\n const [selectedDevice, selectDevice] = useState<Device | null>(null)\n const activeScanRef = useRef(0)\n const dedupeRef = useRef<BluetoothScanDedupe>(options.dedupe ?? \"id\")\n const onErrorRef = useRef(options.onError)\n const scanningRef = useRef(false)\n const timeoutMsRef = useRef(options.timeoutMs)\n\n useEffect(() => {\n dedupeRef.current = options.dedupe ?? \"id\"\n onErrorRef.current = options.onError\n timeoutMsRef.current = options.timeoutMs\n }, [options.dedupe, options.onError, options.timeoutMs])\n\n useEffect(() => {\n scanningRef.current = scanning\n }, [scanning])\n\n useEffect(() => {\n if (!hasDevice(devices, selectedDevice, dedupeRef.current)) {\n selectDevice(null)\n }\n }, [devices, selectedDevice])\n\n useEffect(() => {\n return () => {\n if (!scanningRef.current) {\n return\n }\n activeScanRef.current += 1\n void BluetoothSdk.stopScan().catch(() => undefined)\n }\n }, [])\n\n function clearResults() {\n setDevices([])\n selectDevice(null)\n }\n\n function setModel(nextModel: DeviceModel) {\n setModelState(nextModel)\n clearResults()\n }\n\n async function startScan(nextModel?: DeviceModel): Promise<Device[]> {\n const scanId = activeScanRef.current + 1\n activeScanRef.current = scanId\n const scanModel = nextModel ?? model\n if (nextModel && nextModel !== model) {\n setModelState(nextModel)\n }\n\n setError(null)\n setScanning(true)\n scanningRef.current = true\n setDevices([])\n selectDevice(null)\n\n try {\n const nextDevices = await BluetoothSdk.scan(scanModel, {\n ...(timeoutMsRef.current == null ? {} : {timeoutMs: timeoutMsRef.current}),\n onResults: (results) => {\n if (activeScanRef.current !== scanId) {\n return\n }\n setDevices(dedupeDevices(results, dedupeRef.current))\n },\n })\n const finalDevices = dedupeDevices(nextDevices, dedupeRef.current)\n if (activeScanRef.current === scanId) {\n setDevices(finalDevices)\n setError(null)\n }\n return finalDevices\n } catch (nextError) {\n if (activeScanRef.current === scanId) {\n setError(nextError)\n onErrorRef.current?.(nextError)\n }\n throw nextError\n } finally {\n if (activeScanRef.current === scanId) {\n setScanning(false)\n scanningRef.current = false\n }\n }\n }\n\n async function stopScan() {\n activeScanRef.current += 1\n setScanning(false)\n scanningRef.current = false\n await BluetoothSdk.stopScan()\n }\n\n return {\n clearResults,\n devices,\n error,\n model,\n scanning,\n selectedDevice,\n selectDevice,\n setModel,\n startScan,\n stopScan,\n }\n}\n"]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { PublicBluetoothStatus, PublicGlassesStatus } from "../BluetoothSdk.types";
|
|
2
|
+
export type UseBluetoothStatusOptions = {
|
|
3
|
+
enabled?: boolean;
|
|
4
|
+
onError?: (error: unknown) => void;
|
|
5
|
+
};
|
|
6
|
+
export type BluetoothStatusHookResult = {
|
|
7
|
+
bluetoothStatus: Partial<PublicBluetoothStatus>;
|
|
8
|
+
connected: boolean;
|
|
9
|
+
error: unknown | null;
|
|
10
|
+
glassesStatus: Partial<PublicGlassesStatus>;
|
|
11
|
+
loading: boolean;
|
|
12
|
+
ready: boolean;
|
|
13
|
+
refresh: () => Promise<void>;
|
|
14
|
+
};
|
|
15
|
+
export declare function useBluetoothStatus(options?: UseBluetoothStatusOptions): BluetoothStatusHookResult;
|
|
16
|
+
//# sourceMappingURL=useBluetoothStatus.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useBluetoothStatus.d.ts","sourceRoot":"","sources":["../../src/react/useBluetoothStatus.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAIV,qBAAqB,EACrB,mBAAmB,EAGpB,MAAM,uBAAuB,CAAA;AAE9B,MAAM,MAAM,yBAAyB,GAAG;IACtC,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;CACnC,CAAA;AAED,MAAM,MAAM,yBAAyB,GAAG;IACtC,eAAe,EAAE,OAAO,CAAC,qBAAqB,CAAC,CAAA;IAC/C,SAAS,EAAE,OAAO,CAAA;IAClB,KAAK,EAAE,OAAO,GAAG,IAAI,CAAA;IACrB,aAAa,EAAE,OAAO,CAAC,mBAAmB,CAAC,CAAA;IAC3C,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,OAAO,CAAA;IACd,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC7B,CAAA;AAiCD,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,yBAA8B,GAAG,yBAAyB,CAmHrG"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { useEffect, useRef, useState } from "react";
|
|
2
|
+
import BluetoothSdk from "../index";
|
|
3
|
+
import { createDisconnectedGlassesStatus, isConnectedGlassesConnectionStatus, isReadyGlassesConnectionStatus, } from "../BluetoothSdk.types";
|
|
4
|
+
function wifiStatusFromEvent(event) {
|
|
5
|
+
switch (event.state) {
|
|
6
|
+
case "connected":
|
|
7
|
+
return { state: "connected", ssid: event.ssid, localIp: event.localIp };
|
|
8
|
+
case "disconnected":
|
|
9
|
+
return { state: "disconnected" };
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
function hotspotStatusFromEvent(event) {
|
|
13
|
+
if (event.state === "enabled") {
|
|
14
|
+
return {
|
|
15
|
+
state: "enabled",
|
|
16
|
+
ssid: event.ssid,
|
|
17
|
+
password: event.password,
|
|
18
|
+
localIp: event.localIp,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
return { state: event.state };
|
|
22
|
+
}
|
|
23
|
+
function mergeGlassesStatus(current, changed) {
|
|
24
|
+
if (changed.connection?.state === "disconnected") {
|
|
25
|
+
return { ...createDisconnectedGlassesStatus(), ...changed };
|
|
26
|
+
}
|
|
27
|
+
return { ...current, ...changed };
|
|
28
|
+
}
|
|
29
|
+
export function useBluetoothStatus(options = {}) {
|
|
30
|
+
const enabled = options.enabled ?? true;
|
|
31
|
+
const onErrorRef = useRef(options.onError);
|
|
32
|
+
const [bluetoothStatus, setBluetoothStatus] = useState({});
|
|
33
|
+
const [error, setError] = useState(null);
|
|
34
|
+
const [glassesStatus, setGlassesStatus] = useState(() => createDisconnectedGlassesStatus());
|
|
35
|
+
const [loading, setLoading] = useState(enabled);
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
onErrorRef.current = options.onError;
|
|
38
|
+
}, [options.onError]);
|
|
39
|
+
async function refresh() {
|
|
40
|
+
setLoading(true);
|
|
41
|
+
try {
|
|
42
|
+
const [nextGlassesStatus, nextBluetoothStatus] = await Promise.all([
|
|
43
|
+
BluetoothSdk.getGlassesStatus(),
|
|
44
|
+
BluetoothSdk.getBluetoothStatus(),
|
|
45
|
+
]);
|
|
46
|
+
setGlassesStatus(nextGlassesStatus);
|
|
47
|
+
setBluetoothStatus(nextBluetoothStatus);
|
|
48
|
+
setError(null);
|
|
49
|
+
}
|
|
50
|
+
catch (nextError) {
|
|
51
|
+
setError(nextError);
|
|
52
|
+
onErrorRef.current?.(nextError);
|
|
53
|
+
}
|
|
54
|
+
finally {
|
|
55
|
+
setLoading(false);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
if (!enabled) {
|
|
60
|
+
setLoading(false);
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
let mounted = true;
|
|
64
|
+
const loadInitialStatus = async () => {
|
|
65
|
+
setLoading(true);
|
|
66
|
+
try {
|
|
67
|
+
const [nextGlassesStatus, nextBluetoothStatus] = await Promise.all([
|
|
68
|
+
BluetoothSdk.getGlassesStatus(),
|
|
69
|
+
BluetoothSdk.getBluetoothStatus(),
|
|
70
|
+
]);
|
|
71
|
+
if (!mounted) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
setGlassesStatus(nextGlassesStatus);
|
|
75
|
+
setBluetoothStatus(nextBluetoothStatus);
|
|
76
|
+
setError(null);
|
|
77
|
+
}
|
|
78
|
+
catch (nextError) {
|
|
79
|
+
if (!mounted) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
setError(nextError);
|
|
83
|
+
onErrorRef.current?.(nextError);
|
|
84
|
+
}
|
|
85
|
+
finally {
|
|
86
|
+
if (mounted) {
|
|
87
|
+
setLoading(false);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
void loadInitialStatus();
|
|
92
|
+
const removeGlasses = BluetoothSdk.onGlassesStatus((changed) => {
|
|
93
|
+
setGlassesStatus((current) => mergeGlassesStatus(current, changed));
|
|
94
|
+
});
|
|
95
|
+
const removeBluetooth = BluetoothSdk.onBluetoothStatus((changed) => {
|
|
96
|
+
setBluetoothStatus((current) => ({ ...current, ...changed }));
|
|
97
|
+
});
|
|
98
|
+
const batterySubscription = BluetoothSdk.addListener("battery_status", (event) => {
|
|
99
|
+
setGlassesStatus((current) => ({
|
|
100
|
+
...current,
|
|
101
|
+
batteryLevel: event.level,
|
|
102
|
+
charging: event.charging,
|
|
103
|
+
}));
|
|
104
|
+
});
|
|
105
|
+
const wifiSubscription = BluetoothSdk.addListener("wifi_status_change", (event) => {
|
|
106
|
+
setGlassesStatus((current) => ({ ...current, wifi: wifiStatusFromEvent(event) }));
|
|
107
|
+
});
|
|
108
|
+
const hotspotSubscription = BluetoothSdk.addListener("hotspot_status_change", (event) => {
|
|
109
|
+
setGlassesStatus((current) => ({ ...current, hotspot: hotspotStatusFromEvent(event) }));
|
|
110
|
+
});
|
|
111
|
+
const hotspotErrorSubscription = BluetoothSdk.addListener("hotspot_error", () => {
|
|
112
|
+
setGlassesStatus((current) => ({ ...current, hotspot: { state: "disabled" } }));
|
|
113
|
+
});
|
|
114
|
+
return () => {
|
|
115
|
+
mounted = false;
|
|
116
|
+
removeGlasses();
|
|
117
|
+
removeBluetooth();
|
|
118
|
+
batterySubscription.remove();
|
|
119
|
+
wifiSubscription.remove();
|
|
120
|
+
hotspotSubscription.remove();
|
|
121
|
+
hotspotErrorSubscription.remove();
|
|
122
|
+
};
|
|
123
|
+
}, [enabled]);
|
|
124
|
+
const connection = glassesStatus.connection;
|
|
125
|
+
const connected = connection ? isConnectedGlassesConnectionStatus(connection) : false;
|
|
126
|
+
const ready = connection ? isReadyGlassesConnectionStatus(connection) : false;
|
|
127
|
+
return {
|
|
128
|
+
bluetoothStatus,
|
|
129
|
+
connected,
|
|
130
|
+
error,
|
|
131
|
+
glassesStatus,
|
|
132
|
+
loading,
|
|
133
|
+
ready,
|
|
134
|
+
refresh,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=useBluetoothStatus.js.map
|