From 5881d32886e34e2d821dd7fd950257bc73a06e77 Mon Sep 17 00:00:00 2001 From: Lambda Date: Sun, 14 Sep 2025 22:54:14 +0300 Subject: [PATCH] add examples --- js/main.js | 64 +++++++++++++++++++++++++++++++++++++++- js/tmp.js | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 js/tmp.js diff --git a/js/main.js b/js/main.js index f965458..7ac5a42 100644 --- a/js/main.js +++ b/js/main.js @@ -1,12 +1,74 @@ const startButton = document.getElementById("start"); +console.log(navigator.bluetooth); + +const devices = await navigator.bluetooth.getDevices(); + +devices.forEach(async (device) => { + const gattServer = await device.gatt.connect(); + const primaryService = await gattServer.getPrimaryService(0x1800); + const MANUFACTURER_UUID = 0x2a29; + const MODEL_UUID = 0x2a0a; + const char = await primaryService.getCharacteristic(MODEL_UUID); + const val = await char.readValue(); + //const char2 = await primaryService.getCharacteristic(MODEL_UUID); + //const val2 = await char2.readValue(); + const decoder = new TextDecoder("utf-8"); + const manufacturer = decoder.decode(val); + //const model = decoder.decode(val2); + console.log("Manufacturer:", manufacturer); +}); + startButton.addEventListener("click", async () => { try { + const devices = await navigator.bluetooth.getDevices(); + console.log(2, devices); const device = await navigator.bluetooth.requestDevice({ + filters: [{ services: [0x180d] }], + optionalServices: [ + 0x1818, // Cycling Power – watts, torque, crank torque, etc. + 0x1816, // Cycling Speed & Cadence – speed, cadence, distance + 0x180d, // Heart Rate – optional, if the trainer includes an HR sensor + 0x180f, // Battery Service – trainer battery level (if battery‑powered) + 0x180a, // Device Information – manufacturer, model, firmware version + 0x1800, + // add any custom 128‑bit UUIDs as strings, e.g. + // '0000abcd-0000-1000-8000-00805f9b34fb' + ], acceptAllDevices: true, }); - console.log(device); + + const server = await device.gatt.connect(); + + console.log(await server.getPrimaryServices()); } catch (error) { console.log(error); } }); + +// startButton.addEventListener("click", async () => { +// try { +// const devices = await navigator.bluetooth.getDevices(); +// console.log(2, devices); +// const device = await navigator.bluetooth.requestDevice({ +// //filters: [{ services: ["heart_rate"] }], +// optionalServices: [ +// 0x1818, // Cycling Power – watts, torque, crank torque, etc. +// 0x1816, // Cycling Speed & Cadence – speed, cadence, distance +// 0x180d, // Heart Rate – optional, if the trainer includes an HR sensor +// 0x180f, // Battery Service – trainer battery level (if battery‑powered) +// 0x180a, // Device Information – manufacturer, model, firmware version +// 0x1800, +// // add any custom 128‑bit UUIDs as strings, e.g. +// // '0000abcd-0000-1000-8000-00805f9b34fb' +// ], +// acceptAllDevices: true, +// }); + +// const server = await device.gatt.connect(); + +// console.log(await server.getPrimaryServices()); +// } catch (error) { +// console.log(error); +// } +// }); diff --git a/js/tmp.js b/js/tmp.js new file mode 100644 index 0000000..547d904 --- /dev/null +++ b/js/tmp.js @@ -0,0 +1,86 @@ +// 1️⃣ Request a HR‑monitor device +const hrOptions = { + // Show only devices that advertise the Heart Rate service (0x180D) + filters: [{ services: [0x180d] }], + + // After the user picks a device we also want to read the Device + // Information service (optional, no extra prompt) + optionalServices: [0x180a], // Device Information +}; + +navigator.bluetooth + .requestDevice(hrOptions) + .then((device) => { + console.log("✅ Selected:", device.name); + // 2️⃣ Connect to the GATT server + return device.gatt.connect(); + }) + .then((server) => { + // 3️⃣ Get the Heart Rate service + return server.getPrimaryService(0x180d); + }) + .then((hrService) => { + // 4️⃣ Get the Heart Rate Measurement characteristic (0x2A37) + return hrService.getCharacteristic(0x2a37); + }) + .then((hrChar) => { + // 5️⃣ Enable notifications – the monitor will push new readings + return hrChar.startNotifications().then(() => hrChar); + }) + .then((hrChar) => { + console.log("🔔 Listening for heart‑rate measurements..."); + hrChar.addEventListener("characteristicvaluechanged", (ev) => { + const value = ev.target.value; // DataView + const heartRate = parseHeartRate(value); + console.log("❤️ Heart Rate:", heartRate, "bpm"); + }); + }) + .catch((err) => console.error("❌ Bluetooth error:", err)); + +/** + * Parse the Heart Rate Measurement characteristic (Bluetooth SIG spec). + * Returns the BPM as a Number. + */ +function parseHeartRate(dataView) { + // Flags are in the first byte + const flags = dataView.getUint8(0); + const hrFormatUint16 = flags & 0x01; // 0 = 8‑bit, 1 = 16‑bit + + if (hrFormatUint16) { + return dataView.getUint16(1, /*littleEndian=*/ true); + } + return dataView.getUint8(1); +} + +// After the HR connection succeeds, you can also fetch the Device Info service: +navigator.bluetooth + .requestDevice(hrOptions) // reuse the same options + .then((d) => d.gatt.connect()) + .then((server) => + Promise.all([ + server.getPrimaryService(0x180a), // Device Information + server.getPrimaryService(0x180d), // Heart Rate + ]), + ) + .then(([infoService, hrService]) => + Promise.all([ + // Manufacturer Name (0x2A29) + infoService.getCharacteristic(0x2a29).then((c) => c.readValue()), + // Model Number (0x2A24) + infoService.getCharacteristic(0x2a24).then((c) => c.readValue()), + // Heart Rate Measurement (as before) + hrService + .getCharacteristic(0x2a37) + .then((c) => c.startNotifications().then(() => c)), + ]), + ) + .then(([manufVal, modelVal, hrChar]) => { + const dec = new TextDecoder("utf-8"); + console.log("🏭 Manufacturer:", dec.decode(manufVal)); + console.log("📦 Model:", dec.decode(modelVal)); + + hrChar.addEventListener("characteristicvaluechanged", (ev) => + console.log("❤️", parseHeartRate(ev.target.value), "bpm"), + ); + }) + .catch(console.error);