Files
cardio/static/js/BLE.js
2023-01-26 15:36:36 +11:00

108 lines
3.0 KiB
JavaScript

let socket = null;
let characteristic = null;
let prevRes = null;
function delay(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
async function connect(props) {
const device = await navigator.bluetooth.requestDevice({
filters: [{ services: ["cycling_speed_and_cadence"] }],
acceptAllDevices: false,
});
console.log(`%c\n👩🏼‍⚕️`, "font-size: 82px;", "Starting CSC...\n\n");
const server = await device.gatt.connect();
await delay(500);
console.log("Getting Service...");
const service = await server.getPrimaryService("cycling_speed_and_cadence");
console.log("Getting Characteristic...");
characteristic = await service.getCharacteristic("csc_measurement");
await characteristic.startNotifications();
console.log("> Notifications started");
characteristic.addEventListener("characteristicvaluechanged", props.onChange);
console.log("> Characteristic value changed event listener added");
socket = io();
socket.on("disconnect", (reason) => {
if (reason === "io server disconnect") {
// the disconnection was initiated by the server, you need to reconnect manually
socket.connect();
}
// else the socket will automatically try to reconnect
});
}
async function disconnect() {
if (characteristic) {
try {
await characteristic.stopNotifications();
log("> Notifications stopped");
characteristic.removeEventListener(
"characteristicvaluechanged",
handleNotifications
);
} catch (error) {
log("Argh! " + error);
}
}
}
function parseCSC(e) {
const value = e.target.value;
const flags = value.getUint8(0, true);
const hasWheel = !!(flags & 0x01);
const hasCrank = !!(flags & 0x02);
let index = 1;
const res = {
wheelRevs: null,
wheelTime: null,
crankRevs: null,
crankTime: null,
};
if (hasWheel) {
res.wheelRevs = value.getUint32(index, true);
index += 4;
res.wheelTime = value.getUint16(index, true);
index += 2;
}
if (hasCrank) {
res.crankRevs = value.getUint16(index, true);
index += 2;
res.crankTime = value.getUint16(index, true);
index += 2;
}
console.log("CSC", res);
if (prevRes) {
let rpm = revsToRPM(prevRes, res);
if (rpm > 0)
socket.emit("message", { rpm: parseFloat(rpm.toFixed(2)), id: 1 });
}
prevRes = res;
return res;
}
function revsToRPM(prevRes, res) {
const deltaRevs = res.crankRevs - prevRes.crankRevs;
if (deltaRevs === 0) {
// no rotation
return 0;
}
let deltaTime = (res.crankTime - prevRes.crankTime) / 1024;
if (deltaTime < 0) {
// time counter wraparound
deltaTime += Math.pow(2, 16) / 1024;
}
deltaTime /= 60; // seconds to minutes
const rpm = deltaRevs / deltaTime;
return rpm;
}
document.querySelector("#ble-connect").addEventListener("click", () =>
connect({
onChange: parseCSC,
}).catch(console.error)
);