Qigong button (Puck)

Posted on
  • (I moved this from my comment to Please post what you're working on..)

    My brother had the idea of giving our parents a Qigong button. He had that idea a few hours before our Christmas gathering, so I just had to go for it and try to make a working prototype as fast as I could. I couldn't get the espruino package to work at the time, so I had to use Web Bluetooth instead. I had never used the Puck.js web library before, so it took a bit of poking around to understand how it worked, plus some odd issues, but I got a prototype ready just in time. My parents loved it – the rest of the family had no clue what on earth Qigong was and what it had to do with that strange looking button…

    Some issues I encountered:

    • You can't connect to a Puck from a website without a user action, like pressing a <button> (I should've RTFM..)
    • The Web Bluetooth example's onLine() function receives data with a trailing newline, because the Puck uses "\r\n" instead of "\n" which the code expected. It was an easy fix, but took some time to figure out as Chrome's dev tools didn't show the trailing newline.
    • Just as I got it working, the Puck wouldn't show up anymore when trying to connect :/ Turning Bluetooth off and on again didn't help, but rebooting my laptop did. That is Bluetooth's biggest weakness if you ask me, pairing can be very shaky at times.. Edit: I've since learned that a BLE peripheral won't advertise itself when connected, and if it gets stuck in connected mode you can remove the pairing, thanks to this.
    • The first time the button is pressed after connecting, the returned data (a string: "qigong") is prefixed by ">" when passed to onLine(). Not sure why that is – any ideas?
    • It's impossible to paint on silicon! We ended up using black Tec7 paste, which actually worked pretty well.

    You can check out the code here:

    And if you want to practice Qigong, try it out with your Puck here:

    When connected, your Puck will be reset() and my code written to it. I'm using a bit of a hack to write any function's body to the Puck when connecting, for rapid prototyping. That way I could quickly change the code on the website and Puck at the same time.

    Now I just have to get it working in Node with noble.

  • (This was cross-posted from this comment)

    My node version is done. noble worked great, although it's not the easiest of APIs. Maybe my code can be of use to someone looking to try something similar.

    I've also cleaned up the web version, and maybe taken it a bit too far on the visuals..

    It's probably the strangest (yet beautiful) thing I've ever made. And I don't even practice qigong..

    By the way, I can recommend Netlify for hosting Web Bluetooth Puck projects with HTTPS, as an alternative to GitHub Pages. It's free and easy to connect to git repositories on GitHub/GitLab/Bitbucket/etc. Just git push, wait a few seconds, and it's live. It also supports uploading of files.

  • Thanks! Actually I missed this the first time:

    The first time the button is pressed after connecting, the returned data (a string: "qigong") is prefixed by ">" when passed to onLine(). Not sure why that is – any ideas?

    It's because Espruino writes some text to the console (the command-line interface part) to show that it's moved on to Bluetooth. You could add LoopbackA.setConsole(1) to force the console not to move to Bluetooth - but if you did that then you wouldn't be able to program it until you reset it :)

  • @Gordon Aha, I see. Good to know.

    About your suggestion here, I didn't know that a constant BLE connection used so much power. I assumed that since it's no longer constantly advertising it would use less power, but one should never assume. Again, should've RTFM :)

    As it is, my current code does keep a constant connection. The node script scans for the button and connects to it as soon as it's found, returning to scanning again if the connection is dropped. When connected, it listens for data sent over the UART BLE service. It's unfortunate if that drains the battery, I'd like it to last as long as possible, this being a button that gets pushed only once a day :)

    I looked into having the Puck be the central and the node script the peripheral with bleno, but seems like that puts the heavy lifting on the Puck side? I read an article on making the most out of BLE's advertising mode, to create very low-powered sensors that transmit data using only advertisement packets – unidirectional broadcasting to any listeners.

    Would it be a good idea to have the Puck listen for a button push, and only then advertise the button push event (for the Node script to pick up), before going back to idle? Or maybe add a confirmation step by waiting for the node script to connect after receiving the advertisement and then immediately disconnecting again (with a timeout on the Puck)?

    In general, what's the best way to have a Puck send an event to a node script, with long irregular intervals between each event, if one wants long battery life? I don't mind having the node script continuously scanning/listening, I'll use forever to make sure it always runs.

  • The continuous connection power usage is something I'll try and fix at some point. Basically you have a choice of transmission speed or power usage - when programming Puck.js I need it to go as fast as possible, so it needs to draw quite a bit of power. However I could add an option to set the Puck up so that the connection was very slow, but power efficient, and then you could stay connected for long periods without problems.

    Making Puck do the connection to other devices is a bit more complex for it, but it handles it just fine - and it's not like it uses a bunch of power. The only gotcha is making sure that bleno works on the computer you're trying to connect to.

    With advertising, Puck.js advertises normally. You could make it go to sleep properly when not pressed and it'd really increase the battery life past the 1 year quoted, but I wouldn't worry too much. Often it's nice for your computer to be able to know that the Puck is in range but not pressed.

    One other option is to make the Puck a HID button, and then put it to sleep when not pressed. If you're confident that the Mac will autoconnect whenever it sees it, that could work pretty well. Once pressed, the button will wake up, the Mac will autoconnect, and once connected the button could transmit a button press.

  • Thanks for explaining this so clearly, I really appreciate the time you take to answer questions and help solve issues!

    I'll have to evaluate the alternatives here, they all sound doable. Although BLE is far from simple, I actually like the flexibility it provides, makes it possible to optimise for each use case.

    Would be nice to be able to enable slow but power efficient continuous connections, especially for long-running sensors transmitting small chunks of data. But I'm perfectly fine with any of the other options for my button if they do the trick :)

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

Qigong button (Puck)

Posted by Avatar for Joakim @Joakim