1

I'm trying to connect the Muse headband in chrome so i can stream live brainwave data.

I can connect and stream data fine in python using ports, but am having trouble streaming the data via web BLE.

With the code bellow, I can connect to the device and startNotifications(), but the event listener for "characteristicvaluechanged" is not being triggered. I've also tried connecting with other bluetooth devices, and no values are read so I don't think this is a Muse problem.

<h1>Test HTML</h1>
<button id="read" onclick="onButtonClick(event)">Connect with the BLE device</button>

<script>
function onButtonClick(event){
    connectBLE()
}

async function connectBLE() {
  let serviceUuid = '5052494d-2dab-0341-6972-6f6861424c45'
  let characteristicUuid = '43484152-2dab-3141-6972-6f6861424c45' 

  try {
    console.log('Requesting Bluetooth Device...');
    const device = await navigator.bluetooth.requestDevice({
        filters: [{services: [serviceUuid]}]});

    console.log('Connecting to GATT Server...');
    const server = await device.gatt.connect();

    console.log('Getting Service...');
    const service = await server.getPrimaryService(serviceUuid);

    console.log('Getting Characteristic...');
    myCharacteristic = await service.getCharacteristic(characteristicUuid);

    await myCharacteristic.startNotifications();

    console.log(myCharacteristic)

    console.log('> Notifications started');
    myCharacteristic.addEventListener('characteristicvaluechanged',
        handleNotifications);
  } catch(error) {
    console.log('Argh! ' + error);
  }
}


function handleNotifications(event) {
  console.log('YEAH!')
  let value = event.target.value;
  let a = [];
  // Convert raw data bytes to hex values just for the sake of showing something.
  // In the "real" world, you'd use data.getUint8, data.getUint16 or even
  // TextDecoder to process raw data bytes.
  for (let i = 0; i < value.byteLength; i++) {
    a.push('0x' + ('00' + value.getUint8(i).toString(16)).slice(-2));
  }
  console.log('> ' + a.join(' '));
}

</script>

Anyone ever had a similar issue? I can't find any solutions online so this is kinda my last resort.

PS: I'm running Ubuntu 18.04 and Chromium 83.0.4103.61

  • 1
    Are you sure that the service UUID / characteristic UUID are the right ones for your Muse device? They are different from the ones in the [muse-js library](https://github.com/urish/muse-js/blob/06e83670a0558297feebe4540f6b11d203003aed/src/muse.ts#L21), and googling them doesn't yield any results (other than this question) – urish Jul 25 '20 at 05:28
  • 1
    Sorry for the confusion those were the UUID ad characteristic ID of my AirPods that I tried right afterwards. Yes I'm 100% the UUID is the right one. I used chrome://bluetooth-internals to get the right UUIDs and I connect to the Muse just fine just no data is being recieved – Luke Piette Jul 25 '20 at 07:39
  • 1
    Does the [demo project](https://github.com/urish/muse-js/tree/master/demo) from the repo work? It's hard to tell why you don't get any data without seeing the complete code, but as far as I remember, you need to do [some setup](https://github.com/urish/muse-js/blob/06e83670a0558297feebe4540f6b11d203003aed/src/muse.ts#L132) before the Muse starts spitting out EEG data – urish Jul 25 '20 at 08:46
  • 1
    That's what I was just going to ask about! I'm running the demo from your repo right now ad it works fine. Just saw in the code that you write values to the Muse before streaming data. I'll try that and let you know if anything changes. – Luke Piette Jul 26 '20 at 16:12
  • Why do you add the length of the entire array as the first array point and '\n' as the last array point in the encoding function? function encodeCommand(cmd) { var encoded = new TextEncoder().encode("X" + cmd + "\n"); encoded[0] = encoded.length - 1; return encoded; } – Luke Piette Jul 26 '20 at 16:25
  • If I'm not mistaken, this is how the protocol works... – urish Jul 26 '20 at 20:24

1 Answers1

0

first is length

second is command - to start streaming it is letter "d" ascii

third is "LF" - dunno if in JS it is not CRLF or whatever - you can use 0x0a...

example (which actually starts sending the raw data you've subcribed to) in swift:

let array: [UInt8] = [2, 0x64, 0x0a]
let data: Data = Data(array)
peripheral.writeValue(data, for: characteristic, type: .withoutResponse)
Adam
  • 158
  • 3
  • 8