brilliantsole 0.0.27 → 0.0.29
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/assets/3d/anchor.glb +0 -0
- package/assets/3d/coin.glb +0 -0
- package/assets/3d/glasses.glb +0 -0
- package/assets/audio/bounceMedium.wav +0 -0
- package/assets/audio/bounceStrong.wav +0 -0
- package/assets/audio/bounceWeak.wav +0 -0
- package/assets/audio/coin.wav +0 -0
- package/assets/audio/getUp.wav +0 -0
- package/assets/audio/grab.wav +0 -0
- package/assets/audio/kick.wav +0 -0
- package/assets/audio/platterFadeIn old.wav +0 -0
- package/assets/audio/platterFadeIn.wav +0 -0
- package/assets/audio/platterFadeOut.wav +0 -0
- package/assets/audio/punch.wav +0 -0
- package/assets/audio/punchSqueak.wav +0 -0
- package/assets/audio/purr.wav +0 -0
- package/assets/audio/purrFadeOut.wav +0 -0
- package/assets/audio/release.wav +0 -0
- package/assets/audio/splat.wav +0 -0
- package/assets/audio/stomp.wav +0 -0
- package/build/brilliantsole.cjs +3091 -741
- package/build/brilliantsole.cjs.map +1 -1
- package/build/brilliantsole.js +2759 -709
- package/build/brilliantsole.js.map +1 -1
- package/build/brilliantsole.ls.js +2602 -543
- package/build/brilliantsole.ls.js.map +1 -1
- package/build/brilliantsole.min.js +1 -1
- package/build/brilliantsole.min.js.map +1 -1
- package/build/brilliantsole.module.d.ts +295 -65
- package/build/brilliantsole.module.js +2749 -710
- package/build/brilliantsole.module.js.map +1 -1
- package/build/brilliantsole.module.min.d.ts +295 -65
- package/build/brilliantsole.module.min.js +1 -1
- package/build/brilliantsole.module.min.js.map +1 -1
- package/build/brilliantsole.node.module.d.ts +289 -62
- package/build/brilliantsole.node.module.js +3080 -742
- package/build/brilliantsole.node.module.js.map +1 -1
- package/build/dts/BS-output.d.ts +10 -0
- package/build/dts/BS.d.ts +21 -8
- package/build/dts/CameraManager.d.ts +72 -0
- package/build/dts/Device.d.ts +64 -13
- package/build/dts/DeviceInformationManager.d.ts +4 -4
- package/build/dts/DeviceManager.d.ts +2 -0
- package/build/dts/FileTransferManager.d.ts +18 -8
- package/build/dts/InformationManager.d.ts +2 -0
- package/build/dts/MicrophoneManager.d.ts +88 -0
- package/build/dts/TfliteManager.d.ts +22 -2
- package/build/dts/WifiManager.d.ts +61 -0
- package/build/dts/connection/BaseConnectionManager.d.ts +35 -3
- package/build/dts/connection/ClientConnectionManager.d.ts +7 -2
- package/build/dts/connection/bluetooth/NobleConnectionManager.d.ts +2 -1
- package/build/dts/connection/bluetooth/WebBluetoothConnectionManager.d.ts +1 -0
- package/build/dts/connection/bluetooth/bluetoothUUIDs.d.ts +2 -2
- package/build/dts/connection/udp/UDPConnectionManager.d.ts +28 -0
- package/build/dts/connection/webSocket/WebSocketConnectionManager.d.ts +25 -0
- package/build/dts/devicePair/DevicePair.d.ts +5 -5
- package/build/dts/scanner/BaseScanner.d.ts +4 -1
- package/build/dts/scanner/NobleScanner.d.ts +2 -1
- package/build/dts/sensor/MotionSensorDataManager.d.ts +5 -2
- package/build/dts/sensor/SensorDataManager.d.ts +5 -4
- package/build/dts/server/BaseClient.d.ts +5 -3
- package/build/dts/server/ServerUtils.d.ts +1 -1
- package/build/dts/server/websocket/WebSocketUtils.d.ts +1 -1
- package/build/dts/utils/AudioUtils.d.ts +2 -0
- package/build/dts/utils/Console.d.ts +2 -0
- package/build/dts/utils/ThrottleUtils.d.ts +2 -0
- package/build/dts/vibration/VibrationManager.d.ts +19 -2
- package/build/index.d.ts +292 -62
- package/build/index.node.d.ts +286 -59
- package/examples/3d/scene.html +19 -5
- package/examples/3d-generic/index.html +144 -0
- package/examples/3d-generic/script.js +266 -0
- package/examples/basic/index.html +267 -17
- package/examples/basic/script.js +958 -105
- package/examples/camera/barcode-detector.js +109 -0
- package/examples/camera/depth-estimation.js +71 -0
- package/examples/camera/face-detector.js +119 -0
- package/examples/camera/face-landmark.js +111 -0
- package/examples/camera/gesture-recognition.js +97 -0
- package/examples/camera/hand-landmark.js +74 -0
- package/examples/camera/image-segmentation.js +98 -0
- package/examples/camera/image-to-text.js +43 -0
- package/examples/camera/image-upscale.js +75 -0
- package/examples/camera/index.html +129 -0
- package/examples/camera/object-detection.js +98 -0
- package/examples/camera/pose-landmark.js +60 -0
- package/examples/camera/script.js +316 -0
- package/examples/camera/utils.js +165 -0
- package/examples/camera/yolo-tiny.js +54 -0
- package/examples/camera/yolo.js +119 -0
- package/examples/edge-impulse/script.js +157 -48
- package/examples/edge-impulse-test/README.md +11 -0
- package/examples/edge-impulse-test/edge-impulse-standalone.js +7228 -0
- package/examples/edge-impulse-test/edge-impulse-standalone.wasm +0 -0
- package/examples/edge-impulse-test/index.html +75 -0
- package/examples/edge-impulse-test/run-impulse.js +135 -0
- package/examples/edge-impulse-test/script.js +200 -0
- package/examples/glasses-gestures/README.md +11 -0
- package/examples/glasses-gestures/edge-impulse-standalone.js +7228 -0
- package/examples/glasses-gestures/edge-impulse-standalone.wasm +0 -0
- package/examples/glasses-gestures/index.html +69 -0
- package/examples/glasses-gestures/run-impulse.js +135 -0
- package/examples/glasses-gestures/script.js +226 -0
- package/examples/gloves/edge-impulse-standalone.js +7228 -0
- package/examples/gloves/edge-impulse-standalone.wasm +0 -0
- package/examples/gloves/index.html +4 -1
- package/examples/gloves/run-impulse.js +135 -0
- package/examples/gloves/script.js +367 -51
- package/examples/graph/script.js +94 -37
- package/examples/microphone/gender.js +54 -0
- package/examples/microphone/index.html +102 -0
- package/examples/microphone/script.js +394 -0
- package/examples/microphone/utils.js +45 -0
- package/examples/microphone/whisper-realtime.js +166 -0
- package/examples/microphone/whisper.js +132 -0
- package/examples/punch/index.html +135 -0
- package/examples/punch/punch.tflite +0 -0
- package/examples/punch/script.js +169 -0
- package/examples/server/index.html +98 -22
- package/examples/server/script.js +317 -109
- package/examples/ukaton-firmware-update/merged-firmware.bin +0 -0
- package/examples/utils/aframe/aframe-master.min.js +2 -0
- package/examples/utils/aframe/bs-vibration.js +150 -0
- package/examples/utils/aframe/force-pushable.js +80 -0
- package/examples/utils/aframe/grabbable-anchor.js +46 -0
- package/examples/utils/aframe/grabbable-listener.js +31 -0
- package/examples/utils/aframe/grabbable-physics-body.js +190 -0
- package/examples/utils/aframe/grow-shrink.js +25 -0
- package/examples/utils/aframe/hand-punch.js +119 -0
- package/examples/utils/aframe/my-obb-collider.js +293 -0
- package/examples/utils/aframe/occlude-hand-tracking-controls.js +47 -0
- package/examples/utils/aframe/occlude-mesh.js +42 -0
- package/examples/utils/aframe/palm-up-detector.js +47 -0
- package/examples/utils/aframe/shadow-material.js +20 -0
- package/examples/utils/aframe/soft-shadow-light.js +9 -0
- package/examples/webxr-2/assets/3d/soccerBall.glb +0 -0
- package/examples/webxr-2/assets/audio/shellBounce.wav +0 -0
- package/examples/webxr-2/assets/audio/shellHit.wav +0 -0
- package/examples/webxr-2/assets/audio/shellKick.wav +0 -0
- package/examples/webxr-2/assets/audio/soccerBounce.wav +0 -0
- package/examples/webxr-2/assets/audio/soccerKick.mp3 +0 -0
- package/examples/webxr-2/assets/images/shellTexture.png +0 -0
- package/examples/webxr-2/components/bs-ankle.js +337 -0
- package/examples/webxr-2/components/coin.js +84 -0
- package/examples/webxr-2/components/custom-wrap.js +17 -0
- package/examples/webxr-2/components/goomba.js +3250 -0
- package/examples/webxr-2/components/init-shell-material.js +215 -0
- package/examples/webxr-2/components/platter.js +172 -0
- package/examples/webxr-2/components/shell.js +374 -0
- package/examples/webxr-2/components/soccer-ball.js +250 -0
- package/examples/webxr-2/components/squashed-goomba.js +249 -0
- package/examples/webxr-2/edge-impulse-standalone.js +7228 -0
- package/examples/webxr-2/edge-impulse-standalone.wasm +0 -0
- package/examples/webxr-2/index.html +996 -0
- package/examples/webxr-2/kick.tflite +0 -0
- package/examples/webxr-2/kick2.tflite +0 -0
- package/examples/webxr-2/run-impulse.js +135 -0
- package/examples/webxr-2/script.js +384 -0
- package/examples/webxr-3/components/bs-camera.js +65 -0
- package/examples/webxr-3/index.html +134 -0
- package/examples/webxr-3/script.js +432 -0
- package/package.json +2 -1
- package/src/.prettierrc +4 -0
- package/src/BS.ts +79 -8
- package/src/CameraManager.ts +497 -0
- package/src/Device.ts +691 -86
- package/src/DeviceInformationManager.ts +19 -10
- package/src/DeviceManager.ts +85 -25
- package/src/FileTransferManager.ts +145 -20
- package/src/InformationManager.ts +40 -15
- package/src/MicrophoneManager.ts +599 -0
- package/src/TfliteManager.ts +171 -25
- package/src/WifiManager.ts +323 -0
- package/src/connection/BaseConnectionManager.ts +130 -30
- package/src/connection/ClientConnectionManager.ts +34 -10
- package/src/connection/bluetooth/BluetoothConnectionManager.ts +8 -2
- package/src/connection/bluetooth/NobleConnectionManager.ts +147 -41
- package/src/connection/bluetooth/WebBluetoothConnectionManager.ts +99 -34
- package/src/connection/bluetooth/bluetoothUUIDs.ts +40 -13
- package/src/connection/udp/UDPConnectionManager.ts +356 -0
- package/src/connection/websocket/WebSocketConnectionManager.ts +282 -0
- package/src/devicePair/DevicePair.ts +95 -25
- package/src/devicePair/DevicePairPressureSensorDataManager.ts +27 -7
- package/src/scanner/BaseScanner.ts +49 -11
- package/src/scanner/NobleScanner.ts +76 -14
- package/src/sensor/MotionSensorDataManager.ts +21 -6
- package/src/sensor/PressureSensorDataManager.ts +37 -8
- package/src/sensor/SensorConfigurationManager.ts +73 -22
- package/src/sensor/SensorDataManager.ts +109 -23
- package/src/server/BaseClient.ts +150 -36
- package/src/server/BaseServer.ts +50 -2
- package/src/server/ServerUtils.ts +39 -9
- package/src/server/udp/UDPServer.ts +73 -22
- package/src/server/udp/UDPUtils.ts +9 -2
- package/src/server/websocket/WebSocketClient.ts +27 -7
- package/src/server/websocket/WebSocketUtils.ts +4 -2
- package/src/utils/AudioUtils.ts +65 -0
- package/src/utils/Console.ts +62 -9
- package/src/utils/ParseUtils.ts +24 -5
- package/src/utils/ThrottleUtils.ts +62 -0
- package/src/utils/Timer.ts +1 -1
- package/src/vibration/VibrationManager.ts +166 -40
package/examples/basic/script.js
CHANGED
|
@@ -11,7 +11,9 @@ window.device = device;
|
|
|
11
11
|
|
|
12
12
|
// GET DEVICES
|
|
13
13
|
/** @type {HTMLTemplateElement} */
|
|
14
|
-
const availableDeviceTemplate = document.getElementById(
|
|
14
|
+
const availableDeviceTemplate = document.getElementById(
|
|
15
|
+
"availableDeviceTemplate"
|
|
16
|
+
);
|
|
15
17
|
const availableDevicesContainer = document.getElementById("availableDevices");
|
|
16
18
|
/** @param {BS.Device[]} availableDevices */
|
|
17
19
|
function onAvailableDevices(availableDevices) {
|
|
@@ -23,19 +25,24 @@ function onAvailableDevices(availableDevices) {
|
|
|
23
25
|
const availableDeviceContainer = availableDeviceTemplate.content
|
|
24
26
|
.cloneNode(true)
|
|
25
27
|
.querySelector(".availableDevice");
|
|
26
|
-
availableDeviceContainer.querySelector(".name").innerText =
|
|
27
|
-
|
|
28
|
+
availableDeviceContainer.querySelector(".name").innerText =
|
|
29
|
+
availableDevice.name;
|
|
30
|
+
availableDeviceContainer.querySelector(".type").innerText =
|
|
31
|
+
availableDevice.type;
|
|
28
32
|
|
|
29
33
|
/** @type {HTMLButtonElement} */
|
|
30
|
-
const toggleConnectionButton =
|
|
34
|
+
const toggleConnectionButton =
|
|
35
|
+
availableDeviceContainer.querySelector(".toggleConnection");
|
|
31
36
|
toggleConnectionButton.addEventListener("click", () => {
|
|
32
37
|
device.connectionManager = availableDevice.connectionManager;
|
|
33
38
|
device.reconnect();
|
|
34
39
|
});
|
|
35
40
|
device.addEventListener("connectionStatus", () => {
|
|
36
|
-
toggleConnectionButton.disabled =
|
|
41
|
+
toggleConnectionButton.disabled =
|
|
42
|
+
device.connectionStatus != "notConnected";
|
|
37
43
|
});
|
|
38
|
-
toggleConnectionButton.disabled =
|
|
44
|
+
toggleConnectionButton.disabled =
|
|
45
|
+
device.connectionStatus != "notConnected";
|
|
39
46
|
|
|
40
47
|
availableDevicesContainer.appendChild(availableDeviceContainer);
|
|
41
48
|
});
|
|
@@ -84,7 +91,9 @@ device.addEventListener("connectionStatus", () => {
|
|
|
84
91
|
case "connected":
|
|
85
92
|
case "notConnected":
|
|
86
93
|
toggleConnectionButton.disabled = false;
|
|
87
|
-
toggleConnectionButton.innerText = device.isConnected
|
|
94
|
+
toggleConnectionButton.innerText = device.isConnected
|
|
95
|
+
? "disconnect"
|
|
96
|
+
: "connect";
|
|
88
97
|
break;
|
|
89
98
|
case "connecting":
|
|
90
99
|
case "disconnecting":
|
|
@@ -95,7 +104,29 @@ device.addEventListener("connectionStatus", () => {
|
|
|
95
104
|
});
|
|
96
105
|
|
|
97
106
|
/** @type {HTMLInputElement} */
|
|
98
|
-
const
|
|
107
|
+
const connectIpAddressInput = document.getElementById("connectIpAddress");
|
|
108
|
+
connectIpAddressInput.addEventListener("input", () => {
|
|
109
|
+
const isValid = connectIpAddressInput.checkValidity();
|
|
110
|
+
connectViaIpAddressButton.disabled = !isValid;
|
|
111
|
+
});
|
|
112
|
+
/** @type {HTMLButtonElement} */
|
|
113
|
+
const connectViaIpAddressButton = document.getElementById(
|
|
114
|
+
"connectViaIpAddress"
|
|
115
|
+
);
|
|
116
|
+
connectViaIpAddressButton.addEventListener("click", () => {
|
|
117
|
+
connectViaIpAddressButton.disabled = true;
|
|
118
|
+
console.log(`connecting via ipAddress "${connectIpAddressInput.value}"`);
|
|
119
|
+
device.connect({ type: "webSocket", ipAddress: connectIpAddressInput.value });
|
|
120
|
+
});
|
|
121
|
+
device.addEventListener("isConnected", () => {
|
|
122
|
+
connectIpAddressInput.disabled = device.isConnected;
|
|
123
|
+
connectViaIpAddressButton.disabled = device.isConnected;
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
/** @type {HTMLInputElement} */
|
|
127
|
+
const reconnectOnDisconnectionCheckbox = document.getElementById(
|
|
128
|
+
"reconnectOnDisconnection"
|
|
129
|
+
);
|
|
99
130
|
reconnectOnDisconnectionCheckbox.addEventListener("input", () => {
|
|
100
131
|
device.reconnectOnDisconnection = reconnectOnDisconnectionCheckbox.checked;
|
|
101
132
|
});
|
|
@@ -103,7 +134,7 @@ reconnectOnDisconnectionCheckbox.addEventListener("input", () => {
|
|
|
103
134
|
/** @type {HTMLButtonElement} */
|
|
104
135
|
const resetDeviceButton = document.getElementById("resetDevice");
|
|
105
136
|
device.addEventListener("isConnected", () => {
|
|
106
|
-
resetDeviceButton.disabled = !device.isConnected;
|
|
137
|
+
resetDeviceButton.disabled = !device.isConnected || !device.canReset;
|
|
107
138
|
});
|
|
108
139
|
resetDeviceButton.addEventListener("click", () => {
|
|
109
140
|
device.reset();
|
|
@@ -114,7 +145,11 @@ resetDeviceButton.addEventListener("click", () => {
|
|
|
114
145
|
/** @type {HTMLPreElement} */
|
|
115
146
|
const deviceInformationPre = document.getElementById("deviceInformationPre");
|
|
116
147
|
device.addEventListener("deviceInformation", () => {
|
|
117
|
-
deviceInformationPre.textContent = JSON.stringify(
|
|
148
|
+
deviceInformationPre.textContent = JSON.stringify(
|
|
149
|
+
device.deviceInformation,
|
|
150
|
+
null,
|
|
151
|
+
2
|
|
152
|
+
);
|
|
118
153
|
});
|
|
119
154
|
|
|
120
155
|
// MTU
|
|
@@ -147,7 +182,9 @@ device.addEventListener("getBatteryCurrent", () => {
|
|
|
147
182
|
});
|
|
148
183
|
|
|
149
184
|
/** @type {HTMLButtonElement} */
|
|
150
|
-
const updateBatteryCurrentButton = document.getElementById(
|
|
185
|
+
const updateBatteryCurrentButton = document.getElementById(
|
|
186
|
+
"updateBatteryCurrent"
|
|
187
|
+
);
|
|
151
188
|
device.addEventListener("isConnected", () => {
|
|
152
189
|
updateBatteryCurrentButton.disabled = !device.isConnected;
|
|
153
190
|
});
|
|
@@ -231,22 +268,33 @@ setTypeButton.addEventListener("click", () => {
|
|
|
231
268
|
// SENSOR CONFIGURATION
|
|
232
269
|
|
|
233
270
|
/** @type {HTMLPreElement} */
|
|
234
|
-
const sensorConfigurationPre = document.getElementById(
|
|
271
|
+
const sensorConfigurationPre = document.getElementById(
|
|
272
|
+
"sensorConfigurationPre"
|
|
273
|
+
);
|
|
235
274
|
device.addEventListener("getSensorConfiguration", () => {
|
|
236
|
-
sensorConfigurationPre.textContent = JSON.stringify(
|
|
275
|
+
sensorConfigurationPre.textContent = JSON.stringify(
|
|
276
|
+
device.sensorConfiguration,
|
|
277
|
+
null,
|
|
278
|
+
2
|
|
279
|
+
);
|
|
237
280
|
});
|
|
238
281
|
|
|
239
282
|
/** @type {HTMLTemplateElement} */
|
|
240
|
-
const sensorTypeConfigurationTemplate = document.getElementById(
|
|
283
|
+
const sensorTypeConfigurationTemplate = document.getElementById(
|
|
284
|
+
"sensorTypeConfigurationTemplate"
|
|
285
|
+
);
|
|
241
286
|
BS.SensorTypes.forEach((sensorType) => {
|
|
242
287
|
/** @type {HTMLElement} */
|
|
243
|
-
const sensorTypeConfigurationContainer =
|
|
244
|
-
.
|
|
245
|
-
|
|
246
|
-
|
|
288
|
+
const sensorTypeConfigurationContainer =
|
|
289
|
+
sensorTypeConfigurationTemplate.content
|
|
290
|
+
.cloneNode(true)
|
|
291
|
+
.querySelector(".sensorTypeConfiguration");
|
|
292
|
+
sensorTypeConfigurationContainer.querySelector(".sensorType").innerText =
|
|
293
|
+
sensorType;
|
|
247
294
|
|
|
248
295
|
/** @type {HTMLInputElement} */
|
|
249
|
-
const sensorRateInput =
|
|
296
|
+
const sensorRateInput =
|
|
297
|
+
sensorTypeConfigurationContainer.querySelector(".sensorRate");
|
|
250
298
|
sensorRateInput.value = 0;
|
|
251
299
|
sensorRateInput.max = BS.MaxSensorRate;
|
|
252
300
|
sensorRateInput.step = BS.SensorRateStep;
|
|
@@ -264,18 +312,23 @@ BS.SensorTypes.forEach((sensorType) => {
|
|
|
264
312
|
}
|
|
265
313
|
});
|
|
266
314
|
|
|
267
|
-
sensorTypeConfigurationTemplate.parentElement.appendChild(
|
|
315
|
+
sensorTypeConfigurationTemplate.parentElement.appendChild(
|
|
316
|
+
sensorTypeConfigurationContainer
|
|
317
|
+
);
|
|
268
318
|
sensorTypeConfigurationContainer.dataset.sensorType = sensorType;
|
|
269
319
|
});
|
|
270
320
|
device.addEventListener("getSensorConfiguration", () => {
|
|
271
321
|
for (const sensorType in device.sensorConfiguration) {
|
|
272
|
-
document.querySelector(
|
|
273
|
-
|
|
322
|
+
document.querySelector(
|
|
323
|
+
`.sensorTypeConfiguration[data-sensor-type="${sensorType}"] .input`
|
|
324
|
+
).value = device.sensorConfiguration[sensorType];
|
|
274
325
|
}
|
|
275
326
|
});
|
|
276
327
|
device.addEventListener("isConnected", () => {
|
|
277
328
|
for (const sensorType in device.sensorConfiguration) {
|
|
278
|
-
document.querySelector(
|
|
329
|
+
document.querySelector(
|
|
330
|
+
`[data-sensor-type="${sensorType}"] .input`
|
|
331
|
+
).disabled = !device.isConnected;
|
|
279
332
|
}
|
|
280
333
|
});
|
|
281
334
|
|
|
@@ -290,9 +343,13 @@ resetPressureRangeButton.addEventListener("click", () => {
|
|
|
290
343
|
// SENSOR DATA
|
|
291
344
|
|
|
292
345
|
/** @type {HTMLTemplateElement} */
|
|
293
|
-
const sensorTypeDataTemplate = document.getElementById(
|
|
346
|
+
const sensorTypeDataTemplate = document.getElementById(
|
|
347
|
+
"sensorTypeDataTemplate"
|
|
348
|
+
);
|
|
294
349
|
BS.SensorTypes.forEach((sensorType) => {
|
|
295
|
-
const sensorTypeDataContainer = sensorTypeDataTemplate.content
|
|
350
|
+
const sensorTypeDataContainer = sensorTypeDataTemplate.content
|
|
351
|
+
.cloneNode(true)
|
|
352
|
+
.querySelector(".sensorTypeData");
|
|
296
353
|
sensorTypeDataContainer.querySelector(".sensorType").innerText = sensorType;
|
|
297
354
|
|
|
298
355
|
/** @type {HTMLPreElement} */
|
|
@@ -311,38 +368,52 @@ BS.SensorTypes.forEach((sensorType) => {
|
|
|
311
368
|
const vibrationTemplate = document.getElementById("vibrationTemplate");
|
|
312
369
|
{
|
|
313
370
|
/** @type {HTMLInputElement} */
|
|
314
|
-
const waveformEffectSequenceLoopCountInput =
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
371
|
+
const waveformEffectSequenceLoopCountInput =
|
|
372
|
+
vibrationTemplate.content.querySelector(
|
|
373
|
+
".waveformEffect .sequenceLoopCount"
|
|
374
|
+
);
|
|
375
|
+
waveformEffectSequenceLoopCountInput.max =
|
|
376
|
+
BS.MaxVibrationWaveformEffectSequenceLoopCount;
|
|
318
377
|
}
|
|
319
378
|
/** @type {HTMLTemplateElement} */
|
|
320
|
-
const vibrationLocationTemplate = document.getElementById(
|
|
379
|
+
const vibrationLocationTemplate = document.getElementById(
|
|
380
|
+
"vibrationLocationTemplate"
|
|
381
|
+
);
|
|
321
382
|
|
|
322
383
|
/** @type {HTMLTemplateElement} */
|
|
323
|
-
const waveformEffectSegmentTemplate = document.getElementById(
|
|
384
|
+
const waveformEffectSegmentTemplate = document.getElementById(
|
|
385
|
+
"waveformEffectSegmentTemplate"
|
|
386
|
+
);
|
|
324
387
|
{
|
|
325
388
|
/** @type {HTMLSelectElement} */
|
|
326
|
-
const waveformEffectSelect =
|
|
389
|
+
const waveformEffectSelect =
|
|
390
|
+
waveformEffectSegmentTemplate.content.querySelector(".effect");
|
|
327
391
|
const waveformEffectOptgroup = waveformEffectSelect.querySelector("optgroup");
|
|
328
392
|
BS.VibrationWaveformEffects.forEach((waveformEffect) => {
|
|
329
393
|
waveformEffectOptgroup.appendChild(new Option(waveformEffect));
|
|
330
394
|
});
|
|
331
395
|
|
|
332
396
|
/** @type {HTMLInputElement} */
|
|
333
|
-
const waveformEffectSegmentDelayInput =
|
|
334
|
-
|
|
397
|
+
const waveformEffectSegmentDelayInput =
|
|
398
|
+
waveformEffectSegmentTemplate.content.querySelector(".delay");
|
|
399
|
+
waveformEffectSegmentDelayInput.max =
|
|
400
|
+
BS.MaxVibrationWaveformEffectSegmentDelay;
|
|
335
401
|
|
|
336
402
|
/** @type {HTMLInputElement} */
|
|
337
|
-
const waveformEffectLoopCountInput =
|
|
338
|
-
|
|
403
|
+
const waveformEffectLoopCountInput =
|
|
404
|
+
waveformEffectSegmentTemplate.content.querySelector(".loopCount");
|
|
405
|
+
waveformEffectLoopCountInput.max =
|
|
406
|
+
BS.MaxVibrationWaveformEffectSegmentLoopCount;
|
|
339
407
|
}
|
|
340
408
|
|
|
341
409
|
/** @type {HTMLTemplateElement} */
|
|
342
|
-
const waveformSegmentTemplate = document.getElementById(
|
|
410
|
+
const waveformSegmentTemplate = document.getElementById(
|
|
411
|
+
"waveformSegmentTemplate"
|
|
412
|
+
);
|
|
343
413
|
{
|
|
344
414
|
/** @type {HTMLInputElement} */
|
|
345
|
-
const waveformDurationSegmentInput =
|
|
415
|
+
const waveformDurationSegmentInput =
|
|
416
|
+
waveformSegmentTemplate.content.querySelector(".duration");
|
|
346
417
|
waveformDurationSegmentInput.max = BS.MaxVibrationWaveformSegmentDuration;
|
|
347
418
|
}
|
|
348
419
|
|
|
@@ -350,7 +421,9 @@ const waveformSegmentTemplate = document.getElementById("waveformSegmentTemplate
|
|
|
350
421
|
const addVibrationButton = document.getElementById("addVibration");
|
|
351
422
|
addVibrationButton.addEventListener("click", () => {
|
|
352
423
|
/** @type {HTMLElement} */
|
|
353
|
-
const vibrationContainer = vibrationTemplate.content
|
|
424
|
+
const vibrationContainer = vibrationTemplate.content
|
|
425
|
+
.cloneNode(true)
|
|
426
|
+
.querySelector(".vibration");
|
|
354
427
|
|
|
355
428
|
/** @type {HTMLButtonElement} */
|
|
356
429
|
const deleteButton = vibrationContainer.querySelector(".delete");
|
|
@@ -360,25 +433,33 @@ addVibrationButton.addEventListener("click", () => {
|
|
|
360
433
|
});
|
|
361
434
|
|
|
362
435
|
/** @type {HTMLUListElement} */
|
|
363
|
-
const vibrationLocationsContainer =
|
|
364
|
-
|
|
436
|
+
const vibrationLocationsContainer =
|
|
437
|
+
vibrationContainer.querySelector(".locations");
|
|
438
|
+
device.vibrationLocations.forEach((vibrationLocation) => {
|
|
365
439
|
const vibrationLocationContainer = vibrationLocationTemplate.content
|
|
366
440
|
.cloneNode(true)
|
|
367
441
|
.querySelector(".vibrationLocation");
|
|
368
|
-
vibrationLocationContainer.querySelector("span").innerText =
|
|
369
|
-
|
|
442
|
+
vibrationLocationContainer.querySelector("span").innerText =
|
|
443
|
+
vibrationLocation;
|
|
444
|
+
vibrationLocationContainer.querySelector(
|
|
445
|
+
"input"
|
|
446
|
+
).dataset.vibrationLocation = vibrationLocation;
|
|
370
447
|
vibrationLocationsContainer.appendChild(vibrationLocationContainer);
|
|
371
448
|
});
|
|
372
449
|
|
|
373
450
|
/** @type {HTMLElement} */
|
|
374
|
-
const waveformEffectContainer =
|
|
451
|
+
const waveformEffectContainer =
|
|
452
|
+
vibrationContainer.querySelector(".waveformEffect");
|
|
375
453
|
/** @type {HTMLUListElement} */
|
|
376
|
-
const waveformEffectSegmentsContainer =
|
|
454
|
+
const waveformEffectSegmentsContainer =
|
|
455
|
+
waveformEffectContainer.querySelector(".segments");
|
|
377
456
|
/** @type {HTMLButtonElement} */
|
|
378
|
-
const addWaveformEffectSegmentButton =
|
|
457
|
+
const addWaveformEffectSegmentButton =
|
|
458
|
+
waveformEffectContainer.querySelector(".add");
|
|
379
459
|
const updateAddWaveformEffectSegmentButton = () => {
|
|
380
460
|
addWaveformEffectSegmentButton.disabled =
|
|
381
|
-
waveformEffectSegmentsContainer.children.length >=
|
|
461
|
+
waveformEffectSegmentsContainer.children.length >=
|
|
462
|
+
BS.MaxNumberOfVibrationWaveformEffectSegments;
|
|
382
463
|
};
|
|
383
464
|
addWaveformEffectSegmentButton.addEventListener("click", () => {
|
|
384
465
|
/** @type {HTMLElement} */
|
|
@@ -386,11 +467,14 @@ addVibrationButton.addEventListener("click", () => {
|
|
|
386
467
|
.cloneNode(true)
|
|
387
468
|
.querySelector(".waveformEffectSegment");
|
|
388
469
|
|
|
389
|
-
const effectContainer =
|
|
390
|
-
|
|
470
|
+
const effectContainer =
|
|
471
|
+
waveformEffectSegmentContainer.querySelector(".effect").parentElement;
|
|
472
|
+
const delayContainer =
|
|
473
|
+
waveformEffectSegmentContainer.querySelector(".delay").parentElement;
|
|
391
474
|
|
|
392
475
|
/** @type {HTMLSelectElement} */
|
|
393
|
-
const waveformEffectTypeSelect =
|
|
476
|
+
const waveformEffectTypeSelect =
|
|
477
|
+
waveformEffectSegmentContainer.querySelector(".type");
|
|
394
478
|
waveformEffectTypeSelect.addEventListener("input", () => {
|
|
395
479
|
let shouldShowEffectContainer = false;
|
|
396
480
|
let shouldShowDelayContainer = false;
|
|
@@ -403,7 +487,9 @@ addVibrationButton.addEventListener("click", () => {
|
|
|
403
487
|
shouldShowDelayContainer = true;
|
|
404
488
|
break;
|
|
405
489
|
default:
|
|
406
|
-
throw Error(
|
|
490
|
+
throw Error(
|
|
491
|
+
`uncaught waveformEffectTypeSelect value "${waveformEffectTypeSelect.value}"`
|
|
492
|
+
);
|
|
407
493
|
}
|
|
408
494
|
|
|
409
495
|
effectContainer.style.display = shouldShowEffectContainer ? "" : "none";
|
|
@@ -411,10 +497,12 @@ addVibrationButton.addEventListener("click", () => {
|
|
|
411
497
|
});
|
|
412
498
|
waveformEffectTypeSelect.dispatchEvent(new Event("input"));
|
|
413
499
|
|
|
414
|
-
waveformEffectSegmentContainer
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
500
|
+
waveformEffectSegmentContainer
|
|
501
|
+
.querySelector(".delete")
|
|
502
|
+
.addEventListener("click", () => {
|
|
503
|
+
waveformEffectSegmentContainer.remove();
|
|
504
|
+
updateAddWaveformEffectSegmentButton();
|
|
505
|
+
});
|
|
418
506
|
|
|
419
507
|
waveformEffectSegmentsContainer.appendChild(waveformEffectSegmentContainer);
|
|
420
508
|
updateAddWaveformEffectSegmentButton();
|
|
@@ -423,22 +511,28 @@ addVibrationButton.addEventListener("click", () => {
|
|
|
423
511
|
/** @type {HTMLElement} */
|
|
424
512
|
const waveformContainer = vibrationContainer.querySelector(".waveform");
|
|
425
513
|
/** @type {HTMLUListElement} */
|
|
426
|
-
const waveformSegmentsContainer =
|
|
514
|
+
const waveformSegmentsContainer =
|
|
515
|
+
waveformContainer.querySelector(".segments");
|
|
427
516
|
|
|
428
517
|
/** @type {HTMLButtonElement} */
|
|
429
518
|
const addWaveformSegmentButton = waveformContainer.querySelector(".add");
|
|
430
519
|
const updateAddWaveformSegmentButton = () => {
|
|
431
520
|
addWaveformSegmentButton.disabled =
|
|
432
|
-
waveformSegmentsContainer.children.length >=
|
|
521
|
+
waveformSegmentsContainer.children.length >=
|
|
522
|
+
BS.MaxNumberOfVibrationWaveformSegments;
|
|
433
523
|
};
|
|
434
524
|
addWaveformSegmentButton.addEventListener("click", () => {
|
|
435
525
|
/** @type {HTMLElement} */
|
|
436
|
-
const waveformSegmentContainer = waveformSegmentTemplate.content
|
|
526
|
+
const waveformSegmentContainer = waveformSegmentTemplate.content
|
|
527
|
+
.cloneNode(true)
|
|
528
|
+
.querySelector(".waveformSegment");
|
|
437
529
|
|
|
438
|
-
waveformSegmentContainer
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
530
|
+
waveformSegmentContainer
|
|
531
|
+
.querySelector(".delete")
|
|
532
|
+
.addEventListener("click", () => {
|
|
533
|
+
waveformSegmentContainer.remove();
|
|
534
|
+
updateAddWaveformSegmentButton();
|
|
535
|
+
});
|
|
442
536
|
|
|
443
537
|
waveformSegmentsContainer.appendChild(waveformSegmentContainer);
|
|
444
538
|
updateAddWaveformSegmentButton();
|
|
@@ -447,7 +541,8 @@ addVibrationButton.addEventListener("click", () => {
|
|
|
447
541
|
/** @type {HTMLSelectElement} */
|
|
448
542
|
const vibrationTypeSelect = vibrationContainer.querySelector(".type");
|
|
449
543
|
/** @type {HTMLOptGroupElement} */
|
|
450
|
-
const vibrationTypeSelectOptgroup =
|
|
544
|
+
const vibrationTypeSelectOptgroup =
|
|
545
|
+
vibrationTypeSelect.querySelector("optgroup");
|
|
451
546
|
BS.VibrationTypes.forEach((vibrationType) => {
|
|
452
547
|
vibrationTypeSelectOptgroup.appendChild(new Option(vibrationType));
|
|
453
548
|
});
|
|
@@ -469,7 +564,9 @@ addVibrationButton.addEventListener("click", () => {
|
|
|
469
564
|
throw Error(`invalid vibrationType "${vibrationType}"`);
|
|
470
565
|
}
|
|
471
566
|
|
|
472
|
-
waveformEffectContainer.style.display = showWaveformEffectContainer
|
|
567
|
+
waveformEffectContainer.style.display = showWaveformEffectContainer
|
|
568
|
+
? ""
|
|
569
|
+
: "none";
|
|
473
570
|
waveformContainer.style.display = showWaveformContainer ? "" : "none";
|
|
474
571
|
});
|
|
475
572
|
vibrationTypeSelect.dispatchEvent(new Event("input"));
|
|
@@ -484,40 +581,60 @@ triggerVibrationsButton.addEventListener("click", () => {
|
|
|
484
581
|
/** @type {BS.VibrationConfiguration[]} */
|
|
485
582
|
let vibrationConfigurations = [];
|
|
486
583
|
Array.from(vibrationTemplate.parentElement.querySelectorAll(".vibration"))
|
|
487
|
-
.filter(
|
|
584
|
+
.filter(
|
|
585
|
+
(vibrationContainer) =>
|
|
586
|
+
vibrationContainer.querySelector(".shouldTrigger").checked
|
|
587
|
+
)
|
|
488
588
|
.forEach((vibrationContainer) => {
|
|
489
589
|
/** @type {BS.VibrationConfiguration} */
|
|
490
590
|
const vibrationConfiguration = {
|
|
491
591
|
locations: [],
|
|
492
592
|
};
|
|
493
|
-
Array.from(
|
|
593
|
+
Array.from(
|
|
594
|
+
vibrationContainer.querySelectorAll(`[data-vibration-location]`)
|
|
595
|
+
)
|
|
494
596
|
.filter((input) => input.checked)
|
|
495
597
|
.forEach((input) => {
|
|
496
|
-
vibrationConfiguration.locations.push(
|
|
598
|
+
vibrationConfiguration.locations.push(
|
|
599
|
+
input.dataset.vibrationLocation
|
|
600
|
+
);
|
|
497
601
|
});
|
|
498
602
|
if (vibrationConfiguration.locations.length == 0) {
|
|
499
603
|
return;
|
|
500
604
|
}
|
|
501
605
|
|
|
502
|
-
vibrationConfiguration.type =
|
|
606
|
+
vibrationConfiguration.type =
|
|
607
|
+
vibrationContainer.querySelector("select.type").value;
|
|
503
608
|
switch (vibrationConfiguration.type) {
|
|
504
609
|
case "waveformEffect":
|
|
505
610
|
vibrationConfiguration.segments = Array.from(
|
|
506
|
-
vibrationContainer.querySelectorAll(
|
|
611
|
+
vibrationContainer.querySelectorAll(
|
|
612
|
+
".waveformEffect .waveformEffectSegment"
|
|
613
|
+
)
|
|
507
614
|
).map((waveformEffectSegmentContainer) => {
|
|
508
615
|
/** @type {BS.VibrationWaveformEffectSegment} */
|
|
509
616
|
const waveformEffectSegment = {
|
|
510
|
-
loopCount: Number(
|
|
617
|
+
loopCount: Number(
|
|
618
|
+
waveformEffectSegmentContainer.querySelector(".loopCount").value
|
|
619
|
+
),
|
|
511
620
|
};
|
|
512
|
-
if (
|
|
513
|
-
|
|
621
|
+
if (
|
|
622
|
+
waveformEffectSegmentContainer.querySelector(".type").value ==
|
|
623
|
+
"effect"
|
|
624
|
+
) {
|
|
625
|
+
waveformEffectSegment.effect =
|
|
626
|
+
waveformEffectSegmentContainer.querySelector(".effect").value;
|
|
514
627
|
} else {
|
|
515
|
-
waveformEffectSegment.delay = Number(
|
|
628
|
+
waveformEffectSegment.delay = Number(
|
|
629
|
+
waveformEffectSegmentContainer.querySelector(".delay").value
|
|
630
|
+
);
|
|
516
631
|
}
|
|
517
632
|
return waveformEffectSegment;
|
|
518
633
|
});
|
|
519
634
|
vibrationConfiguration.loopCount = Number(
|
|
520
|
-
vibrationContainer.querySelector(
|
|
635
|
+
vibrationContainer.querySelector(
|
|
636
|
+
".waveformEffect .sequenceLoopCount"
|
|
637
|
+
).value
|
|
521
638
|
);
|
|
522
639
|
break;
|
|
523
640
|
case "waveform":
|
|
@@ -525,8 +642,12 @@ triggerVibrationsButton.addEventListener("click", () => {
|
|
|
525
642
|
vibrationContainer.querySelectorAll(".waveform .waveformSegment")
|
|
526
643
|
).map((waveformSegmentContainer) => {
|
|
527
644
|
return {
|
|
528
|
-
amplitude: Number(
|
|
529
|
-
|
|
645
|
+
amplitude: Number(
|
|
646
|
+
waveformSegmentContainer.querySelector(".amplitude").value
|
|
647
|
+
),
|
|
648
|
+
duration: Number(
|
|
649
|
+
waveformSegmentContainer.querySelector(".duration").value
|
|
650
|
+
),
|
|
530
651
|
};
|
|
531
652
|
});
|
|
532
653
|
break;
|
|
@@ -546,7 +667,8 @@ device.addEventListener("isConnected", () => {
|
|
|
546
667
|
|
|
547
668
|
function updateTriggerVibrationsButtonDisabled() {
|
|
548
669
|
triggerVibrationsButton.disabled =
|
|
549
|
-
!device.isConnected ||
|
|
670
|
+
!device.isConnected ||
|
|
671
|
+
vibrationTemplate.parentElement.querySelectorAll(".vibration").length == 0;
|
|
550
672
|
}
|
|
551
673
|
|
|
552
674
|
// FILE TRANSFER
|
|
@@ -587,14 +709,28 @@ fileTransferTypesSelect.addEventListener("input", () => {
|
|
|
587
709
|
case "tflite":
|
|
588
710
|
fileInput.accept = ".tflite";
|
|
589
711
|
break;
|
|
712
|
+
case "wifiServerCert":
|
|
713
|
+
fileInput.accept = ".crt";
|
|
714
|
+
break;
|
|
715
|
+
case "wifiServerKey":
|
|
716
|
+
fileInput.accept = ".key";
|
|
717
|
+
break;
|
|
590
718
|
}
|
|
591
719
|
});
|
|
592
720
|
/** @type {HTMLOptGroupElement} */
|
|
593
|
-
const fileTransferTypesOptgroup =
|
|
721
|
+
const fileTransferTypesOptgroup =
|
|
722
|
+
fileTransferTypesSelect.querySelector("optgroup");
|
|
594
723
|
BS.FileTypes.forEach((fileType) => {
|
|
595
724
|
fileTransferTypesOptgroup.appendChild(new Option(fileType));
|
|
596
725
|
});
|
|
597
726
|
fileTransferTypesSelect.dispatchEvent(new Event("input"));
|
|
727
|
+
device.addEventListener("connected", () => {
|
|
728
|
+
fileTransferTypesSelect.querySelectorAll("option").forEach((option) => {
|
|
729
|
+
option.hidden =
|
|
730
|
+
BS.FileTypes.includes(option.value) &&
|
|
731
|
+
!device.fileTypes.includes(option.value);
|
|
732
|
+
});
|
|
733
|
+
});
|
|
598
734
|
|
|
599
735
|
/** @type {HTMLProgressElement} */
|
|
600
736
|
const fileTransferProgress = document.getElementById("fileTransferProgress");
|
|
@@ -627,7 +763,8 @@ toggleFileTransferButton.addEventListener("click", async () => {
|
|
|
627
763
|
}
|
|
628
764
|
});
|
|
629
765
|
const updateToggleFileTransferButton = () => {
|
|
630
|
-
const enabled =
|
|
766
|
+
const enabled =
|
|
767
|
+
device.isConnected && (file || fileTransferDirection == "receive");
|
|
631
768
|
toggleFileTransferButton.disabled = !enabled;
|
|
632
769
|
|
|
633
770
|
/** @type {String} */
|
|
@@ -655,7 +792,9 @@ device.addEventListener("fileTransferStatus", () => {
|
|
|
655
792
|
/** @type {BS.FileTransferDirection} */
|
|
656
793
|
let fileTransferDirection;
|
|
657
794
|
/** @type {HTMLSelectElement} */
|
|
658
|
-
const fileTransferDirectionSelect = document.getElementById(
|
|
795
|
+
const fileTransferDirectionSelect = document.getElementById(
|
|
796
|
+
"fileTransferDirection"
|
|
797
|
+
);
|
|
659
798
|
fileTransferDirectionSelect.addEventListener("input", () => {
|
|
660
799
|
fileTransferDirection = fileTransferDirectionSelect.value;
|
|
661
800
|
console.log({ fileTransferDirection });
|
|
@@ -759,9 +898,13 @@ device.addEventListener("getTfliteInferencingEnabled", () => {
|
|
|
759
898
|
/** @type {HTMLSpanElement} */
|
|
760
899
|
const tfliteSampleRateSpan = document.getElementById("tfliteSampleRate");
|
|
761
900
|
/** @type {HTMLInputElement} */
|
|
762
|
-
const setTfliteSampleRateInput = document.getElementById(
|
|
901
|
+
const setTfliteSampleRateInput = document.getElementById(
|
|
902
|
+
"setTfliteSampleRateInput"
|
|
903
|
+
);
|
|
763
904
|
/** @type {HTMLButtonElement} */
|
|
764
|
-
const setTfliteSampleRateButton = document.getElementById(
|
|
905
|
+
const setTfliteSampleRateButton = document.getElementById(
|
|
906
|
+
"setTfliteSampleRateButton"
|
|
907
|
+
);
|
|
765
908
|
|
|
766
909
|
device.addEventListener("isConnected", () => {
|
|
767
910
|
const disabled = !device.isConnected;
|
|
@@ -793,16 +936,22 @@ device.addEventListener("getTfliteInferencingEnabled", () => {
|
|
|
793
936
|
|
|
794
937
|
const tfliteSensorTypesContainer = document.getElementById("tfliteSensorTypes");
|
|
795
938
|
/** @type {HTMLTemplateElement} */
|
|
796
|
-
const tfliteSensorTypeTemplate = document.getElementById(
|
|
939
|
+
const tfliteSensorTypeTemplate = document.getElementById(
|
|
940
|
+
"tfliteSensorTypeTemplate"
|
|
941
|
+
);
|
|
797
942
|
/** @type {Object.<string, HTMLElement>} */
|
|
798
943
|
const tfliteSensorTypeContainers = {};
|
|
799
944
|
/** @type {BS.SensorType[]} */
|
|
800
945
|
let tfliteSensorTypes = [];
|
|
801
946
|
/** @type {HTMLButtonElement} */
|
|
802
|
-
const setTfliteSensorTypesButton = document.getElementById(
|
|
947
|
+
const setTfliteSensorTypesButton = document.getElementById(
|
|
948
|
+
"setTfliteSensorTypes"
|
|
949
|
+
);
|
|
803
950
|
|
|
804
951
|
BS.TfliteSensorTypes.forEach((sensorType) => {
|
|
805
|
-
const sensorTypeContainer = tfliteSensorTypeTemplate.content
|
|
952
|
+
const sensorTypeContainer = tfliteSensorTypeTemplate.content
|
|
953
|
+
.cloneNode(true)
|
|
954
|
+
.querySelector(".sensorType");
|
|
806
955
|
sensorTypeContainer.querySelector(".name").innerText = sensorType;
|
|
807
956
|
|
|
808
957
|
/** @type {HTMLInputElement} */
|
|
@@ -817,7 +966,8 @@ BS.TfliteSensorTypes.forEach((sensorType) => {
|
|
|
817
966
|
});
|
|
818
967
|
|
|
819
968
|
device.addEventListener("getTfliteSensorTypes", () => {
|
|
820
|
-
isSensorEnabledInput.checked =
|
|
969
|
+
isSensorEnabledInput.checked =
|
|
970
|
+
device.tfliteSensorTypes.includes(sensorType);
|
|
821
971
|
});
|
|
822
972
|
isSensorEnabledInput.checked = device.tfliteSensorTypes.includes(sensorType);
|
|
823
973
|
|
|
@@ -852,9 +1002,13 @@ device.addEventListener("tfliteIsReady", () => {
|
|
|
852
1002
|
/** @type {HTMLSpanElement} */
|
|
853
1003
|
const tfliteThresholdSpan = document.getElementById("tfliteThreshold");
|
|
854
1004
|
/** @type {HTMLInputElement} */
|
|
855
|
-
const setTfliteThresholdInput = document.getElementById(
|
|
1005
|
+
const setTfliteThresholdInput = document.getElementById(
|
|
1006
|
+
"setTfliteThresholdInput"
|
|
1007
|
+
);
|
|
856
1008
|
/** @type {HTMLButtonElement} */
|
|
857
|
-
const setTfliteThresholdButton = document.getElementById(
|
|
1009
|
+
const setTfliteThresholdButton = document.getElementById(
|
|
1010
|
+
"setTfliteThresholdButton"
|
|
1011
|
+
);
|
|
858
1012
|
|
|
859
1013
|
device.addEventListener("isConnected", () => {
|
|
860
1014
|
const disabled = !device.isConnected;
|
|
@@ -884,9 +1038,13 @@ setTfliteThresholdButton.addEventListener("click", () => {
|
|
|
884
1038
|
/** @type {HTMLSpanElement} */
|
|
885
1039
|
const tfliteCaptureDelaySpan = document.getElementById("tfliteCaptureDelay");
|
|
886
1040
|
/** @type {HTMLInputElement} */
|
|
887
|
-
const setTfliteCaptureDelayInput = document.getElementById(
|
|
1041
|
+
const setTfliteCaptureDelayInput = document.getElementById(
|
|
1042
|
+
"setTfliteCaptureDelayInput"
|
|
1043
|
+
);
|
|
888
1044
|
/** @type {HTMLButtonElement} */
|
|
889
|
-
const setTfliteCaptureDelayButton = document.getElementById(
|
|
1045
|
+
const setTfliteCaptureDelayButton = document.getElementById(
|
|
1046
|
+
"setTfliteCaptureDelayButton"
|
|
1047
|
+
);
|
|
890
1048
|
|
|
891
1049
|
device.addEventListener("isConnected", () => {
|
|
892
1050
|
const disabled = !device.isConnected;
|
|
@@ -914,18 +1072,23 @@ setTfliteCaptureDelayButton.addEventListener("click", () => {
|
|
|
914
1072
|
});
|
|
915
1073
|
|
|
916
1074
|
/** @type {HTMLInputElement} */
|
|
917
|
-
const tfliteInferencingEnabledInput = document.getElementById(
|
|
1075
|
+
const tfliteInferencingEnabledInput = document.getElementById(
|
|
1076
|
+
"tfliteInferencingEnabled"
|
|
1077
|
+
);
|
|
918
1078
|
/** @type {HTMLButtonElement} */
|
|
919
|
-
const toggleTfliteInferencingEnabledButton = document.getElementById(
|
|
1079
|
+
const toggleTfliteInferencingEnabledButton = document.getElementById(
|
|
1080
|
+
"toggleTfliteInferencingEnabled"
|
|
1081
|
+
);
|
|
920
1082
|
|
|
921
1083
|
device.addEventListener("tfliteIsReady", () => {
|
|
922
1084
|
toggleTfliteInferencingEnabledButton.disabled = !device.tfliteIsReady;
|
|
923
1085
|
});
|
|
924
1086
|
device.addEventListener("getTfliteInferencingEnabled", () => {
|
|
925
1087
|
tfliteInferencingEnabledInput.checked = device.tfliteInferencingEnabled;
|
|
926
|
-
toggleTfliteInferencingEnabledButton.innerText =
|
|
927
|
-
|
|
928
|
-
|
|
1088
|
+
toggleTfliteInferencingEnabledButton.innerText =
|
|
1089
|
+
device.tfliteInferencingEnabled
|
|
1090
|
+
? "disable inferencing"
|
|
1091
|
+
: "enable inferencing";
|
|
929
1092
|
});
|
|
930
1093
|
|
|
931
1094
|
toggleTfliteInferencingEnabledButton.addEventListener("click", () => {
|
|
@@ -958,7 +1121,8 @@ device.addEventListener("tfliteInference", (event) => {
|
|
|
958
1121
|
tfliteInferencePre.textContent = JSON.stringify(tfliteInference, null, 2);
|
|
959
1122
|
|
|
960
1123
|
if (device.tfliteTask == "classification") {
|
|
961
|
-
topInferenceClassElement.innerText =
|
|
1124
|
+
topInferenceClassElement.innerText =
|
|
1125
|
+
inferenceClasses[tfliteInference.maxIndex - 1] ?? "";
|
|
962
1126
|
}
|
|
963
1127
|
});
|
|
964
1128
|
|
|
@@ -974,7 +1138,9 @@ firmwareInput.addEventListener("input", () => {
|
|
|
974
1138
|
updateToggleFirmwareUploadButton();
|
|
975
1139
|
});
|
|
976
1140
|
/** @type {HTMLButtonElement} */
|
|
977
|
-
const toggleFirmwareUploadButton = document.getElementById(
|
|
1141
|
+
const toggleFirmwareUploadButton = document.getElementById(
|
|
1142
|
+
"toggleFirmwareUpload"
|
|
1143
|
+
);
|
|
978
1144
|
toggleFirmwareUploadButton.addEventListener("click", () => {
|
|
979
1145
|
device.uploadFirmware(firmware);
|
|
980
1146
|
});
|
|
@@ -987,20 +1153,28 @@ device.addEventListener("isConnected", () => {
|
|
|
987
1153
|
});
|
|
988
1154
|
|
|
989
1155
|
/** @type {HTMLProgressElement} */
|
|
990
|
-
const firmwareUploadProgress = document.getElementById(
|
|
1156
|
+
const firmwareUploadProgress = document.getElementById(
|
|
1157
|
+
"firmwareUploadProgress"
|
|
1158
|
+
);
|
|
991
1159
|
/** @type {HTMLSpanElement} */
|
|
992
|
-
const firmwareUploadProgressPercentageSpan = document.getElementById(
|
|
1160
|
+
const firmwareUploadProgressPercentageSpan = document.getElementById(
|
|
1161
|
+
"firmwareUploadProgressPercentage"
|
|
1162
|
+
);
|
|
993
1163
|
device.addEventListener("firmwareUploadProgress", (event) => {
|
|
994
1164
|
const progress = event.message.progress;
|
|
995
1165
|
firmwareUploadProgress.value = progress;
|
|
996
|
-
firmwareUploadProgressPercentageSpan.innerText = `${Math.floor(
|
|
1166
|
+
firmwareUploadProgressPercentageSpan.innerText = `${Math.floor(
|
|
1167
|
+
100 * progress
|
|
1168
|
+
)}%`;
|
|
997
1169
|
});
|
|
998
1170
|
device.addEventListener("firmwareUploadComplete", () => {
|
|
999
1171
|
firmwareUploadProgress.value = 0;
|
|
1000
1172
|
});
|
|
1001
1173
|
device.addEventListener("firmwareStatus", () => {
|
|
1002
1174
|
const isUploading = device.firmwareStatus == "uploading";
|
|
1003
|
-
firmwareUploadProgressPercentageSpan.style.display = isUploading
|
|
1175
|
+
firmwareUploadProgressPercentageSpan.style.display = isUploading
|
|
1176
|
+
? ""
|
|
1177
|
+
: "none";
|
|
1004
1178
|
});
|
|
1005
1179
|
|
|
1006
1180
|
/** @type {HTMLPreElement} */
|
|
@@ -1040,7 +1214,7 @@ resetButton.addEventListener("click", () => {
|
|
|
1040
1214
|
const updateResetButton = () => {
|
|
1041
1215
|
const status = device.firmwareStatus;
|
|
1042
1216
|
const enabled = status == "pending" || status == "testing";
|
|
1043
|
-
resetButton.disabled = !enabled;
|
|
1217
|
+
resetButton.disabled = !enabled || !device.canReset;
|
|
1044
1218
|
};
|
|
1045
1219
|
|
|
1046
1220
|
/** @type {HTMLButtonElement} */
|
|
@@ -1054,12 +1228,15 @@ const updateTestFirmwareImageButton = () => {
|
|
|
1054
1228
|
};
|
|
1055
1229
|
|
|
1056
1230
|
/** @type {HTMLButtonElement} */
|
|
1057
|
-
const confirmFirmwareImageButton = document.getElementById(
|
|
1231
|
+
const confirmFirmwareImageButton = document.getElementById(
|
|
1232
|
+
"confirmFirmwareImage"
|
|
1233
|
+
);
|
|
1058
1234
|
confirmFirmwareImageButton.addEventListener("click", () => {
|
|
1059
1235
|
device.confirmFirmwareImage(selectedImageIndex);
|
|
1060
1236
|
});
|
|
1061
1237
|
const updateConfirmFirmwareImageButton = () => {
|
|
1062
|
-
const enabled =
|
|
1238
|
+
const enabled =
|
|
1239
|
+
device.firmwareStatus == "testing" || device.firmwareStatus == "uploaded";
|
|
1063
1240
|
confirmFirmwareImageButton.disabled = !enabled;
|
|
1064
1241
|
};
|
|
1065
1242
|
|
|
@@ -1080,7 +1257,10 @@ const imageSelectionOptGroup = imageSelectionSelect.querySelector("optgroup");
|
|
|
1080
1257
|
device.addEventListener("firmwareImages", () => {
|
|
1081
1258
|
imageSelectionOptGroup.innerHTML = "";
|
|
1082
1259
|
device.firmwareImages.forEach((firmwareImage, index) => {
|
|
1083
|
-
const option = new Option(
|
|
1260
|
+
const option = new Option(
|
|
1261
|
+
`${firmwareImage.version} (slot ${index})`,
|
|
1262
|
+
index
|
|
1263
|
+
);
|
|
1084
1264
|
option.disabled = firmwareImage.empty;
|
|
1085
1265
|
imageSelectionOptGroup.appendChild(option);
|
|
1086
1266
|
});
|
|
@@ -1105,3 +1285,676 @@ function updateSelectImageSelect() {
|
|
|
1105
1285
|
}
|
|
1106
1286
|
imageSelectionSelect.disabled = !enabled;
|
|
1107
1287
|
}
|
|
1288
|
+
|
|
1289
|
+
// WIFI
|
|
1290
|
+
|
|
1291
|
+
/** @type {HTMLSpanElement} */
|
|
1292
|
+
const isWifiAvailableSpan = document.getElementById("isWifiAvailable");
|
|
1293
|
+
device.addEventListener("isWifiAvailable", (event) => {
|
|
1294
|
+
isWifiAvailableSpan.innerText = event.message.isWifiAvailable;
|
|
1295
|
+
});
|
|
1296
|
+
|
|
1297
|
+
/** @type {HTMLSpanElement} */
|
|
1298
|
+
const wifiSSIDSpan = document.getElementById("wifiSSID");
|
|
1299
|
+
device.addEventListener("getWifiSSID", (event) => {
|
|
1300
|
+
wifiSSIDSpan.innerText = event.message.wifiSSID;
|
|
1301
|
+
});
|
|
1302
|
+
/** @type {HTMLInputElement} */
|
|
1303
|
+
const setWifiSSIDInput = document.getElementById("setWifiSSIDInput");
|
|
1304
|
+
setWifiSSIDInput.min = BS.MinWifiSSIDLength;
|
|
1305
|
+
setWifiSSIDInput.max = BS.MaxWifiSSIDLength;
|
|
1306
|
+
setWifiSSIDInput.addEventListener("input", () => {
|
|
1307
|
+
setWifiSSIDButton.disabled = !(
|
|
1308
|
+
setWifiSSIDInput.value.length > BS.MinWifiSSIDLength &&
|
|
1309
|
+
setWifiSSIDInput.value.length < BS.MaxWifiSSIDLength
|
|
1310
|
+
);
|
|
1311
|
+
});
|
|
1312
|
+
/** @type {HTMLButtonElement} */
|
|
1313
|
+
const setWifiSSIDButton = document.getElementById("setWifiSSIDButton");
|
|
1314
|
+
setWifiSSIDButton.addEventListener("click", async () => {
|
|
1315
|
+
setWifiSSIDButton.disabled = true;
|
|
1316
|
+
setWifiSSIDButton.innerText = "setting wifi ssid";
|
|
1317
|
+
await device.setWifiSSID(setWifiSSIDInput.value);
|
|
1318
|
+
setWifiSSIDInput.value = "";
|
|
1319
|
+
setWifiSSIDButton.disabled = false;
|
|
1320
|
+
setWifiSSIDButton.innerText = "set wifi ssid";
|
|
1321
|
+
});
|
|
1322
|
+
|
|
1323
|
+
/** @type {HTMLSpanElement} */
|
|
1324
|
+
const wifiPasswordSpan = document.getElementById("wifiPassword");
|
|
1325
|
+
device.addEventListener("getWifiPassword", (event) => {
|
|
1326
|
+
wifiPasswordSpan.innerText = event.message.wifiPassword;
|
|
1327
|
+
});
|
|
1328
|
+
/** @type {HTMLInputElement} */
|
|
1329
|
+
const setWifiPasswordInput = document.getElementById("setWifiPasswordInput");
|
|
1330
|
+
setWifiPasswordInput.min = BS.MinWifiPasswordLength;
|
|
1331
|
+
setWifiPasswordInput.max = BS.MaxWifiPasswordLength;
|
|
1332
|
+
setWifiPasswordInput.addEventListener("input", () => {
|
|
1333
|
+
const length = setWifiPasswordInput.value.length;
|
|
1334
|
+
setWifiPasswordButton.disabled = !(
|
|
1335
|
+
length == 0 ||
|
|
1336
|
+
(length > BS.MinWifiPasswordLength && length < BS.MaxWifiPasswordLength)
|
|
1337
|
+
);
|
|
1338
|
+
});
|
|
1339
|
+
/** @type {HTMLButtonElement} */
|
|
1340
|
+
const setWifiPasswordButton = document.getElementById("setWifiPasswordButton");
|
|
1341
|
+
setWifiPasswordButton.addEventListener("click", async () => {
|
|
1342
|
+
setWifiPasswordButton.disabled = true;
|
|
1343
|
+
setWifiPasswordButton.innerText = "setting wifi password";
|
|
1344
|
+
await device.setWifiPassword(setWifiPasswordInput.value);
|
|
1345
|
+
setWifiPasswordInput.value = "";
|
|
1346
|
+
setWifiPasswordButton.disabled = false;
|
|
1347
|
+
setWifiPasswordButton.innerText = "set wifi password";
|
|
1348
|
+
});
|
|
1349
|
+
|
|
1350
|
+
const updateWifiInputs = () => {
|
|
1351
|
+
const enabled =
|
|
1352
|
+
device.isConnected &&
|
|
1353
|
+
device.isWifiAvailable &&
|
|
1354
|
+
!device.wifiConnectionEnabled;
|
|
1355
|
+
const disabled = !enabled;
|
|
1356
|
+
|
|
1357
|
+
setWifiPasswordInput.disabled = disabled;
|
|
1358
|
+
setWifiPasswordButton.disabled = disabled;
|
|
1359
|
+
|
|
1360
|
+
setWifiSSIDInput.disabled = disabled;
|
|
1361
|
+
setWifiSSIDButton.disabled = disabled;
|
|
1362
|
+
|
|
1363
|
+
toggleWifiConnectionButton.disabled = !(
|
|
1364
|
+
device.isConnected && device.isWifiAvailable
|
|
1365
|
+
);
|
|
1366
|
+
};
|
|
1367
|
+
device.addEventListener("isConnected", () => {
|
|
1368
|
+
updateWifiInputs();
|
|
1369
|
+
});
|
|
1370
|
+
device.addEventListener("getWifiConnectionEnabled", () => {
|
|
1371
|
+
updateWifiInputs();
|
|
1372
|
+
});
|
|
1373
|
+
|
|
1374
|
+
/** @type {HTMLSpanElement} */
|
|
1375
|
+
const wifiConnectionEnabledSpan = document.getElementById(
|
|
1376
|
+
"wifiConnectionEnabled"
|
|
1377
|
+
);
|
|
1378
|
+
device.addEventListener("getWifiConnectionEnabled", (event) => {
|
|
1379
|
+
wifiConnectionEnabledSpan.innerText = event.message.wifiConnectionEnabled;
|
|
1380
|
+
});
|
|
1381
|
+
|
|
1382
|
+
/** @type {HTMLSpanElement} */
|
|
1383
|
+
const isWifiConnectedSpan = document.getElementById("isWifiConnected");
|
|
1384
|
+
device.addEventListener("isWifiConnected", (event) => {
|
|
1385
|
+
isWifiConnectedSpan.innerText = event.message.isWifiConnected;
|
|
1386
|
+
});
|
|
1387
|
+
|
|
1388
|
+
/** @type {HTMLSpanElement} */
|
|
1389
|
+
const ipAddressSpan = document.getElementById("ipAddress");
|
|
1390
|
+
device.addEventListener("ipAddress", (event) => {
|
|
1391
|
+
ipAddressSpan.innerText = event.message.ipAddress || "none";
|
|
1392
|
+
});
|
|
1393
|
+
|
|
1394
|
+
/** @type {HTMLButtonElement} */
|
|
1395
|
+
const toggleWifiConnectionButton = document.getElementById(
|
|
1396
|
+
"toggleWifiConnection"
|
|
1397
|
+
);
|
|
1398
|
+
toggleWifiConnectionButton.addEventListener("click", async () => {
|
|
1399
|
+
toggleWifiConnectionButton.disabled = true;
|
|
1400
|
+
await device.toggleWifiConnection();
|
|
1401
|
+
toggleWifiConnectionButton.disabled = false;
|
|
1402
|
+
});
|
|
1403
|
+
device.addEventListener("getWifiConnectionEnabled", (event) => {
|
|
1404
|
+
toggleWifiConnectionButton.innerText = event.message.wifiConnectionEnabled
|
|
1405
|
+
? "disable wifi connection"
|
|
1406
|
+
: "enable wifi connection";
|
|
1407
|
+
});
|
|
1408
|
+
|
|
1409
|
+
/** @type {HTMLButtonElement} */
|
|
1410
|
+
const connectViaWebSocketsButton = document.getElementById(
|
|
1411
|
+
"connectViaWebSockets"
|
|
1412
|
+
);
|
|
1413
|
+
connectViaWebSocketsButton.addEventListener("click", async () => {
|
|
1414
|
+
toggleWifiConnectionButton.disabled = true;
|
|
1415
|
+
device.reconnectViaWebSockets();
|
|
1416
|
+
});
|
|
1417
|
+
const updateConnectViaWebSocketsButton = () => {
|
|
1418
|
+
const enabled =
|
|
1419
|
+
device.isConnected &&
|
|
1420
|
+
device.connectionType == "webBluetooth" &&
|
|
1421
|
+
device.isWifiConnected;
|
|
1422
|
+
console.log({ enabled });
|
|
1423
|
+
connectViaWebSocketsButton.disabled = !enabled;
|
|
1424
|
+
};
|
|
1425
|
+
device.addEventListener("isWifiConnected", () =>
|
|
1426
|
+
updateConnectViaWebSocketsButton()
|
|
1427
|
+
);
|
|
1428
|
+
device.addEventListener("isConnected", () =>
|
|
1429
|
+
updateConnectViaWebSocketsButton()
|
|
1430
|
+
);
|
|
1431
|
+
|
|
1432
|
+
// CAMERA
|
|
1433
|
+
/** @type {HTMLSpanElement} */
|
|
1434
|
+
const isCameraAvailableSpan = document.getElementById("isCameraAvailable");
|
|
1435
|
+
device.addEventListener("connected", () => {
|
|
1436
|
+
isCameraAvailableSpan.innerText = device.hasCamera;
|
|
1437
|
+
});
|
|
1438
|
+
|
|
1439
|
+
/** @type {HTMLSpanElement} */
|
|
1440
|
+
const cameraStatusSpan = document.getElementById("cameraStatus");
|
|
1441
|
+
device.addEventListener("cameraStatus", () => {
|
|
1442
|
+
cameraStatusSpan.innerText = device.cameraStatus;
|
|
1443
|
+
});
|
|
1444
|
+
|
|
1445
|
+
/** @type {HTMLButtonElement} */
|
|
1446
|
+
const takePictureButton = document.getElementById("takePicture");
|
|
1447
|
+
takePictureButton.addEventListener("click", () => {
|
|
1448
|
+
if (device.cameraStatus == "idle") {
|
|
1449
|
+
device.takePicture();
|
|
1450
|
+
} else {
|
|
1451
|
+
device.stopCamera();
|
|
1452
|
+
}
|
|
1453
|
+
});
|
|
1454
|
+
device.addEventListener("connected", () => {
|
|
1455
|
+
updateTakePictureButton();
|
|
1456
|
+
});
|
|
1457
|
+
device.addEventListener("getSensorConfiguration", () => {
|
|
1458
|
+
updateTakePictureButton();
|
|
1459
|
+
});
|
|
1460
|
+
const updateTakePictureButton = () => {
|
|
1461
|
+
takePictureButton.disabled =
|
|
1462
|
+
!device.isConnected ||
|
|
1463
|
+
device.sensorConfiguration.camera == 0 ||
|
|
1464
|
+
device.cameraStatus != "idle";
|
|
1465
|
+
};
|
|
1466
|
+
device.addEventListener("cameraStatus", () => {
|
|
1467
|
+
updateTakePictureButton();
|
|
1468
|
+
});
|
|
1469
|
+
|
|
1470
|
+
/** @type {HTMLButtonElement} */
|
|
1471
|
+
const focusCameraButton = document.getElementById("focusCamera");
|
|
1472
|
+
focusCameraButton.addEventListener("click", () => {
|
|
1473
|
+
if (device.cameraStatus == "idle") {
|
|
1474
|
+
device.focusCamera();
|
|
1475
|
+
} else {
|
|
1476
|
+
device.stopCamera();
|
|
1477
|
+
}
|
|
1478
|
+
});
|
|
1479
|
+
device.addEventListener("connected", () => {
|
|
1480
|
+
updateFocusCameraButton();
|
|
1481
|
+
});
|
|
1482
|
+
device.addEventListener("getSensorConfiguration", () => {
|
|
1483
|
+
updateFocusCameraButton();
|
|
1484
|
+
});
|
|
1485
|
+
const updateFocusCameraButton = () => {
|
|
1486
|
+
focusCameraButton.disabled =
|
|
1487
|
+
!device.isConnected ||
|
|
1488
|
+
device.sensorConfiguration.camera == 0 ||
|
|
1489
|
+
device.cameraStatus != "idle";
|
|
1490
|
+
};
|
|
1491
|
+
device.addEventListener("cameraStatus", (event) => {
|
|
1492
|
+
updateFocusCameraButton();
|
|
1493
|
+
if (
|
|
1494
|
+
device.cameraStatus == "idle" &&
|
|
1495
|
+
event.message.previousCameraStatus == "focusing"
|
|
1496
|
+
) {
|
|
1497
|
+
device.takePicture();
|
|
1498
|
+
}
|
|
1499
|
+
});
|
|
1500
|
+
|
|
1501
|
+
/** @type {HTMLButtonElement} */
|
|
1502
|
+
const sleepCameraButton = document.getElementById("sleepCamera");
|
|
1503
|
+
sleepCameraButton.addEventListener("click", () => {
|
|
1504
|
+
if (device.cameraStatus == "asleep") {
|
|
1505
|
+
device.wakeCamera();
|
|
1506
|
+
} else {
|
|
1507
|
+
device.sleepCamera();
|
|
1508
|
+
}
|
|
1509
|
+
});
|
|
1510
|
+
device.addEventListener("connected", () => {
|
|
1511
|
+
updateSleepCameraButton();
|
|
1512
|
+
});
|
|
1513
|
+
device.addEventListener("getSensorConfiguration", () => {
|
|
1514
|
+
updateSleepCameraButton();
|
|
1515
|
+
});
|
|
1516
|
+
const updateSleepCameraButton = () => {
|
|
1517
|
+
let disabled = !device.isConnected || !device.hasCamera;
|
|
1518
|
+
switch (device.cameraStatus) {
|
|
1519
|
+
case "asleep":
|
|
1520
|
+
sleepCameraButton.innerText = "wake camera";
|
|
1521
|
+
break;
|
|
1522
|
+
case "idle":
|
|
1523
|
+
sleepCameraButton.innerText = "sleep camera";
|
|
1524
|
+
break;
|
|
1525
|
+
default:
|
|
1526
|
+
disabled = true;
|
|
1527
|
+
break;
|
|
1528
|
+
}
|
|
1529
|
+
sleepCameraButton.disabled = disabled;
|
|
1530
|
+
};
|
|
1531
|
+
device.addEventListener("cameraStatus", () => {
|
|
1532
|
+
updateSleepCameraButton();
|
|
1533
|
+
});
|
|
1534
|
+
|
|
1535
|
+
/** @type {HTMLImageElement} */
|
|
1536
|
+
const cameraImage = document.getElementById("cameraImage");
|
|
1537
|
+
device.addEventListener("cameraImage", (event) => {
|
|
1538
|
+
cameraImage.src = event.message.url;
|
|
1539
|
+
});
|
|
1540
|
+
|
|
1541
|
+
/** @type {HTMLProgressElement} */
|
|
1542
|
+
const cameraImageProgress = document.getElementById("cameraImageProgress");
|
|
1543
|
+
device.addEventListener("cameraImageProgress", (event) => {
|
|
1544
|
+
if (event.message.type == "image") {
|
|
1545
|
+
cameraImageProgress.value = event.message.progress;
|
|
1546
|
+
}
|
|
1547
|
+
});
|
|
1548
|
+
|
|
1549
|
+
/** @type {HTMLInputElement} */
|
|
1550
|
+
const autoPictureCheckbox = document.getElementById("autoPicture");
|
|
1551
|
+
let autoPicture = autoPictureCheckbox.checked;
|
|
1552
|
+
autoPictureCheckbox.addEventListener("input", () => {
|
|
1553
|
+
autoPicture = autoPictureCheckbox.checked;
|
|
1554
|
+
});
|
|
1555
|
+
device.addEventListener("cameraImage", () => {
|
|
1556
|
+
if (autoPicture) {
|
|
1557
|
+
device.takePicture();
|
|
1558
|
+
}
|
|
1559
|
+
});
|
|
1560
|
+
|
|
1561
|
+
/** @type {HTMLPreElement} */
|
|
1562
|
+
const cameraConfigurationPre = document.getElementById(
|
|
1563
|
+
"cameraConfigurationPre"
|
|
1564
|
+
);
|
|
1565
|
+
device.addEventListener("getCameraConfiguration", () => {
|
|
1566
|
+
cameraConfigurationPre.textContent = JSON.stringify(
|
|
1567
|
+
device.cameraConfiguration,
|
|
1568
|
+
null,
|
|
1569
|
+
2
|
|
1570
|
+
);
|
|
1571
|
+
});
|
|
1572
|
+
|
|
1573
|
+
const cameraConfigurationContainer = document.getElementById(
|
|
1574
|
+
"cameraConfiguration"
|
|
1575
|
+
);
|
|
1576
|
+
/** @type {HTMLTemplateElement} */
|
|
1577
|
+
const cameraConfigurationTypeTemplate = document.getElementById(
|
|
1578
|
+
"cameraConfigurationTypeTemplate"
|
|
1579
|
+
);
|
|
1580
|
+
BS.CameraConfigurationTypes.forEach((cameraConfigurationType) => {
|
|
1581
|
+
const cameraConfigurationTypeContainer =
|
|
1582
|
+
cameraConfigurationTypeTemplate.content
|
|
1583
|
+
.cloneNode(true)
|
|
1584
|
+
.querySelector(".cameraConfigurationType");
|
|
1585
|
+
|
|
1586
|
+
cameraConfigurationContainer.appendChild(cameraConfigurationTypeContainer);
|
|
1587
|
+
|
|
1588
|
+
cameraConfigurationTypeContainer.querySelector(".type").innerText =
|
|
1589
|
+
cameraConfigurationType;
|
|
1590
|
+
|
|
1591
|
+
/** @type {HTMLInputElement} */
|
|
1592
|
+
const input = cameraConfigurationTypeContainer.querySelector("input");
|
|
1593
|
+
|
|
1594
|
+
/** @type {HTMLSpanElement} */
|
|
1595
|
+
const span = cameraConfigurationTypeContainer.querySelector("span");
|
|
1596
|
+
|
|
1597
|
+
device.addEventListener("isConnected", () => {
|
|
1598
|
+
updateisInputDisabled();
|
|
1599
|
+
});
|
|
1600
|
+
device.addEventListener("cameraStatus", () => {
|
|
1601
|
+
updateisInputDisabled();
|
|
1602
|
+
});
|
|
1603
|
+
const updateisInputDisabled = () => {
|
|
1604
|
+
input.disabled =
|
|
1605
|
+
!device.isConnected || !device.hasCamera || device.cameraStatus != "idle";
|
|
1606
|
+
};
|
|
1607
|
+
|
|
1608
|
+
const updateInput = () => {
|
|
1609
|
+
const value = device.cameraConfiguration[cameraConfigurationType];
|
|
1610
|
+
span.innerText = value;
|
|
1611
|
+
input.value = value;
|
|
1612
|
+
};
|
|
1613
|
+
|
|
1614
|
+
device.addEventListener("connected", () => {
|
|
1615
|
+
if (!device.hasCamera) {
|
|
1616
|
+
return;
|
|
1617
|
+
}
|
|
1618
|
+
const range = device.cameraConfigurationRanges[cameraConfigurationType];
|
|
1619
|
+
input.min = range.min;
|
|
1620
|
+
input.max = range.max;
|
|
1621
|
+
|
|
1622
|
+
updateInput();
|
|
1623
|
+
});
|
|
1624
|
+
|
|
1625
|
+
device.addEventListener("getCameraConfiguration", () => {
|
|
1626
|
+
updateInput();
|
|
1627
|
+
});
|
|
1628
|
+
|
|
1629
|
+
input.addEventListener("change", () => {
|
|
1630
|
+
const value = Number(input.value);
|
|
1631
|
+
// console.log(`updating ${cameraConfigurationType} to ${value}`);
|
|
1632
|
+
device.setCameraConfiguration({
|
|
1633
|
+
[cameraConfigurationType]: value,
|
|
1634
|
+
});
|
|
1635
|
+
if (takePictureAfterUpdate) {
|
|
1636
|
+
device.addEventListener(
|
|
1637
|
+
"getCameraConfiguration",
|
|
1638
|
+
() => {
|
|
1639
|
+
setTimeout(() => device.takePicture()), 100;
|
|
1640
|
+
},
|
|
1641
|
+
{ once: true }
|
|
1642
|
+
);
|
|
1643
|
+
}
|
|
1644
|
+
});
|
|
1645
|
+
});
|
|
1646
|
+
|
|
1647
|
+
/** @type {HTMLInputElement} */
|
|
1648
|
+
const takePictureAfterUpdateCheckbox = document.getElementById(
|
|
1649
|
+
"takePictureAfterUpdate"
|
|
1650
|
+
);
|
|
1651
|
+
let takePictureAfterUpdate = false;
|
|
1652
|
+
takePictureAfterUpdateCheckbox.addEventListener("input", () => {
|
|
1653
|
+
takePictureAfterUpdate = takePictureAfterUpdateCheckbox.checked;
|
|
1654
|
+
console.log({ takePictureAfterUpdate });
|
|
1655
|
+
});
|
|
1656
|
+
|
|
1657
|
+
/** @type {HTMLInputElement} */
|
|
1658
|
+
const cameraWhiteBalanceInput = document.getElementById("cameraWhiteBalance");
|
|
1659
|
+
const updateWhiteBalance = BS.ThrottleUtils.throttle(
|
|
1660
|
+
(config) => {
|
|
1661
|
+
if (device.cameraStatus != "idle") {
|
|
1662
|
+
return;
|
|
1663
|
+
}
|
|
1664
|
+
|
|
1665
|
+
device.setCameraConfiguration(config);
|
|
1666
|
+
|
|
1667
|
+
if (takePictureAfterUpdate) {
|
|
1668
|
+
device.addEventListener(
|
|
1669
|
+
"getCameraConfiguration",
|
|
1670
|
+
() => {
|
|
1671
|
+
setTimeout(() => device.takePicture()), 100;
|
|
1672
|
+
},
|
|
1673
|
+
{ once: true }
|
|
1674
|
+
);
|
|
1675
|
+
}
|
|
1676
|
+
},
|
|
1677
|
+
200,
|
|
1678
|
+
true
|
|
1679
|
+
);
|
|
1680
|
+
cameraWhiteBalanceInput.addEventListener("input", () => {
|
|
1681
|
+
let [redGain, greenGain, blueGain] = cameraWhiteBalanceInput.value
|
|
1682
|
+
.replace("#", "")
|
|
1683
|
+
.match(/.{1,2}/g)
|
|
1684
|
+
.map((value) => Number(`0x${value}`))
|
|
1685
|
+
.map((value) => value / 255)
|
|
1686
|
+
.map((value) => value * device.cameraConfigurationRanges.blueGain.max)
|
|
1687
|
+
.map((value) => Math.round(value));
|
|
1688
|
+
|
|
1689
|
+
updateWhiteBalance({ redGain, greenGain, blueGain });
|
|
1690
|
+
});
|
|
1691
|
+
const updateCameraWhiteBalanceInput = () => {
|
|
1692
|
+
if (!device.hasCamera) {
|
|
1693
|
+
return;
|
|
1694
|
+
}
|
|
1695
|
+
cameraWhiteBalanceInput.disabled =
|
|
1696
|
+
!device.isConnected || !device.hasCamera || device.cameraStatus != "idle";
|
|
1697
|
+
|
|
1698
|
+
const { redGain, blueGain, greenGain } = device.cameraConfiguration;
|
|
1699
|
+
|
|
1700
|
+
cameraWhiteBalanceInput.value = `#${[redGain, blueGain, greenGain]
|
|
1701
|
+
.map((value) => value / device.cameraConfigurationRanges.redGain.max)
|
|
1702
|
+
.map((value) => value * 255)
|
|
1703
|
+
.map((value) => Math.round(value))
|
|
1704
|
+
.map((value) => value.toString(16))
|
|
1705
|
+
.join("")}`;
|
|
1706
|
+
};
|
|
1707
|
+
device.addEventListener("connected", () => {
|
|
1708
|
+
updateCameraWhiteBalanceInput();
|
|
1709
|
+
});
|
|
1710
|
+
device.addEventListener("getCameraConfiguration", () => {
|
|
1711
|
+
updateCameraWhiteBalanceInput();
|
|
1712
|
+
});
|
|
1713
|
+
|
|
1714
|
+
// MICROPHONE
|
|
1715
|
+
|
|
1716
|
+
/** @type {HTMLSpanElement} */
|
|
1717
|
+
const isMicrophoneAvailableSpan = document.getElementById(
|
|
1718
|
+
"isMicrophoneAvailable"
|
|
1719
|
+
);
|
|
1720
|
+
device.addEventListener("connected", () => {
|
|
1721
|
+
isMicrophoneAvailableSpan.innerText = device.hasMicrophone;
|
|
1722
|
+
});
|
|
1723
|
+
|
|
1724
|
+
/** @type {HTMLSpanElement} */
|
|
1725
|
+
const microphoneStatusSpan = document.getElementById("microphoneStatus");
|
|
1726
|
+
device.addEventListener("microphoneStatus", () => {
|
|
1727
|
+
microphoneStatusSpan.innerText = device.microphoneStatus;
|
|
1728
|
+
});
|
|
1729
|
+
|
|
1730
|
+
/** @type {HTMLPreElement} */
|
|
1731
|
+
const microphoneConfigurationPre = document.getElementById(
|
|
1732
|
+
"microphoneConfigurationPre"
|
|
1733
|
+
);
|
|
1734
|
+
device.addEventListener("getMicrophoneConfiguration", () => {
|
|
1735
|
+
microphoneConfigurationPre.textContent = JSON.stringify(
|
|
1736
|
+
device.microphoneConfiguration,
|
|
1737
|
+
null,
|
|
1738
|
+
2
|
|
1739
|
+
);
|
|
1740
|
+
});
|
|
1741
|
+
|
|
1742
|
+
const microphoneConfigurationContainer = document.getElementById(
|
|
1743
|
+
"microphoneConfiguration"
|
|
1744
|
+
);
|
|
1745
|
+
/** @type {HTMLTemplateElement} */
|
|
1746
|
+
const microphoneConfigurationTypeTemplate = document.getElementById(
|
|
1747
|
+
"microphoneConfigurationTypeTemplate"
|
|
1748
|
+
);
|
|
1749
|
+
BS.MicrophoneConfigurationTypes.forEach((microphoneConfigurationType) => {
|
|
1750
|
+
const microphoneConfigurationTypeContainer =
|
|
1751
|
+
microphoneConfigurationTypeTemplate.content
|
|
1752
|
+
.cloneNode(true)
|
|
1753
|
+
.querySelector(".microphoneConfigurationType");
|
|
1754
|
+
|
|
1755
|
+
microphoneConfigurationContainer.appendChild(
|
|
1756
|
+
microphoneConfigurationTypeContainer
|
|
1757
|
+
);
|
|
1758
|
+
|
|
1759
|
+
microphoneConfigurationTypeContainer.querySelector(".type").innerText =
|
|
1760
|
+
microphoneConfigurationType;
|
|
1761
|
+
|
|
1762
|
+
/** @type {HTMLSelectElement} */
|
|
1763
|
+
const select = microphoneConfigurationTypeContainer.querySelector("select");
|
|
1764
|
+
/** @type {HTMLOptGroupElement} */
|
|
1765
|
+
const optgroup = select.querySelector("optgroup");
|
|
1766
|
+
optgroup.label = microphoneConfigurationType;
|
|
1767
|
+
|
|
1768
|
+
BS.MicrophoneConfigurationValues[microphoneConfigurationType].forEach(
|
|
1769
|
+
(value) => {
|
|
1770
|
+
optgroup.appendChild(new Option(value));
|
|
1771
|
+
}
|
|
1772
|
+
);
|
|
1773
|
+
|
|
1774
|
+
/** @type {HTMLSpanElement} */
|
|
1775
|
+
const span = microphoneConfigurationTypeContainer.querySelector("span");
|
|
1776
|
+
|
|
1777
|
+
device.addEventListener("isConnected", () => {
|
|
1778
|
+
updateisInputDisabled();
|
|
1779
|
+
});
|
|
1780
|
+
device.addEventListener("microphoneStatus", () => {
|
|
1781
|
+
updateisInputDisabled();
|
|
1782
|
+
});
|
|
1783
|
+
const updateisInputDisabled = () => {
|
|
1784
|
+
select.disabled =
|
|
1785
|
+
!device.isConnected ||
|
|
1786
|
+
!device.hasMicrophone ||
|
|
1787
|
+
device.microphoneStatus != "idle";
|
|
1788
|
+
};
|
|
1789
|
+
|
|
1790
|
+
const updateSelect = () => {
|
|
1791
|
+
const value = device.microphoneConfiguration[microphoneConfigurationType];
|
|
1792
|
+
span.innerText = value;
|
|
1793
|
+
select.value = value;
|
|
1794
|
+
};
|
|
1795
|
+
|
|
1796
|
+
device.addEventListener("connected", () => {
|
|
1797
|
+
if (!device.hasMicrophone) {
|
|
1798
|
+
return;
|
|
1799
|
+
}
|
|
1800
|
+
updateSelect();
|
|
1801
|
+
});
|
|
1802
|
+
|
|
1803
|
+
device.addEventListener("getMicrophoneConfiguration", () => {
|
|
1804
|
+
updateSelect();
|
|
1805
|
+
});
|
|
1806
|
+
|
|
1807
|
+
select.addEventListener("input", () => {
|
|
1808
|
+
const value = select.value;
|
|
1809
|
+
// console.log(`updating ${microphoneConfigurationType} to ${value}`);
|
|
1810
|
+
device.setMicrophoneConfiguration({
|
|
1811
|
+
[microphoneConfigurationType]: value,
|
|
1812
|
+
});
|
|
1813
|
+
});
|
|
1814
|
+
});
|
|
1815
|
+
|
|
1816
|
+
/** @type {HTMLButtonElement} */
|
|
1817
|
+
const toggleMicrophoneButton = document.getElementById("toggleMicrophone");
|
|
1818
|
+
toggleMicrophoneButton.addEventListener("click", () => {
|
|
1819
|
+
device.toggleMicrophone();
|
|
1820
|
+
});
|
|
1821
|
+
device.addEventListener("connected", () => {
|
|
1822
|
+
updateToggleMicrophoneButton();
|
|
1823
|
+
});
|
|
1824
|
+
device.addEventListener("getSensorConfiguration", () => {
|
|
1825
|
+
updateToggleMicrophoneButton();
|
|
1826
|
+
});
|
|
1827
|
+
const updateToggleMicrophoneButton = () => {
|
|
1828
|
+
let disabled =
|
|
1829
|
+
!device.isConnected ||
|
|
1830
|
+
device.sensorConfiguration.microphone == 0 ||
|
|
1831
|
+
!device.hasMicrophone;
|
|
1832
|
+
|
|
1833
|
+
switch (device.microphoneStatus) {
|
|
1834
|
+
case "streaming":
|
|
1835
|
+
toggleMicrophoneButton.innerText = "stop microphone";
|
|
1836
|
+
break;
|
|
1837
|
+
case "idle":
|
|
1838
|
+
toggleMicrophoneButton.innerText = "start microphone";
|
|
1839
|
+
break;
|
|
1840
|
+
}
|
|
1841
|
+
toggleMicrophoneButton.disabled = disabled;
|
|
1842
|
+
};
|
|
1843
|
+
device.addEventListener("microphoneStatus", () => {
|
|
1844
|
+
updateToggleMicrophoneButton();
|
|
1845
|
+
});
|
|
1846
|
+
|
|
1847
|
+
/** @type {HTMLButtonElement} */
|
|
1848
|
+
const startMicrophoneButton = document.getElementById("startMicrophone");
|
|
1849
|
+
startMicrophoneButton.addEventListener("click", () => {
|
|
1850
|
+
device.startMicrophone();
|
|
1851
|
+
});
|
|
1852
|
+
/** @type {HTMLButtonElement} */
|
|
1853
|
+
const stopMicrophoneButton = document.getElementById("stopMicrophone");
|
|
1854
|
+
stopMicrophoneButton.addEventListener("click", () => {
|
|
1855
|
+
device.stopMicrophone();
|
|
1856
|
+
});
|
|
1857
|
+
/** @type {HTMLButtonElement} */
|
|
1858
|
+
const enableMicrophoneVadButton = document.getElementById("enableMicrphoneVad");
|
|
1859
|
+
enableMicrophoneVadButton.addEventListener("click", () => {
|
|
1860
|
+
device.enableMicrophoneVad();
|
|
1861
|
+
});
|
|
1862
|
+
|
|
1863
|
+
const updateMicrophoneButtons = () => {
|
|
1864
|
+
let disabled =
|
|
1865
|
+
!device.isConnected ||
|
|
1866
|
+
device.sensorConfiguration.microphone == 0 ||
|
|
1867
|
+
!device.hasMicrophone;
|
|
1868
|
+
|
|
1869
|
+
startMicrophoneButton.disabled =
|
|
1870
|
+
disabled || device.microphoneStatus == "streaming";
|
|
1871
|
+
stopMicrophoneButton.disabled = disabled || device.microphoneStatus == "idle";
|
|
1872
|
+
enableMicrophoneVadButton.disabled =
|
|
1873
|
+
disabled || device.microphoneStatus == "vad";
|
|
1874
|
+
};
|
|
1875
|
+
device.addEventListener("microphoneStatus", () => {
|
|
1876
|
+
updateMicrophoneButtons();
|
|
1877
|
+
});
|
|
1878
|
+
device.addEventListener("connected", () => {
|
|
1879
|
+
updateMicrophoneButtons();
|
|
1880
|
+
});
|
|
1881
|
+
device.addEventListener("getSensorConfiguration", () => {
|
|
1882
|
+
updateMicrophoneButtons();
|
|
1883
|
+
});
|
|
1884
|
+
|
|
1885
|
+
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
|
|
1886
|
+
const checkAudioContextState = () => {
|
|
1887
|
+
const { state } = audioContext;
|
|
1888
|
+
console.log({ audioContextState: state });
|
|
1889
|
+
if (state != "running") {
|
|
1890
|
+
document.addEventListener("click", () => audioContext.resume(), {
|
|
1891
|
+
once: true,
|
|
1892
|
+
});
|
|
1893
|
+
}
|
|
1894
|
+
};
|
|
1895
|
+
audioContext.addEventListener("statechange", () => {
|
|
1896
|
+
checkAudioContextState();
|
|
1897
|
+
});
|
|
1898
|
+
checkAudioContextState();
|
|
1899
|
+
|
|
1900
|
+
device.audioContext = audioContext;
|
|
1901
|
+
|
|
1902
|
+
/** @type {HTMLAudioElement} */
|
|
1903
|
+
const microphoneStreamAudioElement =
|
|
1904
|
+
document.getElementById("microphoneStream");
|
|
1905
|
+
microphoneStreamAudioElement.srcObject =
|
|
1906
|
+
device.microphoneMediaStreamDestination.stream;
|
|
1907
|
+
|
|
1908
|
+
/** @type {HTMLAudioElement} */
|
|
1909
|
+
const microphoneRecordingAudioElement = document.getElementById(
|
|
1910
|
+
"microphoneRecording"
|
|
1911
|
+
);
|
|
1912
|
+
/** @type {HTMLInputElement} */
|
|
1913
|
+
const autoPlayMicrphoneRecordingCheckbox = document.getElementById(
|
|
1914
|
+
"autoPlayMicrphoneRecording"
|
|
1915
|
+
);
|
|
1916
|
+
let autoPlayMicrphoneRecording = autoPlayMicrphoneRecordingCheckbox.checked;
|
|
1917
|
+
console.log("autoPlayMicrphoneRecording", autoPlayMicrphoneRecording);
|
|
1918
|
+
autoPlayMicrphoneRecordingCheckbox.addEventListener("input", () => {
|
|
1919
|
+
autoPlayMicrphoneRecording = autoPlayMicrphoneRecordingCheckbox.checked;
|
|
1920
|
+
console.log({ autoPlayMicrphoneRecording });
|
|
1921
|
+
});
|
|
1922
|
+
device.addEventListener("microphoneRecording", (event) => {
|
|
1923
|
+
microphoneRecordingAudioElement.src = event.message.url;
|
|
1924
|
+
if (autoPlayMicrphoneRecording) {
|
|
1925
|
+
microphoneRecordingAudioElement.play();
|
|
1926
|
+
}
|
|
1927
|
+
});
|
|
1928
|
+
|
|
1929
|
+
/** @type {HTMLButtonElement} */
|
|
1930
|
+
const toggleMicrophoneRecordingButton = document.getElementById(
|
|
1931
|
+
"toggleMicrophoneRecording"
|
|
1932
|
+
);
|
|
1933
|
+
toggleMicrophoneRecordingButton.addEventListener("click", () => {
|
|
1934
|
+
device.toggleMicrophoneRecording();
|
|
1935
|
+
});
|
|
1936
|
+
device.addEventListener("connected", () => {
|
|
1937
|
+
updateToggleMicrophoneRecordingButton();
|
|
1938
|
+
});
|
|
1939
|
+
device.addEventListener("getSensorConfiguration", () => {
|
|
1940
|
+
updateToggleMicrophoneRecordingButton();
|
|
1941
|
+
});
|
|
1942
|
+
const updateToggleMicrophoneRecordingButton = () => {
|
|
1943
|
+
let disabled =
|
|
1944
|
+
!device.isConnected ||
|
|
1945
|
+
device.sensorConfiguration.microphone == 0 ||
|
|
1946
|
+
!device.hasMicrophone ||
|
|
1947
|
+
device.microphoneStatus != "streaming";
|
|
1948
|
+
|
|
1949
|
+
toggleMicrophoneRecordingButton.innerText = device.isRecordingMicrophone
|
|
1950
|
+
? "stop recording"
|
|
1951
|
+
: "start recording";
|
|
1952
|
+
|
|
1953
|
+
toggleMicrophoneRecordingButton.disabled = disabled;
|
|
1954
|
+
};
|
|
1955
|
+
device.addEventListener("isRecordingMicrophone", () => {
|
|
1956
|
+
updateToggleMicrophoneRecordingButton();
|
|
1957
|
+
});
|
|
1958
|
+
device.addEventListener("microphoneStatus", () => {
|
|
1959
|
+
updateToggleMicrophoneRecordingButton();
|
|
1960
|
+
});
|