Bluetooth Secure Characteristic Read w/Notifications
+
This is a simple test to subscribe to secure characteristic value change notifications.
+
+
+
Step 1
+
+
+
+ Press the button to load the code to the Espruino IDE.
+ From there flash any Bluetooth capable Espruino device.
+
+
+ View source.
+
+
+
+
+
+
+
+
Step 2
+
+
+
+ Once running, start the test. When prompted for the passcode enter
+ "141414".
+
+
+
+
+
+
+
NOTE:
+
+ When re-running this test, this device will likely
+ not prompt for the passcode a second time, as the device is
+ now paired with this host. To force re-prompting for the passcode,
+ access the Bluetooth preferences on this host and forget/unpair
+ the test device.
+
+
+
+
+
Status:
+
+
+
+
+ Web Bluetooth is not supported by this browser.
+
+
+ Bluetooth requires a secure context (HTTPS). For development purposes it
+ does support HTTP, but only the on the loopback adapter (i.e. "localhost").
+
+
+ Web Bluetooth is supported by this browser but this device does not have
+ Bluetooth capabilities.
+
+
+
+
diff --git a/characteristic_secure_notify/web_app.js b/characteristic_secure_notify/web_app.js
new file mode 100644
index 0000000..7c71700
--- /dev/null
+++ b/characteristic_secure_notify/web_app.js
@@ -0,0 +1,153 @@
+/**
+ * Copyright 2021 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// The test service defined in device_code.js
+const testService = '02fc549a-244c-11eb-adc1-0242ac120002';
+// The test characteristic defined in device_code.js
+const testCharacteristic = '02fc549a-244c-11eb-adc1-0242ac120002';
+const requiredNumUpdates = 100;
+
+let gattServer = undefined;
+
+/**
+ * Load the device code to the Espruino IDE.
+ */
+function loadEspruinoDeviceCode() {
+ fetch('device_code.js').then(response => response.text()).then(data => {
+ let url = 'http://www.espruino.com/webide?code=' + encodeURIComponent(data);
+ window.open(url, '_window');
+ });
+}
+
+function onGattDisconnected(evt) {
+ const device = evt.target;
+ logInfo(`Disconnected from GATT on device ${device.name}.`);
+ assertFalse(gattServer.connected, 'Server connected');
+}
+
+async function startTest() {
+ clearStatus();
+ logInfo('Starting test');
+
+ $('btn_start_test').disabled = true;
+ $('btn_load_code').disabled = true;
+ let notifyCharacteristic = undefined;
+ let updateNum = 0;
+ let lastValue = null;
+
+ const resetTest = async () => {
+ if (notifyCharacteristic) {
+ await notifyCharacteristic.stopNotifications();
+ }
+ if (gattServer && gattServer.connected) {
+ logInfo('Disconnecting from GATT.');
+ gattServer.disconnect();
+ }
+ $('btn_start_test').disabled = false;
+ $('btn_load_code').disabled = false;
+ }
+
+ const checkCharacteristicValue = (value) => {
+ if (value > 9999) {
+ throw `Invalid characteristic value ${value}. Should be val <= 9999.`;
+ }
+ if (!lastValue) {
+ return;
+ }
+ if (lastValue === 9999) {
+ assertEquals(0, value);
+ }
+ assertEquals(lastValue + 1, value, 'Skipped value');
+ }
+
+ const onCharacteristicChanged = (evt) => {
+ updateNum += 1;
+ try {
+ const characteristic = evt.target;
+ const dataView = characteristic.value;
+ const val = dataView.getUint32(0, /*littleEndian=*/true);
+ checkCharacteristicValue(val);
+ lastValue = val;
+ if (updateNum == requiredNumUpdates) {
+ logInfo('Test success.');
+ }
+ } catch (error) {
+ logError(`Unexpected failure: ${error}`);
+ updateNum = requiredNumUpdates; // Force test to stop.
+ }
+ if (updateNum >= requiredNumUpdates) {
+ resetTest();
+ testDone();
+ }
+ }
+
+ try {
+ const options = {
+ filters: [{ services: [getEspruinoPrimaryService()] }],
+ optionalServices: [testService]
+ };
+ logInfo(`Requesting Bluetooth device with service ${testService}`);
+ const device = await navigator.bluetooth.requestDevice(options);
+
+ device.addEventListener('gattserverdisconnected', onGattDisconnected);
+ logInfo(`Connecting to GATT server for device \"${device.name}\"...`);
+ gattServer = await device.gatt.connect();
+ assertEquals(gattServer.device, device, 'Server device mismatch');
+ assertTrue(gattServer.connected, 'server.connected should be true');
+
+ logInfo(`Connected to GATT, requesting service: ${testService}...`);
+ const service = await gattServer.getPrimaryService(testService);
+ assertEquals(service.device, device, 'service device mismatch');
+
+ logInfo(`Connected to service uuid:${service.uuid}, primary:${service.isPrimary}`);
+ logInfo(`Requesting characteristic ${testCharacteristic}...`);
+ const characteristic = await service.getCharacteristic(testCharacteristic);
+ assertEquals(characteristic.service, service,
+ 'characteristic service mismatch');
+
+ logInfo(`Got characteristic, reading value...`);
+ let dataView = await characteristic.readValue();
+ let val = dataView.getUint32(0, /*littleEndian=*/true);
+ checkCharacteristicValue(val);
+
+ notifyCharacteristic = await characteristic.startNotifications();
+ notifyCharacteristic.addEventListener(
+ 'characteristicvaluechanged', onCharacteristicChanged);
+ } catch (error) {
+ logError(`Unexpected failure: ${error}`);
+ resetTest();
+ testDone();
+ }
+}
+
+async function init() {
+ if (!isBluetoothSupported()) {
+ console.log('Bluetooth not supported.');
+ $('bluetooth_available').style.display = 'none';
+ if (window.isSecureContext == 'https') {
+ $('bluetooth_none').style.visibility = 'visible';
+ } else {
+ $('bluetooth_insecure').style.visibility = 'visible';
+ }
+ return;
+ }
+
+ const available = await navigator.bluetooth.getAvailability();
+ if (!available) {
+ $('bluetooth_available').style.display = 'none';
+ $('bluetooth_unavailable').style.visibility = 'visible';
+ }
+}
diff --git a/index.html b/index.html
index 050f9fd..14f1504 100644
--- a/index.html
+++ b/index.html
@@ -38,6 +38,7 @@