@mentra/bluetooth-sdk 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/README.md +75 -19
  2. package/android/src/main/java/com/mentra/bluetoothsdk/BluetoothSdkModule.kt +13 -13
  3. package/android/src/main/java/com/mentra/bluetoothsdk/Bridge.kt +42 -18
  4. package/android/src/main/java/com/mentra/bluetoothsdk/DeviceManager.kt +19 -21
  5. package/android/src/main/java/com/mentra/bluetoothsdk/DeviceStore.kt +4 -4
  6. package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothModels.kt +118 -103
  7. package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothSdk.kt +110 -38
  8. package/android/src/main/java/com/mentra/bluetoothsdk/controllers/ControllerManager.kt +4 -4
  9. package/android/src/main/java/com/mentra/bluetoothsdk/controllers/R1.kt +2 -2
  10. package/android/src/main/java/com/mentra/bluetoothsdk/services/PhoneMic.kt +6 -6
  11. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G1.java +1 -1
  12. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G2.kt +3 -3
  13. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Mach1.java +1 -1
  14. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraLive.java +18 -18
  15. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraNex.kt +1 -1
  16. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/SGCManager.kt +4 -4
  17. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Simulated.kt +2 -2
  18. package/android/src/main/java/com/mentra/bluetoothsdk/utils/Constants.kt +6 -6
  19. package/app.plugin.js +3 -1
  20. package/build/BluetoothSdk.types.d.ts +126 -27
  21. package/build/BluetoothSdk.types.d.ts.map +1 -1
  22. package/build/BluetoothSdk.types.js.map +1 -1
  23. package/build/_internal.d.ts +12 -0
  24. package/build/_internal.d.ts.map +1 -0
  25. package/build/_internal.js +11 -0
  26. package/build/_internal.js.map +1 -0
  27. package/build/{BluetoothSdkModule.d.ts → _private/BluetoothSdkModule.d.ts} +19 -8
  28. package/build/_private/BluetoothSdkModule.d.ts.map +1 -0
  29. package/build/{BluetoothSdkModule.js → _private/BluetoothSdkModule.js} +41 -26
  30. package/build/_private/BluetoothSdkModule.js.map +1 -0
  31. package/build/index.d.ts +4 -2
  32. package/build/index.d.ts.map +1 -1
  33. package/build/index.js +3 -4
  34. package/build/index.js.map +1 -1
  35. package/build/react/index.d.ts +5 -0
  36. package/build/react/index.d.ts.map +1 -0
  37. package/build/react/index.js +5 -0
  38. package/build/react/index.js.map +1 -0
  39. package/build/react/useBluetoothEvent.d.ts +6 -0
  40. package/build/react/useBluetoothEvent.d.ts.map +1 -0
  41. package/build/react/useBluetoothEvent.js +21 -0
  42. package/build/react/useBluetoothEvent.js.map +1 -0
  43. package/build/react/useBluetoothScan.d.ts +22 -0
  44. package/build/react/useBluetoothScan.d.ts.map +1 -0
  45. package/build/react/useBluetoothScan.js +135 -0
  46. package/build/react/useBluetoothScan.js.map +1 -0
  47. package/build/react/useBluetoothStatus.d.ts +16 -0
  48. package/build/react/useBluetoothStatus.d.ts.map +1 -0
  49. package/build/react/useBluetoothStatus.js +137 -0
  50. package/build/react/useBluetoothStatus.js.map +1 -0
  51. package/build/react/useGlassesConnection.d.ts +29 -0
  52. package/build/react/useGlassesConnection.d.ts.map +1 -0
  53. package/build/react/useGlassesConnection.js +140 -0
  54. package/build/react/useGlassesConnection.js.map +1 -0
  55. package/ios/BluetoothSdkModule.swift +14 -9
  56. package/ios/Source/Bridge.swift +44 -12
  57. package/ios/Source/DeviceManager.swift +27 -26
  58. package/ios/Source/DeviceStore.swift +4 -4
  59. package/ios/Source/MentraBluetoothSDK.swift +250 -132
  60. package/ios/Source/controllers/ControllerManager.swift +5 -5
  61. package/ios/Source/controllers/R1.swift +3 -3
  62. package/ios/Source/services/PhoneMic.swift +5 -5
  63. package/ios/Source/sgcs/Frame.swift +1 -1
  64. package/ios/Source/sgcs/G1.swift +1 -1
  65. package/ios/Source/sgcs/G2.swift +3 -3
  66. package/ios/Source/sgcs/Mach1.swift +1 -1
  67. package/ios/Source/sgcs/MentraLive.swift +31 -33
  68. package/ios/Source/sgcs/MentraNex.swift +2 -2
  69. package/ios/Source/sgcs/SGCManager.swift +5 -5
  70. package/ios/Source/sgcs/Simulated.swift +3 -3
  71. package/ios/Source/utils/Constants.swift +6 -6
  72. package/ios/Source/utils/JSCExperiment.swift +8 -8
  73. package/ios/Source/utils/TarBz2Extractor.swift +2 -2
  74. package/package.json +19 -1
  75. package/src/BluetoothSdk.types.ts +186 -28
  76. package/src/_internal.ts +11 -0
  77. package/src/{BluetoothSdkModule.ts → _private/BluetoothSdkModule.ts} +71 -38
  78. package/src/index.ts +80 -4
  79. package/src/react/index.ts +22 -0
  80. package/src/react/useBluetoothEvent.ts +38 -0
  81. package/src/react/useBluetoothScan.ts +173 -0
  82. package/src/react/useBluetoothStatus.ts +180 -0
  83. package/src/react/useGlassesConnection.ts +194 -0
  84. package/build/BluetoothSdkModule.d.ts.map +0 -1
  85. package/build/BluetoothSdkModule.js.map +0 -1
