diff --git a/static/js/BLE.js b/static/js/BLE.js
new file mode 100644
index 0000000..dda6be5
--- /dev/null
+++ b/static/js/BLE.js
@@ -0,0 +1,68 @@
+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();
+ const service = await server.getPrimaryService("cycling_speed_and_cadence");
+ const char = await service.getCharacteristic("csc_measurement");
+ char.oncharacteristicvaluechanged = props.onChange;
+ char.startNotifications();
+ return char;
+}
+
+function parseCSC({ 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);
+ const pre = document.createElement("pre");
+ pre.style.border = "1px solid red";
+ pre.textContent = JSON.stringify(res, null, 2);
+ document.body.appendChild(pre);
+ return res;
+}
+
+function revsToRPM(t1, t2) {
+ const deltaRevs = t2.revs - t1.revs;
+ if (deltaRevs === 0) {
+ // no rotation
+ return 0;
+ }
+
+ let deltaTime = (t2.time - t1.time) / 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)
+);
diff --git a/templates/base.html b/templates/base.html
index 5c21cf9..4f7b76b 100644
--- a/templates/base.html
+++ b/templates/base.html
@@ -51,8 +51,18 @@
+
+