urish / muse-js

Muse 2016 EEG Headset JavaScript Library (using Web Bluetooth)
https://medium.com/@urish/reactive-brain-waves-af07864bb7d4
MIT License
280 stars 78 forks source link

Handle bootloader connection issue #12

Open jdpigeon opened 6 years ago

jdpigeon commented 6 years ago

Just noticed that muse-js is running into a similar issue that Muse LSL did before this PR: https://github.com/alexandrebarachant/muse-lsl/pull/37

When a headband is charged from empty all the way to full, it will often go into a different preset mode ('bootloader') and require a 'reset to headset mode' command (0x03 2a 31 0a) before it's BLE characteristics are made available for connection.

Attempting to connect to the headset in this mode leads to the following error: No Characteristics matching UUID 273e000b-4c4d-454d-96be-f03bac821358 found in Service with UUID 0000fe8d-0000-1000-8000-00805f9b34fb.

I suggest that we add a getDeviceInfo check to the connect function and handle a 'bootloader' device state by sending a reset command with the sendCommand function

urish commented 6 years ago

Thanks! PR?

jdpigeon commented 6 years ago

Can confirm that client.sendCommand("*1") kicks the headband out of bootloader and into headset mode.

Will make a PR sometime this week. Do you agree with the addition of a deviceInfo check to the connect function?

urish commented 6 years ago

Awesome. Yes, sound good - this should be transparent for the user.

deviceInfo is using async/await, which is a new feature in JavaScript which add syntactic sugar on top of promises:

    async deviceInfo() {
        const resultListener = this.controlResponses.pipe(filter((r) => !!r.fw), take(1)).toPromise();
        await this.sendCommand('v1');
        return resultListener as Promise<MuseDeviceInfo>;
    }

This is equivalent to writing:

    deviceInfo() {
        const resultListener = this.controlResponses.pipe(filter((r) => !!r.fw), take(1)).toPromise();
        return this.sendCommand('v1').then(() => {
            return resultListener as Promise<MuseDeviceInfo>;
        });
    }
jdpigeon commented 6 years ago

Ah thanks man, I'll get on it.

Turned out I just forgot to execute it. deviceInfo sounds like a property to me, not a function. Maybe I should rename it to getDeviceInfo?

urish commented 6 years ago

Perhaps it'd make more sense, but that would also break the API. I'd rather keep it this way...