Feeding data from Android phone to Bangle.js continuously?

Posted on
Page
of 2
/ 2
Next
  • Hi!

    The two most important features of a smart watch, for my personal use, are displaying notifications, and displaying a particular integer that my phone knows that is updated every 5 minutes (it's my blood sugar, retrieved by xDrip+, but that's not a terribly important detail).

    Notifications seem to be easy, thanks Gadgetbridge!

    The display of the integer is where things get difficult, and I'm trying to figure out a good starting approach. My experience with Bluetooth has been that it's really easy to get caught in confusing dead ends where you can't tell whether you have some small bug or your whole approach is wrong, so I'd appreciate some direction before I dive in too deep.

    The phone can publish the data in a few ways: it's send out as a broadcast Intent in Android, and it can be accessible through a local Web server, so I can write an Android app that hooks into either of those methods and forward it along to any other method, like advertising with Bluetooth.

    Then, I'd write a widget or custom watch face in the Bangle.js that listens for that advertisement and displays the value.

    However, if I'm reading things right, then this would interfere with other NRF functions, so Gadgetbridge would stop working? I'd really like to know this before I've written the two ends of this system.

    It seems like another approach could be to modify Gadgetbridge, to use the channel it already has set up, but to make a special kind of "notification" that is intercepted in the Bangle.js app and interpreted to mean "save these data into storage." Then my widget could just read from storage and display the value there. Of course, this would mean either maintaining my own fork of Gadgetbridge, or getting my code path merged in for this specific, personal need, neither of which seems great.

    Does anyone have any insight or suggestions? There's lots of help for using the sensors built into the Bangle.js, but I haven't found anything clear for doing something like this.

    Thanks in advance!

  • Hi! This is something that's been a frustration for me for a while. Basically Gadgetbridge is big on privacy, so much so that they will never add any internet connectivity to it (although you could build it in yourself).

    Since Gadgetbridge has the Bluetooth connection open you're also a bit stuck for Bluetooth comms. My personal wish would be have a WebView running in Gadgetbridge that has access to send/receive from Bangle.js - but given the lack of internet access that's not an option.

    I'd been talking to Andreas (one of the lead developers) about this and he is willing to try and add something, but it seems that inter-process comms in Android can also be a bit insecure so it's actually a bit tricky.

    So right now I think you have a few options - ordered by how hard they are :)

    • Easiest (IMO) is display a notification from your app. Gadgetbridge should then pick that up and pass it to the Bangle, where you can get it really easily.
    • You could make your phone advertise the data over Bluetooth, and then Bangle.js can pick it up with 'NRF.requestDevice' - that's not related to the connection so won't be an issue, but the data is effectively public for anyone listening for Bluetooth devices
    • You could make Bangle.js connect to your phone (the phone will already be connected to Bangle.js, but you can have a connection the other way too!) - and you could add a Bluetooth service to your phone for the xDrip+ - but honestly this way seems a lot more painful.



  • Thank you, this is really good detail!

    Interesting to hear about Gadgetbridge's reasoning. I can definitely respect it. I'll keep an eye out for updates, but won't wait on them.

    You're right that a notification would be easiest, but I do hope to avoid it, because I get notifications when the number I care about goes out of bounds (too high or too low), and so also having them for ordinary values (which I want to check idly from time to time) would become too busy.

    I didn't realize that the phone could advertise the data and the Bangle.js could pick it up. That sounds very promising. I don't actually care about privacy for this case. Even though it's technically medical information, I honestly am perfectly fine with someone else (someone would would have to be near me, even) knowing it. I mean, I actually publish the data to a website, I just don't share that URL too much. Convenience way outweighs privacy for me for this particular case. I'll take a look at this route. I assume that I'll need a (tiny) Android app to advertise the data. Oh, and if I ever decide I really do care about security, I'll set up a one-time pad or something to encrypt the data.

    I'm constantly surprised by Bluetooth semantics. The Bangle.js connecting to the phone is definitely interesting. I agree it's a pain, but, assuming it doesn't cost too much for either of their batteries, I might look at that long-term. If I could make it work then I could have a general pipe for data between them and that sounds fantastic.

    Thanks again! I don't know if any of this will become an app that would make sense to publish, but I'll at least update this thread with my findings in case anyone else comes looking.

  • I assume that I'll need a (tiny) Android app to advertise the data

    Yes, I think so... You might be able to use DroidScript but I'm not sure how much Bluetooth support it has - probably using Android directly will be easier in this case.

    In terms of power usage, it'd use less power to have a connection - the most power consuming part of Bluetooth is receiving data, and when there's a connection the devices arrange that they're only listening for data at certain times. When you're listening for Advertising data you can't be sure when it'll be, so you have to listen all the time which takes a bunch of power.

    However it's less of a deal on the Bangle - realistically you could listen for Bluetooth data for a full 24 hours before the battery ran out. In reality I imagine you'll end up listening maybe every 30 seconds for just enough time to get advertising data (~0.5 sec?) so the impact to battery will go right down.

    All you need is something like:

    function doScan() {
      NRF.requestDevice({ filters: [{ name: 'My_phones_BT_name' }] }).then(function(device) {
       // the data should be in the 'device' object 
      });
    }
    setInterval(doScan, 30*1000); // 30 secs
    

    I'll at least update this thread with my findings in case anyone else comes looking.

    That would be great! Getting data onto the Bangle is something a lot of people would be interested in.

  • This conversation brings me an idea. What if we create a small Android app made in MIT App Inventor for BangleJS?

    But yes there is a caveat is MIT app inventor apps does not supports background services or task out of the box for web the app will be in background no notifications will be sent to BangleJs. But this can be fixed via adding some extension. Few are paid but those are more then hack.

  • Do you think using App Inventor really helps? I'd have thought just a basic Android app would probably be more use for most people?

    The problem is really the interaction with Gadgetbridge (if you're using that). If you're not, and you don't care about background apps, then Web Bluetooth apps work great

  • Just to add, the advertising works well. I:

    • Opened the 'nRF Connect' app on the phone
    • Clicked 'Advertiser' and set the phone up to advertise with manufacturer data 0x0590 (Espruino's manufacturer data)
    • Opened Web IDE on the phone and connect to the Bangle
    • Ran NRF.requestDevice({ filters: [{ manufacturerData:{0x0590:{}} }] }).then(print); on the Bangle, and you see something like:

      BluetoothDevice: {
      "id": "80:58:f8:98:77:6d public",
      "rssi": -51,
      "data": new Uint8Array([7, 255, 144, 5, 222, 173, 190, 239]).buffer,
      "manufacturer": 1424,
      "manufacturerData": new Uint8Array([222, 173, 190, 239]).buffer
      }
      

    It might be hard to filter by device mac address as modern phones change their address to stop tracking, so using manufacturerdata works pretty well.

    I believe this is what you need to do it directly from an Android app: https://developer.android.com/reference/­android/bluetooth/le/BluetoothLeAdvertis­er

    Note: I have the Covid contact tracing enabled on my phone, and that stops nRF connect from advertising any data - so you'll either need to disable the app, or use a different phone to be able to use advertising correctly. Hopefully once the vaccine is widespread the contact tracing will be a thing of the past though.

  • Yes, not sure I am following you, but I think MIT app is more capable of doing lots of custom things. And BangleJs needs it’s very own app to interact with. Basic use case of app where you can push latest news, announcement and update. Very own way to send notifications to BangleJs.

    Web Ble App Store works grate for installing and updating apps but it is not practical to do everyday “smartwatch” stuff from mobile browser as a use needs a lot user actions to perform a simple task. A dedicated app would make more sense to me.

  • Let’s start collate an Idea and user of BangleJs design and develop it.

    “Form the community, For the community” model.

  • Let’s start collate an Idea and user of BangleJs design and develop it.

    Maybe you could do that as a separate thread to avoid pulling @epw's off-topic?

  • Sure @Gordon.

    Sorry @epw, my intention was not to hijack your thread :).

  • No problem @Abhigkar, and in fact that's just where I was going next! So please do start that thread, and I'll be there.

    Gordon, thank you for the continued direction! I had been hoping to test it out before writing a little app, but didn't know about nRF Connect, only nRF Toolbox. I haven't had a chance to try and follow your steps yet but I'm about to start.

  • Working great so far!

    My current plan has 3 steps:

    1. I'll write a small Android app that can be configured to accept broadcast Intents and advertise the contained data with BLE.
    2. A Tasker profile can receive the broadcast Intents from xDrip and broadcast a new one in the form useful for the advertisement app (yes, I could encode that in the app, but I'd rather make it more general-purpose).
    3. A watch face or widget will poll for the advertisement every 5 minutes and update the display.

    I'll link the Android app here when I have it. It will be open source, of course.

  • Sounds great! I had a little try last night with something that'd grab a URL, pull data out of it and broadcast it. The BLE code you need is:

            BluetoothManager mBluetoothManager = (BluetoothManager)mContext.getSystemServ­ice(Context.BLUETOOTH_SERVICE);
            BluetoothAdapter mBluetoothAdapter = mBluetoothManager.getAdapter();
            BluetoothLeAdvertiser mBluetoothLeAdvertiser = mBluetoothAdapter.getBluetoothLeAdvertis­er();
    
            AdvertiseSettings.Builder settingsBuilder = new AdvertiseSettings.Builder();
            settingsBuilder.setAdvertiseMode(Adverti­seSettings.ADVERTISE_MODE_BALANCED); // was ADVERTISE_MODE_LOW_POWER
            settingsBuilder.setTimeout(0); // always!
            //setTxPowerLevel(ADVERTISE_TX_POWER_HIG­H.)
            AdvertiseSettings settings = settingsBuilder.build();
    
            AdvertiseData.Builder dataBuilder = new AdvertiseData.Builder();
            dataBuilder.addManufacturerData(0x0590, foundData.getBytes());
            //dataBuilder.setIncludeDeviceName(true)­;
            AdvertiseData data = dataBuilder.build();
    
            mAdvertiseCallback = new SampleAdvertiseCallback();
    
            mBluetoothLeAdvertiser.stopAdvertising(m­AdvertiseCallback);
            mBluetoothLeAdvertiser.startAdvertising(­settings, data,
                    mAdvertiseCallback);
    
  • App is here: https://github.com/espruino/AndroidBLEAd­vertiser

    Every 15 minutes it'll fetch the webpage given and set your phone's Bluetooth advertising to Espruino's 0x0590 manufacturer data with the value from the RegEx's first match group.

    By default it'll show you roughly how many people have been rickrolled to date.

    Not quite what @epw needs but hopefully it's a good start, and makes it super easy for everyone else to script common tasks (eg grab data from a website, get it on your wrist). Hopefully it's pretty energy efficient too.

    It's just a shame the Android API appears to stop an app from executing background tasks more often than every 15 minutes

  • That app is great! You're much faster than me.

    It could even do what I want, since xDrip can run a local Web server, so it could just be pointed to that. And I love the idea in general!

    However, the 15 minute limitation probably does stop this method from working for me. Updates coming every 5 minutes are about as slow as I can handle for this.

    xDrip is already running constantly (persistent notification and everything), so I'm investigating having it advertise the data in its broadcast method. It doesn't help the Bangle.js ecosystem as much, but will still teach me things.

    Thanks for the continued attention!

    If a Bangle.js "companion app" for Android starts being developed, I'll still definitely want to help with that if I can.

  • @epw! interestingly PineTime also have a companion app built on top of flutter_blue library and same code can be compile in to Android or iOS app.

    Unfortunately java/DART are not my skill set. So not able to understand much!!

  • This thread is exceptional, as it's tackling a problem I was encountering.

    What are thoughts on feasibility of these ideas:

    1. Having a URL embedded in an app on a Bangle.js
    2. An app on a phone to interrogate apps on the Bangle to build a list of URLs and sample rates
    3. Phone samples URLs via web, puts together a data package
    4. Forward to Bangle, where apps will parse for their relevant data.

    My thought is to build a "universal" standard for pushing data to the Bangle, allowing homebrew apps to flexibly acquire it without much user configuration on a phone-based middleman app.

  • I'm going to give this a shot. Going to start with creating a list of queries for the app to run: a dictionary of URLs, query frequencies, and methods to process the query result. Push to espruino/Bangle.js.

    I've a decade of programming experience, but I'm new to Java/Mobile development, so if there's any advice I'm in the market.

  • Hi, That'd be great!

    The poll and report idea is quite interesting and would work great with the advertiser app I posted up.

    However if you're going to keep a two-way connection to the watch itself open, I'd say it is probably better to actually respond directly to queries from the Bangle.js app. For instance the Bangle.js app might send the text {"type":"get","url":"http://....."}, and then your app could respond with the webpage. I think that's more flexible, and it actually avoids you having to manage querying for URLs and storing all that info somewhere

  • Just ordered my Bangle a few short hours ago, now dizzy with anticipation. I second this thread is exceptional.

    Personally I'm hoping to have health check status for various web services I maintain displayed as a widget. @epw I think you're use case trumps mine though, quite literally a health check, very worthwhile to be sure.

    It's just a shame the Android API appears to stop an app from executing background tasks more often than every 15 minutes

    @Gordon my understanding is that is a limitation of the WorkManager API (I have yet to try it out), yes? I believe you make reference to this in your comments (see MIN_PERIODIC_INTERVAL_MILLIS).

    It seems some people work around this by scheduling a OneTimeWorkRequest instead, with a set delay to control the execution frequency, and ending by calling another OneTimeWorkRequest.

    Hard not to wrinkle my nose a little bit at this, but Android does seem to have collected an awful lot of scheduling APIs by now, and if you simply want to run your task every 5 minutes... well..

  • It seems some people work around this by scheduling a OneTimeWorkRequest instead

    Thanks - yes, that sounds like it could work great (or as you say there seem to be other options as well). If someone wanted to make a PR to add it to https://github.com/espruino/AndroidBLEAd­vertiser I'd be more than happy to pull it in :)

  • Happy to! I may need to figure out how to mimic the Bangle in Python or something first though for testing. Does anyone have any recomendations for Bluetooth (LE) libraries?

  • Does anyone have any recomendations for Bluetooth (LE) libraries?

    This might help: https://www.espruino.com/Interfacing

    However trying to emulate a Bangle first (if you're doing connections) might end up sucking up a bunch of time. If you want to debug a Bluetooth LE UART connection I'd suggest getting another Espruino device that you can connect a non-bluetooth UART to - then you can connect over serial and see what's happening on Bluetooth.

    Official MDBT42 and Pixl.js boards are easy to add a USB-TTL converter to but don't work out of the box, or the cheapest/easiest option is to just get a micro:bit 2, which there are Espruino builds for

  • Dear @epw,
    I have recently bought a similar device to espruino and I'd like to do exactly the same you stated at the beginning of the post. XDrip>WebServerBroadcast>BG data to smartwatch.
    I am facing similar issues like gadgetbridge or nRFConnect won't have a http request web service that could return the BG data via BLE to the SmartWatch.
    I was wondering how far you've got with this project.
    I am a very beginner in coding (I do mainly testing :)), and therefore any help to get me started and in the right direction would be more than welcome.
    Thanks a lot in advance!

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

Feeding data from Android phone to Bangle.js continuously?

Posted by Avatar for epw @epw

Actions