@@ -6,13 +6,22 @@ const DEFAULT_CONNECT_OPTIONS = {
6
6
  saveAsDefault: true,
7
7
  cancelExistingConnectionAttempt: true,
8
8
  };
9
- const DEFAULT_CONNECT_FIRST_TIMEOUT_MS = 15_000;
9
+ const DEFAULT_SCAN_TIMEOUT_MS = 15_000;
10
10
  const CAMERA_FOV_SETTINGS = {
11
- standard: { fov: 118, roi_position: 0 },
12
- wide: { fov: 118, roi_position: 0 },
11
+ standard: { fov: 118, roiPosition: 0 },
12
+ wide: { fov: 118, roiPosition: 0 },
13
13
  };
14
- function findSearchResult(status, model) {
15
- return status.searchResults?.find((device) => device.model === model) ?? null;
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, fps) {
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: 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.connectFirst = async function (model, options) {
175
- const { timeoutMs = DEFAULT_CONNECT_FIRST_TIMEOUT_MS, ...connectOptions } = options ?? {};
176
- const device = await new Promise((resolve, reject) => {
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, result) => {
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 if (result) {
196
- resolve(result);
214
+ else {
215
+ resolve([...latestResults]);
197
216
  }
198
217
  };
199
218
  const handleBluetoothStatus = (status) => {
200
- const result = findSearchResult(status, model);
201
- if (result) {
202
- settle(null, result);
203
- }
219
+ emitResults(searchResultsForModel(status, scanOptions.model));
204
220
  };
205
221
  removeBluetoothListener = this.onBluetoothStatus(handleBluetoothStatus);
206
- if (Number.isFinite(timeoutMs) && timeoutMs > 0) {
207
- timeout = setTimeout(() => {
208
- settle(new Error(`Timed out after ${timeoutMs}ms while scanning for ${model}.`));
209
- }, timeoutMs);
210
- }
211
- Promise.resolve(this.startScan(model))
212
- .then(() => this.getBluetoothStatus())
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
- export { default } from "./BluetoothSdkModule";
2
- 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";
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
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAC,OAAO,EAAC,MAAM,sBAAsB,CAAA;AAC5C,cAAc,sBAAsB,CAAA"}
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
- // Reexport the native module. On web, it will be resolved to BluetoothSdkModule.web.ts
2
- // and on native platforms to BluetoothSdkModule.ts
3
- export { default } from "./BluetoothSdkModule";
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
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,uFAAuF;AACvF,mDAAmD;AACnD,OAAO,EAAC,OAAO,EAAC,MAAM,sBAAsB,CAAA;AAC5C,cAAc,sBAAsB,CAAA","sourcesContent":["// Reexport the native module. On web, it will be resolved to BluetoothSdkModule.web.ts\n// and on native platforms to BluetoothSdkModule.ts\nexport {default} from \"./BluetoothSdkModule\"\nexport * from \"./BluetoothSdk.types\"\n"]}
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