Skip to content

Instantly share code, notes, and snippets.

@jacobrosenthal
Last active July 15, 2016 04:48
Show Gist options
  • Save jacobrosenthal/f630398b46c76cad86cb7756e5f2c86d to your computer and use it in GitHub Desktop.
Save jacobrosenthal/f630398b46c76cad86cb7756e5f2c86d to your computer and use it in GitHub Desktop.
Ring Zero Webbluetooth
var canvas = document.querySelector('canvas');
var statusText = document.querySelector('#scanBtn');
statusText.addEventListener('click', function() {
statusText.textContent = 'scanning...';
ring.connect()
.then(() => ring.startNotificationsEvents().then(handleEvent))
.then(() => {
statusText.textContent = 'got one...';
ring.readConfig().then(function (points) {
console.log(points);
});
// ring.readMode().then(function (points) {
// console.log(points);
// });
})
.catch(error => {
console.log(error);
statusText.textContent = error;
});
});
window.addEventListener("unhandledrejection", function(err, promise) {
console.log(err, promise)
});
function handlePoints(points){
console.log("points promise", points.byteLength);
return 6; //return an error code to send as feedback
}
function feedback(response){
return ring.sendFeedback(response);
}
function handleEvent(motion) {
motion.addEventListener('characteristicvaluechanged', event => {
let something = event.target.value.getUint8(0);
console.log(something);
switch (something) {
case 0x01: break;
case 0x02: break;
case 0x03:
ring.readPoints()
.then(handlePoints)
.then(feedback);
break;
case 0x05: console.log('heartbeat'); break;
case 0x0d:
ring.sendFeedback(5);
break;
default: break;
}
});
}
<!doctype html>
<!--
Material Design Lite
Copyright 2015 Google Inc. All rights reserved.
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
-->
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="description" content="A front-end template that helps you build fast, modern mobile web apps.">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>BLE</title>
<!-- Load c3.css -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.11/c3.min.css" rel="stylesheet" type="text/css">
<!-- Load d3.js and c3.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.1.1/d3.min.js" charset="utf-8"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.11/c3.min.js"></script>
<!-- Add to homescreen for Chrome on Android -->
<meta name="mobile-web-app-capable" content="yes">
<link rel="stylesheet" href="https://code.getmdl.io/1.1.3/material.indigo-light_blue.min.css" />
</head>
<body class="mdl-demo mdl-color--grey-100 mdl-color-text--grey-700 mdl-base">
<button class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored" id="scanBtn" style="margin: 10px;">
Start Scanning
</button>
<div id="output"></div>
<div id="errorOutput" style="color: red;"></div>
<div id="chart"></div>
<script src="ring.js"></script>
<script src="app.js"></script>
</body>
</html>
(function() {
'use strict';
var CONFIG_SERVICE_UUID = '1e374a10-851e-11e3-b9e7-0002a5d5c51b';
var CONFIG_CHARACTERISTIC_UUID = '1e374a11-851e-11e3-b9e7-0002a5d5c51b';
var MOTION_SERVICE_UUID = '1e374a20-851e-11e3-b9e7-0002a5d5c51b';
var MOTION_RAW_CHARACTERISTIC_UUID = '1e374a21-851e-11e3-b9e7-0002a5d5c51b';
var MOTION_POINTS_CHARACTERISTIC_UUID = '1e374a22-851e-11e3-b9e7-0002a5d5c51b';
var RING_SERVICE_UUID = '1e374a30-851e-11e3-b9e7-0002a5d5c51b';
var RING_EVENT_CHARACTERISTIC_UUID = '1e374a31-851e-11e3-b9e7-0002a5d5c51b';
var RING_MODE_CHARACTERISTIC_UUID = '1e374a32-851e-11e3-b9e7-0002a5d5c51b';
var RING_FEEDBACK_CHARACTERISTIC_UUID = '1e374a33-851e-11e3-b9e7-0002a5d5c51b';
class Ring {
constructor() {
this.device = null;
this.server = null;
this._characteristics = new Map();
}
connect() {
return navigator.bluetooth.requestDevice(
{
filters:[
{services:[ RING_SERVICE_UUID ]},
{services:[ MOTION_SERVICE_UUID ]},
{services:[ CONFIG_SERVICE_UUID ]}
],
// optionalServices: [MOTION_SERVICE_UUID, CONFIG_SERVICE_UUID]
})
.then(device => {
console.log('device', device);
this.device = device;
return device.gatt.connect();
})
.then(server => {
this.server = server;
return Promise.all([
server.getPrimaryService(MOTION_SERVICE_UUID).then(service => {
return Promise.all([
this._cacheCharacteristic(service, MOTION_RAW_CHARACTERISTIC_UUID),
this._cacheCharacteristic(service, MOTION_POINTS_CHARACTERISTIC_UUID)
])
}),
server.getPrimaryService(RING_SERVICE_UUID).then(service => {
return Promise.all([
this._cacheCharacteristic(service, RING_EVENT_CHARACTERISTIC_UUID),
this._cacheCharacteristic(service, RING_MODE_CHARACTERISTIC_UUID),
this._cacheCharacteristic(service, RING_FEEDBACK_CHARACTERISTIC_UUID)
])
}),
server.getPrimaryService(CONFIG_SERVICE_UUID).then(service => {
return Promise.all([
this._cacheCharacteristic(service, CONFIG_CHARACTERISTIC_UUID)
])
})
]);
})
}
startNotificationsEvents() {
return this._startNotifications(RING_EVENT_CHARACTERISTIC_UUID);
}
stopNotificationsEvents() {
return this._stopNotifications(RING_EVENT_CHARACTERISTIC_UUID);
}
readPoints() {
return this._readCharacteristicValue(MOTION_POINTS_CHARACTERISTIC_UUID)
.then(data => {
return data;
});
}
readRaw() {
return this._readCharacteristicValue(MOTION_RAW_CHARACTERISTIC_UUID)
.then(data => {
return data;
});
}
readMode() {
return this._readCharacteristicValue(RING_MODE_CHARACTERISTIC_UUID)
.then(data => {
console.log(data);
return 0;
});
}
readConfig() {
return this._readCharacteristicValue(CONFIG_CHARACTERISTIC_UUID)
.then(data => {
console.log(data);
return 0;
});
}
sendFeedback(feedback) {
return this._writeCharacteristicValue(RING_FEEDBACK_CHARACTERISTIC_UUID, new Uint8Array([feedback]));
}
/* Utils */
_cacheCharacteristic(service, characteristicUuid) {
return service.getCharacteristic(characteristicUuid)
.then(characteristic => {
this._characteristics.set(characteristicUuid, characteristic);
});
}
_readCharacteristicValue(characteristicUuid) {
let characteristic = this._characteristics.get(characteristicUuid);
return characteristic.readValue();
}
_writeCharacteristicValue(characteristicUuid, value) {
let characteristic = this._characteristics.get(characteristicUuid);
return characteristic.writeValue(value);
}
_startNotifications(characteristicUuid) {
let characteristic = this._characteristics.get(characteristicUuid);
// Returns characteristic to set up characteristicvaluechanged event
// handlers in the resolved promise.
return characteristic.startNotifications()
.then(() => characteristic);
}
_stopNotifications(characteristicUuid) {
let characteristic = this._characteristics.get(characteristicUuid);
// Returns characteristic to remove characteristicvaluechanged event
// handlers in the resolved promise.
return characteristic.stopNotifications()
.then(() => characteristic);
}
}
window.ring = new Ring();
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment