@mentra/bluetooth-sdk 0.1.13 → 0.1.16
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 +18 -8
- package/android/src/main/java/com/mentra/bluetoothsdk/BluetoothSdkModule.kt +48 -48
- package/android/src/main/java/com/mentra/bluetoothsdk/Bridge.kt +5 -20
- package/android/src/main/java/com/mentra/bluetoothsdk/DeviceManager.kt +360 -269
- package/android/src/main/java/com/mentra/bluetoothsdk/DeviceStore.kt +3 -7
- package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothSdk.kt +152 -72
- package/android/src/main/java/com/mentra/bluetoothsdk/OtaManifest.kt +12 -12
- package/android/src/main/java/com/mentra/bluetoothsdk/camera/CameraModels.kt +25 -11
- package/android/src/main/java/com/mentra/bluetoothsdk/controllers/ControllerManager.kt +1 -2
- package/android/src/main/java/com/mentra/bluetoothsdk/controllers/R1.kt +1 -2
- package/android/src/main/java/com/mentra/bluetoothsdk/events/BluetoothEvents.kt +1 -22
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G1.kt +51 -8
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G2.kt +1184 -800
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Mach1.kt +1 -5
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraLive.kt +423 -117
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraNex.kt +4 -6
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Nimo.kt +2532 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/SGCManager.kt +17 -5
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Simulated.kt +3 -7
- package/android/src/main/java/com/mentra/bluetoothsdk/status/DeviceStatus.kt +0 -6
- package/android/src/main/java/com/mentra/bluetoothsdk/streaming/StreamModels.kt +16 -33
- package/android/src/main/java/com/mentra/bluetoothsdk/types/DeviceModels.kt +5 -3
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/Constants.kt +2 -1
- package/android/src/test/java/com/mentra/bluetoothsdk/camera/PhotoRequestTest.kt +60 -1
- package/android/src/test/java/com/mentra/bluetoothsdk/sgcs/NimoProtocolTest.kt +333 -0
- package/build/BluetoothSdk.types.d.ts +50 -24
- package/build/BluetoothSdk.types.d.ts.map +1 -1
- package/build/BluetoothSdk.types.js +1 -0
- package/build/BluetoothSdk.types.js.map +1 -1
- package/build/_internal.d.ts +4 -4
- package/build/_internal.js +4 -4
- package/build/_internal.js.map +1 -1
- package/build/_private/BluetoothSdkModule.d.ts +14 -8
- package/build/_private/BluetoothSdkModule.d.ts.map +1 -1
- package/build/_private/BluetoothSdkModule.js +4 -3
- package/build/_private/BluetoothSdkModule.js.map +1 -1
- package/build/_private/cameraRequestPayload.d.ts +4 -0
- package/build/_private/cameraRequestPayload.d.ts.map +1 -0
- package/build/_private/cameraRequestPayload.js +25 -0
- package/build/_private/cameraRequestPayload.js.map +1 -0
- package/build/_private/photoRequestPayload.d.ts.map +1 -1
- package/build/_private/photoRequestPayload.js +11 -3
- package/build/_private/photoRequestPayload.js.map +1 -1
- package/build/index.d.ts +1 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js +70 -61
- package/build/index.js.map +1 -1
- package/ios/BluetoothSdkModule.swift +51 -28
- package/ios/Source/Bridge.swift +4 -16
- package/ios/Source/DeviceManager.swift +76 -22
- package/ios/Source/DeviceStore.swift +0 -4
- package/ios/Source/MentraBluetoothSDK.swift +144 -78
- package/ios/Source/OtaManifest.swift +13 -13
- package/ios/Source/camera/CameraModels.swift +82 -20
- package/ios/Source/controllers/ControllerManager.swift +1 -2
- package/ios/Source/controllers/R1.swift +1 -2
- package/ios/Source/errors/{BluetoothError.swift → BluetoothSdkError.swift} +1 -1
- package/ios/Source/events/BluetoothEvents.swift +5 -27
- package/ios/Source/internal/BluetoothAvailability.swift +5 -5
- package/ios/Source/sgcs/Frame.swift +0 -2
- package/ios/Source/sgcs/G1.swift +52 -4
- package/ios/Source/sgcs/G2.swift +643 -204
- package/ios/Source/sgcs/Mach1.swift +1 -3
- package/ios/Source/sgcs/MentraLive.swift +64 -77
- package/ios/Source/sgcs/MentraNex.swift +1 -3
- package/ios/Source/sgcs/Nimo.swift +1928 -0
- package/ios/Source/sgcs/SGCManager.swift +16 -10
- package/ios/Source/sgcs/Simulated.swift +2 -6
- package/ios/Source/status/DeviceStatus.swift +0 -8
- package/ios/Source/streaming/StreamModels.swift +7 -32
- package/ios/Source/stt/STTTools.swift +1 -1
- package/ios/Source/types/DeviceModels.swift +5 -0
- package/ios/Source/utils/Constants.swift +2 -0
- package/package.json +6 -1
- package/src/BluetoothSdk.types.ts +54 -28
- package/src/_internal.ts +4 -4
- package/src/_private/BluetoothSdkModule.ts +20 -11
- package/src/_private/cameraRequestPayload.ts +29 -0
- package/src/_private/photoRequestPayload.ts +12 -3
- package/src/index.ts +77 -67
package/README.md
CHANGED
|
@@ -315,7 +315,7 @@ console.log(ledAck.state)
|
|
|
315
315
|
Settings commands that return `SettingsAckSuccessEvent` reject when the ASG reports an error ack. The SDK updates its local settings store only after that ASG ack resolves successfully, so observed SDK state reflects the acknowledged glasses state rather than a queued request. Raw `settings_ack` listener events still use `SettingsAckEvent` because they can include both success and failure statuses. `rgbLedControl(...)` resolves from a successful ASG `rgb_led_control_response` and rejects when the ASG reports `state: "error"`; raw `settings_ack` and `rgb_led_control_response` events remain available through listeners.
|
|
316
316
|
|
|
317
317
|
WiFi, hotspot, and version-info commands resolve from the ASG response path, not local dispatch:
|
|
318
|
-
`requestWifiScan()` resolves from the ASG `wifi_scan_result` completion response with the updated scan list, including `[]` when no networks are found. Intermediate `wifi_scan_result` events can arrive with `scanComplete: false` while the glasses stream discovered networks; the final event uses `scanComplete: true`. `sendWifiCredentials()` resolves when the requested SSID is connected, `forgetWifiNetwork()` resolves when that SSID is no longer connected, `setHotspotState()` resolves when the requested hotspot state is reported, and `requestVersionInfo()` resolves from the ASG `version_info` response instead of local store changes.
|
|
318
|
+
`requestWifiScan()` resolves from the ASG `wifi_scan_result` completion response with the updated scan list, including `[]` when no networks are found. Intermediate `wifi_scan_result` events can arrive with `scanComplete: false` while the glasses stream discovered networks; the final event uses `scanComplete: true`. If older glasses stream non-empty scan results but never send the completion event, the request resolves with the accumulated scan list when the request times out. `sendWifiCredentials()` resolves when the requested SSID is connected, `forgetWifiNetwork()` resolves when that SSID is no longer connected, `setHotspotState()` resolves when the requested hotspot state is reported, and `requestVersionInfo()` resolves from the ASG `version_info` response instead of local store changes.
|
|
319
319
|
|
|
320
320
|
React Native narrows returned values to success shapes where the raw listener event can also report errors:
|
|
321
321
|
|
|
@@ -327,7 +327,7 @@ React Native narrows returned values to success shapes where the raw listener ev
|
|
|
327
327
|
| `rgbLedControl(...)` | `RgbLedControlSuccessResponseEvent` with `state: "success"`. | Rejects when raw `rgb_led_control_response.state === "error"` or the response times out. |
|
|
328
328
|
| `checkForOtaUpdate()` | `boolean`, true when the configured OTA manifest has an ASG APK, MTK, or BES update for the connected glasses; false only when the manifest was checked successfully and no update is available. | Rejects when the glasses are disconnected, version info is unavailable, the manifest cannot be fetched, or the manifest response is invalid/missing required ASG app version fields. |
|
|
329
329
|
|
|
330
|
-
Android and iOS async APIs use `
|
|
330
|
+
Android and iOS async APIs use `BluetoothSdkException` / `BluetoothSdkError` for the same error paths. Their returned event structs are the successful response in normal `try`/`await` code, while raw listener/delegate events still include both success and error payloads.
|
|
331
331
|
|
|
332
332
|
`setMicState(true)` defaults to continuous microphone PCM from the glasses. The SDK does not apply phone-side Voice Activity Detection gating to microphone audio events. Glasses-side Voice Activity Detection is disabled by default for public SDK consumers; use `setVoiceActivityDetectionEnabled(true)` when you want supported glasses to gate microphone audio and emit live speaking status. `voice_activity_detection_status` reports whether glasses-side Voice Activity Detection is enabled, and `speaking_status` reports speaking/not-speaking when supported. Microphone events include the latest `voiceActivityDetectionEnabled` value.
|
|
333
333
|
|
|
@@ -369,8 +369,6 @@ OTA requires Mentra Live glasses firmware that supports the ASG OTA protocol and
|
|
|
369
369
|
|
|
370
370
|
```ts
|
|
371
371
|
const photo = await BluetoothSdk.requestPhoto({
|
|
372
|
-
requestId: `photo-${Date.now()}`,
|
|
373
|
-
appId: 'com.example.app',
|
|
374
372
|
size: 'medium',
|
|
375
373
|
webhookUrl: 'https://api.example.com/mentra/photo',
|
|
376
374
|
authToken: 'optional-token',
|
|
@@ -382,7 +380,7 @@ const photo = await BluetoothSdk.requestPhoto({
|
|
|
382
380
|
console.log('photo delivered', photo.photoUrl ?? photo.uploadUrl, photo.fileSizeBytes)
|
|
383
381
|
```
|
|
384
382
|
|
|
385
|
-
`requestPhoto(...)` resolves only after the full photo action reaches terminal success: capture completed and the photo was delivered to the webhook, either directly from the glasses over Wi-Fi or through the phone's Bluetooth fallback relay. It rejects if the ASG reports `state: "error"`, if phone-side fallback upload fails, if the SDK cannot send the command, or if no terminal `photo_response` arrives before the command timeout. Use `photo_status` for intermediate stages such as `accepted`, `configuring`, `capturing`, `captured`, `uploading`, `ble_fallback_compression`, `ready_for_transfer`, and `transferring`; `photo_status` is progress, while `photo_response` is terminal success/error. The raw `photo_response` event stream still includes both success and error events for subscribers. The webhook should accept multipart form data with a `photo` file and `requestId`. If `authToken` is provided, the uploader adds `Authorization: Bearer <token>`. The camera light is always enabled for photo capture.
|
|
383
|
+
`requestPhoto(...)` resolves only after the full photo action reaches terminal success: capture completed and the photo was delivered to the webhook, either directly from the glasses over Wi-Fi or through the phone's Bluetooth fallback relay. If you omit `requestId`, the SDK generates one and the terminal response includes it. It rejects if the ASG reports `state: "error"`, if phone-side fallback upload fails, if the SDK cannot send the command, or if no terminal `photo_response` arrives before the command timeout. Use `photo_status` for intermediate stages such as `accepted`, `configuring`, `capturing`, `captured`, `uploading`, `ble_fallback_compression`, `ready_for_transfer`, and `transferring`; `photo_status` is progress, while `photo_response` is terminal success/error. The raw `photo_response` event stream still includes both success and error events for subscribers. The webhook should accept multipart form data with a `photo` file and `requestId`. If `authToken` is provided, the uploader adds `Authorization: Bearer <token>`. The camera light is always enabled for photo capture.
|
|
386
384
|
|
|
387
385
|
For one-shot manual capture tuning, pass `exposureTimeNs` and `iso` together. `exposureTimeNs` is sensor exposure time in nanoseconds; `iso` is sensor ISO. If `exposureTimeNs` is omitted, `null`, invalid, or unsupported by the connected glasses, the camera uses auto exposure and ignores `iso`.
|
|
388
386
|
|
|
@@ -405,8 +403,8 @@ await BluetoothSdk.startStream({
|
|
|
405
403
|
await BluetoothSdk.stopStream()
|
|
406
404
|
```
|
|
407
405
|
|
|
408
|
-
Use `rtmp://` or `rtmps://` for RTMP, `srt://` for SRT, and `http://` or `https://` for WHIP/WebRTC ingest. `startStream()` resolves with the correlated `stream_status` event once the glasses report `status: "streaming"`; `stopStream()` resolves when the glasses report `status: "stopped"` or confirms the stream was already stopped / not streaming. `stopStream()` returns a normalized stopped event for that already-stopped case. Stream starts reject if the glasses report an error before streaming; stream stops reject for real stop errors, send failure, another stop in flight, or timeout. The SDK sends stream keep-alives automatically while streaming and reports keep-alive failures through `stream_status`. The camera light is always enabled while streaming.
|
|
409
|
-
`stream_status` events may include `resolvedConfig`, which reports the effective transport, video, and audio settings after glasses defaults, clamps, and camera preflight.
|
|
406
|
+
Use `rtmp://` or `rtmps://` for RTMP, `srt://` for SRT, and `http://` or `https://` for WHIP/WebRTC ingest. `startStream()` resolves with the correlated `stream_status` event once the glasses report `status: "streaming"`; `stopStream()` resolves when the glasses report `status: "stopped"` or confirms the stream was already stopped / not streaming. `stopStream()` returns a normalized stopped event for that already-stopped case. Stream starts reject if the glasses report an error before streaming; stream stops reject for real stop errors, send failure, another stop in flight, or timeout. Stream video input fields are `width`, `height`, `bitrate`, and `fps`. The SDK sends stream keep-alives automatically while streaming and reports keep-alive failures through `stream_status`. The camera light is always enabled while streaming.
|
|
407
|
+
`stream_status` events may include `resolvedConfig`, which reports the effective transport, video, and audio settings after glasses defaults, clamps, and camera preflight. The resolved effective frame rate is reported as `resolvedConfig.video.fps`.
|
|
410
408
|
|
|
411
409
|
## Events
|
|
412
410
|
|
|
@@ -459,13 +457,25 @@ MENTRA_BLUETOOTH_SDK_PACKAGE_PATH=/path/to/MentraOS/mobile/modules/bluetooth-sdk
|
|
|
459
457
|
|
|
460
458
|
Use `bunx expo run:android` for Android. Keep local paths in your shell or CI environment, not in committed app config.
|
|
461
459
|
|
|
460
|
+
For local Android source compile checks inside this monorepo, run from the
|
|
461
|
+
MentraOS repo root:
|
|
462
|
+
|
|
463
|
+
```sh
|
|
464
|
+
./scripts/check-android-compile.sh bluetooth-sdk
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
The `android/` folder in this package is source for the generated Expo Android
|
|
468
|
+
project, not the local Gradle entrypoint. The check script prepares
|
|
469
|
+
`mobile/android` and uses its Gradle wrapper with `-PmentraPublicSdk=true`,
|
|
470
|
+
matching the CI release workflow's public SDK dependency mode.
|
|
471
|
+
|
|
462
472
|
For bare native iOS apps, use the public SwiftPM repository:
|
|
463
473
|
|
|
464
474
|
```text
|
|
465
475
|
https://github.com/Mentra-Community/mentra-bluetooth-sdk-ios.git
|
|
466
476
|
```
|
|
467
477
|
|
|
468
|
-
Select version `0.1.
|
|
478
|
+
Select version `0.1.16`, then add the `MentraBluetoothSDK` product to your app target.
|
|
469
479
|
|
|
470
480
|
For local SDK development, add this package folder directly in Xcode:
|
|
471
481
|
|
|
@@ -116,6 +116,10 @@ class BluetoothSdkModule : Module() {
|
|
|
116
116
|
sendEvent("photo_status", event.values)
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
+
override fun onCameraStatus(event: CameraStatusEvent) {
|
|
120
|
+
sendEvent("camera_status", event.values)
|
|
121
|
+
}
|
|
122
|
+
|
|
119
123
|
override fun onVideoRecordingStatus(event: VideoRecordingStatusEvent) {
|
|
120
124
|
sendEvent("video_recording_status", event.values)
|
|
121
125
|
}
|
|
@@ -136,10 +140,6 @@ class BluetoothSdkModule : Module() {
|
|
|
136
140
|
sendEvent("keep_alive_ack", event.values)
|
|
137
141
|
}
|
|
138
142
|
|
|
139
|
-
override fun onOtaUpdateAvailable(event: OtaUpdateAvailableEvent) {
|
|
140
|
-
sendEvent("ota_update_available", event.values)
|
|
141
|
-
}
|
|
142
|
-
|
|
143
143
|
override fun onOtaStartAck(event: OtaStartAckEvent) {
|
|
144
144
|
sendEvent("ota_start_ack", event.values)
|
|
145
145
|
}
|
|
@@ -183,7 +183,7 @@ class BluetoothSdkModule : Module() {
|
|
|
183
183
|
|
|
184
184
|
private fun requireSdk(): MentraBluetoothSdk =
|
|
185
185
|
sdk
|
|
186
|
-
?: throw
|
|
186
|
+
?: throw BluetoothSdkException(
|
|
187
187
|
"sdk_not_initialized",
|
|
188
188
|
"Bluetooth SDK is not initialized.",
|
|
189
189
|
)
|
|
@@ -216,6 +216,7 @@ class BluetoothSdkModule : Module() {
|
|
|
216
216
|
"hotspot_error",
|
|
217
217
|
"photo_response",
|
|
218
218
|
"photo_status",
|
|
219
|
+
"camera_status",
|
|
219
220
|
"video_recording_status",
|
|
220
221
|
"media_success",
|
|
221
222
|
"media_error",
|
|
@@ -244,7 +245,6 @@ class BluetoothSdkModule : Module() {
|
|
|
244
245
|
"stream_status",
|
|
245
246
|
"keep_alive_ack",
|
|
246
247
|
"mtk_update_complete",
|
|
247
|
-
"ota_update_available",
|
|
248
248
|
"ota_progress",
|
|
249
249
|
"ota_start_ack",
|
|
250
250
|
"ota_status",
|
|
@@ -441,49 +441,16 @@ class BluetoothSdkModule : Module() {
|
|
|
441
441
|
sdk?.setVoiceActivityDetectionEnabled(enabled)
|
|
442
442
|
}
|
|
443
443
|
|
|
444
|
-
AsyncFunction("
|
|
445
|
-
|
|
446
|
-
val mfnr = params["mfnr"] as? Boolean
|
|
447
|
-
val zsl = params["zsl"] as? Boolean
|
|
448
|
-
val noiseReduction = params["noiseReduction"] as? Boolean
|
|
449
|
-
val edgeEnhancement = params["edgeEnhancement"] as? Boolean
|
|
450
|
-
val ispDigitalGain = (params["ispDigitalGain"] as? Number)?.toInt()
|
|
451
|
-
val ispAnalogGain = params["ispAnalogGain"] as? String
|
|
452
|
-
val aeExposureDivisor = (params["aeExposureDivisor"] as? Number)?.toInt()
|
|
453
|
-
val isoCap = (params["isoCap"] as? Number)?.toInt()
|
|
454
|
-
val compress = params["compress"] as? String
|
|
455
|
-
val sound = params["sound"] as? Boolean
|
|
456
|
-
val resetCaptureTuning = params["resetCaptureTuning"] as? Boolean == true
|
|
457
|
-
requireSdk()
|
|
458
|
-
.setButtonPhotoSettings(
|
|
459
|
-
ButtonPhotoSettings(
|
|
460
|
-
size = size,
|
|
461
|
-
mfnr = mfnr,
|
|
462
|
-
zsl = zsl,
|
|
463
|
-
noiseReduction = noiseReduction,
|
|
464
|
-
edgeEnhancement = edgeEnhancement,
|
|
465
|
-
ispDigitalGain = ispDigitalGain,
|
|
466
|
-
ispAnalogGain = ispAnalogGain,
|
|
467
|
-
aeExposureDivisor = aeExposureDivisor,
|
|
468
|
-
isoCap = isoCap,
|
|
469
|
-
compress = compress,
|
|
470
|
-
sound = sound,
|
|
471
|
-
resetCaptureTuning = resetCaptureTuning,
|
|
472
|
-
),
|
|
473
|
-
)
|
|
474
|
-
.values
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
AsyncFunction("setButtonVideoRecordingSettings") { width: Int, height: Int, fps: Int ->
|
|
478
|
-
requireSdk().setButtonVideoRecordingSettings(width, height, fps).values
|
|
444
|
+
AsyncFunction("setPhotoCaptureDefaults") { params: Map<String, Any?> ->
|
|
445
|
+
requireSdk().setPhotoCaptureDefaults(params.toPhotoCaptureDefaults()).values
|
|
479
446
|
}
|
|
480
447
|
|
|
481
|
-
AsyncFunction("
|
|
482
|
-
requireSdk().
|
|
448
|
+
AsyncFunction("setVideoRecordingDefaults") { width: Int, height: Int, fps: Int ->
|
|
449
|
+
requireSdk().setVideoRecordingDefaults(VideoRecordingDefaults(width, height, fps)).values
|
|
483
450
|
}
|
|
484
451
|
|
|
485
|
-
AsyncFunction("
|
|
486
|
-
requireSdk().
|
|
452
|
+
AsyncFunction("setMaxVideoRecordingDuration") { minutes: Int ->
|
|
453
|
+
requireSdk().setMaxVideoRecordingDuration(minutes).values
|
|
487
454
|
}
|
|
488
455
|
|
|
489
456
|
AsyncFunction("setCameraFov") { fov: Map<String, Any> ->
|
|
@@ -495,6 +462,10 @@ class BluetoothSdkModule : Module() {
|
|
|
495
462
|
requireSdk().setCameraFov(CameraFov(value, roiPosition)).values
|
|
496
463
|
}
|
|
497
464
|
|
|
465
|
+
AsyncFunction("setCameraTuningConfig") { anrOn: Boolean, gainOn: Boolean ->
|
|
466
|
+
requireSdk().setCameraTuningConfig(anrOn, gainOn).values
|
|
467
|
+
}
|
|
468
|
+
|
|
498
469
|
AsyncFunction("queryGalleryStatus") { requireSdk().queryGalleryStatus().values }
|
|
499
470
|
|
|
500
471
|
AsyncFunction("requestPhoto") { params: Map<String, Any?> ->
|
|
@@ -505,11 +476,22 @@ class BluetoothSdkModule : Module() {
|
|
|
505
476
|
}.toMap()
|
|
506
477
|
val req = PhotoRequest.fromMap(sanitized)
|
|
507
478
|
Bridge.log(
|
|
508
|
-
"NATIVE: PHOTO PIPELINE [3/6] BluetoothSdk.requestPhoto requestId=${req.requestId}
|
|
479
|
+
"NATIVE: PHOTO PIPELINE [3/6] BluetoothSdk.requestPhoto requestId=${req.requestId} size=${req.size} compress=${req.compress} sound=${req.sound} exposureTimeNs=${req.exposureTimeNs} iso=${req.iso}"
|
|
509
480
|
)
|
|
510
481
|
requireSdk().requestPhoto(req).values
|
|
511
482
|
}
|
|
512
483
|
|
|
484
|
+
AsyncFunction("warmUpCamera") { params: Map<String, Any?> ->
|
|
485
|
+
val requestId = params["requestId"] as? String
|
|
486
|
+
val size = PhotoSize.fromValue(params["size"] as? String)
|
|
487
|
+
val exposureRaw = (params["exposureTimeNs"] as? Number)?.toDouble()
|
|
488
|
+
val exposureTimeNs =
|
|
489
|
+
if (exposureRaw != null && exposureRaw.isFinite() && exposureRaw > 0) exposureRaw.toLong() else null
|
|
490
|
+
val durationRaw = (params["durationMs"] as? Number)?.toInt() ?: 0
|
|
491
|
+
val durationMs = if (durationRaw > 0) durationRaw else 15000
|
|
492
|
+
requireSdk().warmUpCamera(requestId, size, exposureTimeNs, durationMs).values
|
|
493
|
+
}
|
|
494
|
+
|
|
513
495
|
// MARK: - OTA Commands
|
|
514
496
|
|
|
515
497
|
Function("setOtaVersionUrl") { otaVersionUrl: String ->
|
|
@@ -535,8 +517,6 @@ class BluetoothSdkModule : Module() {
|
|
|
535
517
|
|
|
536
518
|
AsyncFunction("sendOtaQueryStatus") { requireSdk().sendOtaQueryStatus().values }
|
|
537
519
|
|
|
538
|
-
AsyncFunction("retryOtaVersionCheck") { requireSdk().retryOtaVersionCheck().values }
|
|
539
|
-
|
|
540
520
|
// MARK: - Version Info Commands
|
|
541
521
|
|
|
542
522
|
AsyncFunction("requestVersionInfo") { requireSdk().requestVersionInfo().toMap() }
|
|
@@ -586,6 +566,10 @@ class BluetoothSdkModule : Module() {
|
|
|
586
566
|
requireSdk().startStream(StreamRequest.fromMap(params)).values
|
|
587
567
|
}
|
|
588
568
|
|
|
569
|
+
AsyncFunction("startExternallyManagedStream") { params: Map<String, Any> ->
|
|
570
|
+
requireSdk().startExternallyManagedStream(StreamRequest.fromMap(params)).values
|
|
571
|
+
}
|
|
572
|
+
|
|
589
573
|
AsyncFunction("stopStream") { requireSdk().stopStream().values }
|
|
590
574
|
|
|
591
575
|
AsyncFunction("sendExternallyManagedStreamKeepAlive") { params: Map<String, Any> ->
|
|
@@ -775,6 +759,22 @@ private fun Map<String, Any>?.toMentraDevice(): Device? {
|
|
|
775
759
|
)
|
|
776
760
|
}
|
|
777
761
|
|
|
762
|
+
private fun Map<String, Any?>.toPhotoCaptureDefaults(): PhotoCaptureDefaults =
|
|
763
|
+
PhotoCaptureDefaults(
|
|
764
|
+
size = (this["size"] as? String)?.let { PhotoSize.fromValue(it) },
|
|
765
|
+
mfnr = this["mfnr"] as? Boolean,
|
|
766
|
+
zsl = this["zsl"] as? Boolean,
|
|
767
|
+
noiseReduction = this["noiseReduction"] as? Boolean,
|
|
768
|
+
edgeEnhancement = this["edgeEnhancement"] as? Boolean,
|
|
769
|
+
ispDigitalGain = (this["ispDigitalGain"] as? Number)?.toInt(),
|
|
770
|
+
ispAnalogGain = this["ispAnalogGain"] as? String,
|
|
771
|
+
aeExposureDivisor = (this["aeExposureDivisor"] as? Number)?.toInt(),
|
|
772
|
+
isoCap = (this["isoCap"] as? Number)?.toInt(),
|
|
773
|
+
compress = this["compress"] as? String,
|
|
774
|
+
sound = this["sound"] as? Boolean,
|
|
775
|
+
resetCaptureTuning = this["resetCaptureTuning"] as? Boolean == true,
|
|
776
|
+
)
|
|
777
|
+
|
|
778
778
|
private fun Map<String, Any>?.toMentraConnectOptions(): ConnectOptions {
|
|
779
779
|
val values = this ?: return ConnectOptions()
|
|
780
780
|
return ConnectOptions(
|
|
@@ -374,6 +374,11 @@ public class Bridge private constructor() {
|
|
|
374
374
|
sendTypedMessage("photo_status", statusJson)
|
|
375
375
|
}
|
|
376
376
|
|
|
377
|
+
@JvmStatic
|
|
378
|
+
fun sendCameraStatus(statusJson: Map<String, Any>) {
|
|
379
|
+
sendTypedMessage("camera_status", statusJson)
|
|
380
|
+
}
|
|
381
|
+
|
|
377
382
|
@JvmStatic
|
|
378
383
|
fun sendPhotoResponse(responseJson: Map<String, Any>) {
|
|
379
384
|
sendTypedMessage("photo_response", responseJson)
|
|
@@ -587,26 +592,6 @@ public class Bridge private constructor() {
|
|
|
587
592
|
sendTypedMessage("mtk_update_complete", eventBody as Map<String, Any>)
|
|
588
593
|
}
|
|
589
594
|
|
|
590
|
-
/**
|
|
591
|
-
* Send OTA update available notification - glasses have detected an available update
|
|
592
|
-
* (background mode)
|
|
593
|
-
*/
|
|
594
|
-
@JvmStatic
|
|
595
|
-
fun sendOtaUpdateAvailable(
|
|
596
|
-
versionCode: Long,
|
|
597
|
-
versionName: String,
|
|
598
|
-
updates: List<String>,
|
|
599
|
-
totalSize: Long
|
|
600
|
-
) {
|
|
601
|
-
val eventBody = HashMap<String, Any>()
|
|
602
|
-
eventBody["version_code"] = versionCode
|
|
603
|
-
eventBody["version_name"] = versionName
|
|
604
|
-
eventBody["updates"] = updates
|
|
605
|
-
eventBody["total_size"] = totalSize
|
|
606
|
-
|
|
607
|
-
sendTypedMessage("ota_update_available", eventBody as Map<String, Any>)
|
|
608
|
-
}
|
|
609
|
-
|
|
610
595
|
/** Send ota_start_ack — glasses confirmed receipt of ota_start command */
|
|
611
596
|
@JvmStatic
|
|
612
597
|
fun sendOtaStartAck() {
|