• I use https://www.puck-js.com/puck.js and

    Puck.connect(callback);
    

    to connect to Puck.js (v2.09) from my website. While developing, my website will reload upon code changes, which requires me to reselect my already paired Puck.js which is cumbersome.

    I noticed that the WebIDE is capable of connecting to an already paired device without showing the navigator.bluetooth dialog, however it relies on EspruinoTools which I couldn't get to integrate nicely with my webpage.

    let pairedDevices = await navigator.bluetooth.getDevices();
    

    will provide currently paired devices, however forwarding such a device to the connect() method replacing the call to navigator.bluetooth.requestDevice was not successful, resulting in a "Bluetooth device is out of range error". I suspect this happens because the last advertisement packet is too old, so I waited on prepairedDevice.watchAdvertisements() to fire first which took care of the "out of range error" but somehow introduced empty txItem.data items in puck.writeProgress(txItem.maxLength - txItem.data.length, txItem.maxLength);

    Is there a solution that avoids "re-pairing" my Puck.js on every page load, i.e. by adapting the puck.js file or somehow integrating parts of the WebIDE/EspruinoTools?

    Thanks a lot for your help!

  • Thr 2021.04.29

    'While developing, my website will reload upon code changes'
    'Is there a solution that avoids "re-pairing" my Puck.js on every page load'

    Although I haven't tried this, what about using the Html < iframe >element?
    Embed the page that will reload as the iFrame itself, retaining the PuckJs code called from the outer container. In that way, when the inner iframe page is reloaded, the outer calling page doesn't perform the Puck re-initialization.

    https://www.w3schools.com/tags/tag_iframe.asp

    passing data back-n-forth

    https://stackoverflow.com/questions/6271313/pass-a-javascript-variable-from-an-iframe-to-the-parent-frame



    or possibly using the onload() event, set a variable within the page Global scope that bypasses the Html section that loads the PuckJs code.

    https://www.w3schools.com/jsref/event_onload.asp
    https://stackoverflow.com/questions/588040/window-onload-vs-document-onload
    https://www.plus2net.com/javascript_tutorial/window-onload.php
    https://www.codegrepper.com/code-examples/javascript/windows+onload+javascript+w3schools

  • While developing, my website will reload upon code changes, which requires me to reselect my already paired Puck.js which is cumbersome.
    I noticed that the WebIDE is capable of connecting to an already paired device without showing the navigator.bluetooth dialog

    The WebIDE at https://www.espruino.com/ide/ can keep previous connection info and reconnect, however it is also lost when you reload the page. I think this is by design and is some sort of security so devices are not silently accessed across different pages.

  • Hi! This is something I have been wondering about actually.

    I think realistically to do it nicely, it could do with being integrated into the Puck.js/UART.js library itself (at https://github.com/espruino/EspruinoWebTools). I think long term the best thing would be to introduce the functionality to UART.js (which already has the ability to display a menu for >1 device), and then maybe just make Puck.js a stripped down version of UART.js that doesn't do Web Serial (it's getting stupid having two extremely similar libraries).

    The WebIDE at https://www.espruino.com/ide/ can keep previous connection info and reconnect, however it is also lost when you reload the page. I think this is by design

    Yes, I was wondering about that. On Web Serial it works totally as expected, but it seems it doesn't on Web Bluetooth.

    Having said that, this example from the Chrome team themselves doesn't appear to remember devices: https://googlechrome.github.io/samples/web-bluetooth/watch-advertisements-and-connect.html

    But this one does - at least for me: https://googlechrome.github.io/samples/web-bluetooth/watch-advertisements-and-connect-async-await.html

    But apart from the usage of promises vs. async/await I'm having trouble figuring out why!

    However if we can figure that out I'd love to get the changes into the IDE so it does remember, and maybe get the relevant stuff added to UART.js

  • Using an iframe could work for dev page reload, I think it may be possible to even achieve reconnect across a tab/window reload (getDevices() will return an already paired device), but I will keep this workaround in mind, thanks!

  • Thanks for the link.

    https://googlechrome.github.io/samples/w­eb-bluetooth/watch-advertisements-and-co­nnect-async-await.html also gives me the device is out of range error, however, adding a call to requestLEScan() or just requestDevice() seems to trigger advertisement packages, which will cause a reconnect without selecting a device in the dialog.

    However, the scanning/request dialog is still shown (and it doesn't disappear when a device is connected). Is there any option to close the scanning/request dialog programatically? It does not support AbortController signals.

  • Having said that, this example from the Chrome team themselves doesn't appear to remember devices: https://googlechrome.github.io/samples/w­eb-bluetooth/watch-advertisements-and-co­nnect.html

    Oh, it does for me. Clicked 'request device' selected Espruino device. Clicked 'connect to bluetooth devices' and it connected. Then I reloaded the page and clicked connect again and it remembered previous device and connected again.

    EDIT: and btw about that security effort, here is issue https://github.com/WebBluetoothCG/web-bluetooth/issues/358 where they are pretty anal about showing the dialog with no way to circumvent/customize/prevent it but that is for first connection, here https://github.com/WebBluetoothCG/web-bluetooth/issues/164 it clearly says this should work

  • @fanoush: Interesting, could you post details on your OS/Bluetooth/Browser/Espruino combo? Definitely doesn't work for me (macOS 10.15/Chrome 90 + flag:#enable-web-bluetooth-new-permissions-backend/Puck.js v2.09)

    //Press Connect
    Getting existing permitted Bluetooth devices...
    > Got 1 Bluetooth device.
    Watching advertisements from "Puck.js c699"...
    //Stuck here, but if you now press Request and don't select a device:
    Requesting any Bluetooth device...
    > Received advertisement from "Puck.js c699"...
    Connecting to GATT Server from "Puck.js c699"...
    > Bluetooth device "Puck.js c699 connected.
    //Abort Request
    Argh! NotFoundError: User cancelled the requestDevice() chooser.
    

    It seems like for some reason your Espruino is still sending advertisement packets even after it is connected? Do you have any Bluetooth device scanning tool running in the background/in parallel?

  • it is recent Chrome (89) on windows 10, device is nrf52840 dongle with SDK15 based Espruino, however it does not matter, I just tried DK08 watch (sdk11 based firmware) and it worked too. even closed the window, opened new, clicked connect and it even tried both remembered devices and picked up the watch

    Getting existing permitted Bluetooth devices...
    > Got 2 Bluetooth devices.
    Watching advertisements from "Magic3 1f60"...
    Watching advertisements from "DK08"...
    > Received advertisement from "DK08"...
    Connecting to GATT Server from "DK08"...
    > Bluetooth device "DK08 connected.
    

    BTW the dongle is named Magic3 since it is name of some other 52840 hackable watch I was testing FW for.

    No scanning tool running in the backround AFAICT.

    EDIT:
    It can be timing issue, I now tried to reload and quickly connect and was also stuck on "Watching advertisements ", previously I tried successfully several times but always clicked connect after some seconds.

  • now I closed window, removed and reconnected the dongle (=power cycled it, cannot do it with the watch), reopened https://googlechrome.github.io/samples/web-bluetooth/watch-advertisements-and-connect.html page, clicked request device but cancelled dialog, then clicked connect and it connected to both of them

    Requesting any Bluetooth device...
    Argh! NotFoundError: User cancelled the requestDevice() chooser.
    Getting existing permitted Bluetooth devices...
    > Got 2 Bluetooth devices.
    Watching advertisements from "Magic3 1f60"...
    Watching advertisements from "DK08"...
    > Received advertisement from "DK08"...
    Connecting to GATT Server from "DK08"...
    > Bluetooth device "DK08 connected.
    > Received advertisement from "Magic3 1f60"...
    Connecting to GATT Server from "Magic3 1f60"...
    > Bluetooth device "Magic3 1f60 connected.
    

    so now I have opposite problem, don't have easy way to clear the list of remembered devices :-)

  • I can confirm your experience on Windows 10/CSR8510 (Win10 Bluetooth Driver)/Chrome 90:

    Result:

    Getting existing permitted Bluetooth devices...
    > Got 1 Bluetooth devices.
    Watching advertisements from "Puck.js c699"...
    > Received advertisement from "Puck.js c699"...
    Connecting to GATT Server from "Puck.js c699"...
    > Bluetooth device "Puck.js c699 connected.
    

    On macOS I don't get a reconnect because no advertisement packets are received unless I explicitly trigger a scan or request a device.

  • I connected the CSR8510 to my MacBook Pro 16 to check if the difference is caused by Windows or the Bluetooth chip; as a result Bluetooth on my MacBook Pro 16 is now bricked and apparently needs a Logic Board replacement (https://discussions.apple.com/thread/250944058). 🤷

  • Wow, you can actually permanently brick on-board Bluetooth just by inserting a USB stick? that's crazy!

  • It seems like the power requirement for the USB dongle permanently overwrites the (lower) power requirement for the integrated Bluetooth module. As a result the Bluetooth module thinks it is not supplied with sufficient power and shuts down.

    Apparently there is a workaround with certain old Bluetooth 2.0 dongles with similar power requirements to the internal Bluetooth module, 2 I had lying around, which didn't work - I now bought a third one from eBay that I hope will fix this. Can't use the Puck.js until then and can't afford the time to have my MacBook shipped for repairs.

    In the thread they are even shipping around old Bluetooth dongles via post to fix this.

  • @Gordon: What is interesting is that the automatic reconnect works on Windows/CSR8510. Can you clarify which Browser/OS/Bluetooth combo you have where it doesn't? Still trying to find out if this is specific to OS or the Bluetooth chip.

  • I'm using Linux here... Honestly I'd think that changes between OS were most likely due to Chrome's implementation. It's something I imagine we could flag up with them.

    I don't suppose this is related to whether the 'Experimental Web Platform features' flag is enabled?

  • I don't think this is related to the flag, as I can't run the examples without it, IIRC .getDevices() is not defined without the new permission backend flag.

    Interesting that Linux/macOS behave similarly, how can we check if this is a Chrome implementation issue? https://github.com/GoogleChrome/samples/issues does not appear to be monitoring new issues.

  • I think issues need to be filed in https://bugs.chromium.org/p/chromium/issues/list - there's a special bug type for Web Bluetooth I believe

  • it is discussed here https://bugs.chromium.org/p/chromium/issues/detail?id=577953&q=bluetooth%20permissions%20getDevices&can=2
    they mention it is hidden behind flag but I do not remember setting any flag for Chrome on Windows. BTW they link guide https://docs.google.com/document/d/1RF4D-60cQJWR1LoQeLBxxigrxJwYS8nLOE0qWmBF1eo/edit which shows Puck.js as an example :-)

    or there are more issues related
    https://bugs.chromium.org/p/chromium/issues/list?q=bluetooth%20permissions%20getDevices&can=2

    also the https://developer.mozilla.org/en-US/docs/Web/API/Web_Bluetooth_API is not very green for getDevices() line :-(

  • Thanks for the link to the issue tracker. So to summarize, reconnecting to already paired devices should be supported in Chrome when using chrome://flags/#enable-web-bluetooth-new-permissions-backend and chrome://flags/#enable-experimental-web-platform-features and this code:

    async function getPermittedBluetoothDevices() {
      let devices = await navigator.bluetooth.getDevices();
      for (let device of devices) {
        // Start a scan for each device before connecting to check that they're in
        // range.
        let abortController = new AbortController();
        await device.watchAdvertisements({signal: abortController.signal});
        device.addEventListener('advertisementreceived', async (evt) => {
          // Stop the scan to conserve power on mobile devices.
          abortController.abort();
     
          // At this point, we know that the device is in range, and we can attempt
          // to connect to it.
          await evt.device.gatt.connect();
        });
      }
    }
    
    

    However, at least on Linux and macOS, the event advertisementreceived is never triggered. Is that an issue with Chrome, the OS or the device? Looks like .watchAdvertisement is supposed to trigger advertisement packages but it doesn't on Linux/macOS?

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

How to avoid reconnecting an already paired device via WebBluetooth on every page reload.

Posted by Avatar for user128009 @user128009

Actions