diff --git a/js/ble/gatt.js b/js/ble/gatt.js new file mode 100644 index 0000000..b180c67 --- /dev/null +++ b/js/ble/gatt.js @@ -0,0 +1,48 @@ +const GATT = Object.freeze({ + Battery: Object.freeze({ + service: 0x180f, + level: "0x2A19", // Battery Level (Read / Notify) + }), + + HeartRate: Object.freeze({ + service: 0x180d, + measurement: "0x2A37", // Heart Rate Measurement (Notify) + bodySensorLocation: "0x2A38", // Body Sensor Location (Read) + controlPoint: "0x2A39", // Heart Rate Control Point (Write) + }), + + Cadence: Object.freeze({ + service: "0x1816", + measurement: "0x2A5B", // CSC Measurement (Notify) + feature: "0x2A5C", // CSC Feature (Read) + location: "0x2A5D", // Sensor Location (Read) + }), + + PowerMeter: Object.freeze({ + service: "0x1818", + measurement: "0x2A63", // Cycling Power Measurement (Notify) + feature: "0x2A64", // Cycling Power Feature (Read) + controlPoint: "0x2A65", // Cycling Power Control Point (Write) + location: "0x2A66", // Sensor Location (Read) + }), + + SmartTrainer: Object.freeze({ + service: "0x1826", // Fitness Machine Service + status: "0x2AD9", // Fitness Machine Status (Notify) + controlPoint: "0x2ACC", // Fitness Machine Control Point (Write/Indicate) + feature: "0x2ADA", // Fitness Machine Feature (Read) + indoorBikeData: "0x2ADB", // Indoor Bike Data (Notify) + trainingStatus: "0x2ADC", // Training Status (Notify) + supportedResistance: "0x2ADD", // Supported Resistance Level (Read) + }), + + DeviceInfo: Object.freeze({ + service: 0x180a, // Device Information Service + manufacturerName: "0x2A29", // Manufacturer Name String (Read) + modelNumber: "0x2A24", // Model Number String (Read) + serialNumber: "0x2A25", // Serial Number String (Read) + firmwareRevision: "0x2A26", // Firmware Revision String (Read) + }), +}); + +export { GATT }; diff --git a/js/ble/index.js b/js/ble/index.js new file mode 100644 index 0000000..e1cd735 --- /dev/null +++ b/js/ble/index.js @@ -0,0 +1,17 @@ +import { GATT } from "./gatt.js"; + +const hrSensorOptions = { + filters: [{ services: [GATT.HeartRate.service] }], + optionalServices: [GATT.DeviceInfo.service, GATT.Battery.service], +}; + +const requestHRSensor = async () => { + try { + return await navigator.bluetooth.requestDevice(hrSensorOptions); + } catch (err) { + console.log(err); + return null; + } +}; + +export { requestHRSensor }; diff --git a/js/main.js b/js/main.js index 33d4839..e1271e2 100644 --- a/js/main.js +++ b/js/main.js @@ -1,18 +1,10 @@ import { Core } from "./device/index.js"; +import { requestHRSensor } from "./ble/index.js"; const startButton = document.getElementById("start"); const hrButton = document.getElementById("hr"); hrButton.addEventListener("click", async () => { - 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 - }; - function parseHeartRate(dataView) { // Flags are in the first byte const flags = dataView.getUint8(0); @@ -25,7 +17,9 @@ hrButton.addEventListener("click", async () => { } try { - const device = await navigator.bluetooth.requestDevice(hrOptions); + const device = await requestHRSensor(); + console.log("D", device); + if (!device) return; const server = await device.gatt.connect(); const partialCore = new Core({ diff --git a/js/ui/index.js b/js/ui/index.js new file mode 100644 index 0000000..fbe6989 --- /dev/null +++ b/js/ui/index.js @@ -0,0 +1,5 @@ +const connectHRSensor = () => {}; +const connectCadenceSensor = () => {}; +const connectTrainer = () => {}; + +export { connectHRSensor, connectCadenceSensor, connectTrainer };