Widget idea: BLE Battery Service

Posted on
  • Hi. I was thinking it would be nice if the Bangle could advertise it's battery level (so Home Assistant can remind to charge it, for example).

    Does anything like this exist? Is a widget the right way to do it? Something like this works for me.

    (() => {
      function advertiseBattery() {
        NRF.setAdvertising([
          {0x180F : [E.getBattery()]},
        ]);
      }
      
      setInterval(advertiseBattery, 60 * 1000);
      advertiseBattery();
      
      // add your widget
      WIDGETS["ble_battery_service"]={
        area:"tl", // tl (top left), tr (top right), bl (bottom left), br (bottom right)
        width: 0, // how wide is the widget? You can change this and call Bangle.drawWidgets() to re-layout
        draw: function() {} // called to draw the widget
      };
    })()
    

    I'll open a PR if this is sensible. Thanks.

  • What would happen if another app or widget also called NRF.setAdvertising()? Would one overwrite the other? I can see that being a problem.

  • Hi - that sounds like a good idea...

    But yes, multiple calls to NRF.setAdvertising() could overwrite each other. To work around it you could do:

    if (!Bangle.bleAdvert) Bangle.bleAdvert = {};
    function advertiseBattery() {
      Bangle.bleAdvert[0x180F] = [E.getBattery()];
       NRF.setAdvertising(Bangle.bleAdvert);
    }
    

    Then as long as other apps followed the same form they could all work together

  • What do I need to do to make this available on Bangle JS 2 as well? Just test to see if it works, then update "supports": ["BANGLEJS"],?

  • Yes, that's all that's needed - thanks!

    You can test it just by connecting with the app loading, clicking top-left to choose 'all apps' and then clicking 'install'

  • How would I use this example as a way use my bangle2 to advertising it as a beacon?
    I have tried

    
    (() => {
      function advertiseBeacon() {
        NRF.setAdvertising([
          require("ble_ibeacon").get({
            uuid : [0xb1, 0xae, 0x51, 0x2b, 0x97, 0x03, 0x4a, 0xe2, 0xb9, 0xc3, 0x9e, 0x26, 0x0c, 0xa7, 0xb3, 0x99],
            rssi : -60
          })
        ]);
      }
      setInterval(advertiseBeacon, 60 * 1000);
      advertiseBeacon();
    })();
    
    

    but get a "Uncaught Storage Updated" when I try to save it to a file in storage on the watch.

    I want to figure out how to use it in this format

    Bangle.bleAdvert[0x180F] = [E.getBattery()];
    

    so they all play together
    Thanks
    Katherine

  • but get a "Uncaught Storage Updated" when I try to save it to a file in storage on the watch.

    That's fine I think. All it means is you changed the boot code (I guess you wrote it to xyz.boot.js?) and so Bangle.js had to rewrite the .boot0 file with your new code. If you do load() on the left-hand side or just long-press the button, the bangle should load up and everything will work ok.

    For the bleAdvert form, it's best to use https://github.com/espruino/BangleApps/t­ree/master/apps/bootgattbat as an example.

    **BUT ** the issue is that iBeacon can't be used in the same advertising packet as other data. It has to have a packet all to itself.

    All I can suggest is:

    (() => {
      function advertiseBeacon() {
        NRF.setAdvertising([
          Bangle.bleAdvert,
          require("ble_ibeacon").get({
            uuid : [0xb1, 0xae, 0x51, 0x2b, 0x97, 0x03, 0x4a, 0xe2, 0xb9, 0xc3, 0x9e, 0x26, 0x0c, 0xa7, 0xb3, 0x99],
            rssi : -60
          })
        ]);
      }
      if (!Bangle.bleAdvert) Bangle.bleAdvert = {};
      setInterval(advertiseBeacon, 60 * 1000);
      advertiseBeacon();
    })();
    

    Which will 'rotate' the advertisements - so you get one Bangle.js advert and one iBeacon one. However the next time another app like bootgattbat updates, it'll effectively disable iBeacon until your app updates it again.

    I don't see there's an easy way around that, apart from maybe overwriting setAdvertising:

    var myiBeacon = require("ble_ibeacon").get({
            uuid : [0xb1, 0xae, 0x51, 0x2b, 0x97, 0x03, 0x4a, 0xe2, 0xb9, 0xc3, 0x9e, 0x26, 0x0c, 0xa7, 0xb3, 0x99],
            rssi : -60
          });
    var _setAdvertising = NRF.setAdvertising;
    NRF.setAdvertising = function(a,b) {
      if (Array.isArray(typeof a)) a = [a,myiBeacon];
      _setAdvertising(a,b);
    };
    
      function advertiseBeacon() {
        NRF.setAdvertising(Bangle.bleAdvert);
      }
      if (!Bangle.bleAdvert) Bangle.bleAdvert = {};
      setInterval(advertiseBeacon, 60 * 1000);
      advertiseBeacon();
    
    
    
  • Thanks for info on error.
    Also - thanks for overwrite of setAdvertising. Tried it and get an error on left side of ide at line 7: invalid typeof value "array"
    I g-searched but could not come up with a fix. I assume you are checking to see if incoming a is an array? Sorry - just a hair above my javascript knowledge.

  • Ahh, ok - my fault. I've just updated it to use if (Array.isArray(typeof a)) a = [a,myiBeacon];

  • Uncaught error: Too much recursion stack is about to overflow
    in function "_setadvertising" called from line 9 col 21 in .boot0
    

    First "rotating" the advertising code seems to work. Stick to no more ble advertising and I should be fine?

  • Could you post up exactly the code you used?

    It seems like maybe you could have had the code in there twice, or var _setAdvertising = NRF.setAdvertising; after NRF.setAdvertising =.

    ```

  • Nope. With code below I only get to the bangle logo with a line
    -> bluetooth

    then it sticks

    var myiBeacon = require("ble_ibeacon").get({
      uuid : [0xbd, 0x84, 0xb1, 0xb2, 0x1c, 0x2c, 0x00, 0xbe, 0x0c, 0xe9, 0x26, 0x70, 0x0f, 0xfe, 0x0c, 0xa0],
      rssi : -74
    });
    
    NRF.setAdvertising = function(a,b) {
      if (Array.isArray(typeof a)) a = [a,myiBeacon];
        _setAdvertising(a,b);
    };
    
    var _setAdvertising = NRF.setAdvertising;
    
    function advertiseBeacon() {
      NRF.setAdvertising(Bangle.bleAdvert);
    }
    
    if (!Bangle.bleAdvert) Bangle.bleAdvert = {};
    
    setInterval(advertiseBeacon, 60 * 1000);
    
    advertiseBeacon();
    
  • ok. Cleared out all my files, went back to basics.
    added an image and an info file to storage. then added a ibeacon.boot.js file to storage with

    var myiBeacon = require("ble_ibeacon").get({
      uuid : [0xxx, 0xxx, 0xxx, 0xxx, 0xxx, 0xxx, 0xxx, 0xxx, 0xxx, 0xxx, 0xxx, 0xxx, 0xxx, 0xxx, 0xxx, 0xxx], [#myuuid](http://forum.espruino.com/sear­ch/?q=%23myuuid)
      rssi : -74
    });
    var _setAdvertising = NRF.setAdvertising;
    NRF.setAdvertising = function(a,b) {
      if (Array.isArray(typeof a)) a = [a,myiBeacon];
      _setAdvertising(a,b);
    };
    function advertiseBeacon() {
      NRF.setAdvertising(Bangle.bleAdvert);
    }
    if (!Bangle.bleAdvert) Bangle.bleAdvert = {};
    setInterval(advertiseBeacon, 60 * 1000);
    advertiseBeacon();
    

    did a load() and it disconnected from bangle2 with prompt not detected, upload failed, trying to recover. And it reconnected. At that point I checked the file was saved - it was and I did load() and then disconnected - and all seems to work. It is picked up by Home Assistant Espresense as an ibeacon.

    I guess I should now try t add widget bootgattbat and see if they all work together. First... a backup

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

Widget idea: BLE Battery Service

Posted by Avatar for user91203 @user91203

Actions