• Got my Bangle JS today - been playing with it for hours and doing a bit of tinkering.

    I tried the Active Pedometer which also comes with a Widget. I find the text on the Widgets too small to read even with glasses on. Ideally when I am walking up a mountain in the pouring rain and my glasses are all steamed up I would like to be able to see how many steps I have done without the glasses, so the fonts will need to be large.

    I tried to change the font size on the widget but my upload crashed the watch so had to delete the App and start again.

    In the meantime I looked at the way Multiclock works. This has the concepted of a xx.face.js file which then gets picked up as a screen that can be cycled to using BTN1/BTN3, which is a much nicer interface for moving between Apps.

    I thought it would be great to just have a psuedu clock / screen that just showed.


    | Steps |

    | 7899 |

    I though there might be an easy way to do this (just pick up a global variable).

    BUT when I have looked at the activepedom/widget.js I can see that the bulk of the processing / logging and correction is done inside the widget ? It appears that widgets are being treated as daemons/services with no seperation of the display logic from the actual processing.

    Obviously it would be better if I did not have to replicate the entire code of widget.js just to get the value of todays steps. I guess I could just read the latest value out of the log file.

    Is there a software design issue here with the widget concept ? Should we be thinking in terms of having some sort of store / registry for common output variables so that other simpler code can then just handle the display part ?

    Does anyone have any thoughts on this ?

    Thanks
    Hugh

  • ...one could go the Win 3.0, 3.1, ... way... and abuse the windowing system as pseudo-multi-tasking for background processes. In other words: there are widgets with no real estate that can be talked to apps and widgets w/ real estate and can be talked to by apps and widgets w/ real estate. Problem (quick and dirty9 resolved. Haha...

    @Gordon, what are your thoughts about that? There is obviously a need for services that can process like widgets. Since the 'mechanism' is already there, why not generalize and have applets or servlets that can serve apps and widgets...

  • I think from a future proofing / maintaince point of view having a hidden widget that provided a service would be a good thing. This would enable the display aspects to be seperate from the service aspect. I like the widgets but they are just too small for me to see practically so I will need to produce a bigger screen for looking at the data I am interested in.

    Is writing to "storage" a good way to share data between Apps / Widgets ? For example I could clone the GPS tracking App and get it to just write the contents of the last fix into a 1 line CSV file. Would this be considered hacky is there a better way to do it without getting over complicated ?

  • Here is a screenshot of my proof of concept steps watch face. This reads the last log line from the ActivePedomiter CSV log file. The code needs polishing up. For example there is a 1 second delay while the log file gets read. The code only needs to read the last data, so maybe some optimision might be possible. Also need to handle the log file not being present and a hint to use
    the ActivePedominter App.

    I managed to write the code below to ped2.face.js to Storage and when the multiclock reloads this face gets added. Obviously this is not the correct way. Need to setup my github / bootloader.

    (() => {
    
       function getFace(){
                        
      function getArrayFromCSV(file, column) { 
        var history = 86400000; // 28800000=8h 43200000=12h //86400000=24h
    
        i = 0;
        array = [];
        now = new Date();
        while ((nextLine = file.readLine())) { //as long as there is a next line
          if(nextLine) {
            dataSplitted = nextLine.split(','); //split line, 
            diff = now - dataSplitted[0]; //calculate difference between now and stored time
            if (diff <= history) { //only entries from the last x ms
              array.push(dataSplitted[column]);
            }
          }
          i++;
        }
        return array;
      }
            
      function draw() {
        const storage = require("Storage");
        let now = new Date();
        let month = now.getMonth() + 1;
          
        if (month < 10) month = "0" + month;
        
        let filename = "activepedom" + now.getFullYear() + month + now.getDate() + ".data";
        let csvFile = storage.open(filename, "r");
        let data = getArrayFromCSV(csvFile, 1);
        let steps = data[data.length-1];      
        csvFile = undefined;
        data = undefined;
          
        if (steps > 99999){
             steps = steps % 100000; // cap to five digits + comma = 6 characters
        }
    
        let stps = steps.toString();
        g.reset();
        g.clearRect(0,24,239,239);
        g.setFont("Vector",48);
        g.setColor(1,1,1);  // white
        g.drawString("Steps",50,24,true);
        g.setColor(0,255,0);
        g.drawString(stps,50,96,true);   
      }
           
      function onSecond(){
        var t = new Date();
        if (t.getSeconds() === 0) draw();
      }
    
        return {init:draw, tick:onSecond};
      }
    
      return getFace;
    
    })();
    
    

    1 Attachment

    • IMG_20210103_210741.jpg
  • Hi! There's actually a pedometer built into Bangle.js - I believe Active Pedometer was an attempt to get better step recording than is done by the default firmware, and you might find the 'normal' pedometer a bit cleaner: https://github.com/espruino/BangleApps/b­lob/master/apps/widpedom/widget.js

    However obviously getting elapsed steps is a bit more tricky.

    I'd suggest going with modules if you want a nice tidy solution. As an example, look at gbridge:

    • gbridge uses notifications and adds "dependencies": { "notify":"type" }, to its JSON
    • Both notify and notifyfs implement notify, and have "type": "notify", in their JSON
    • When you install gbridge the app loader checks if you already have an app of type notify, and if not it installs the first one

    So you could do this for the pedometer, then you'd be able to switch out the code you used for step counting and all apps would then use that - plus you wouldn't have to access files directly.

    Having said that, the best solution here would be to get Bangle.js's built-in step counting to a point where everyone was happy just to use that (there's an issue open for it at https://github.com/espruino/Espruino/iss­ues/1846). I guess maybe keeping track of the amount of steps per day could be built in too.

  • Thanks Gordon. Nice to interact with you. Massive thanks for getting this product / concept to market fantastic achievement.

    I did originally try the /widpedom/widget.js but found the numbers in the widget display rather small. I then attempted just the edit the widget.js file and upload to storage, but should have followed the setup your own App store via github mechanism.

    The current step count is stored in stp_today and was not sure if this is a global variable so I could access from another App.

    I tried >stp_today in the IDE and got undefined. I wonder if all I would need to do is create a getTodaysSteps() function in the widget and that would give me the ability to grab what I need for a larger display of the count.

  • then attempted just the edit the widget.js file and upload to storage

    It's a shame you hit trouble there - that should have been quite straightforward. If a 24px high font is ok for you then that'd definitely be a nice easy solution (we could always make the size configurable).

    I wonder if all I would need to do is create a getTodaysSteps() function in the widget

    Ahh - yes, that would be really easy. If you just change:

    WIDGETS["wpedom"]={area:"tl",width:26,dr­aw:draw,reload:reload};
    // to
    WIDGETS["wpedom"]={area:"tl",width:26,dr­aw:draw,reload:reload,getSteps:()=>stp_t­oday};
    

    In the pedometer widget at https://github.com/espruino/BangleApps/b­lob/master/apps/widpedom/widget.js then you'd be sorted, and you could easily access the step count from WIDGETS["wpedom"].getSteps()

    I'm very happy to add that if you want?

  • I tried it out. I am setup in Github now.

    https://github.com/hughbarney/BangleApps­/commit/39829faf26a956243a8f9aa1fb4d6f42­c2a43280

    I tried to update the Active Pedometer widget but each time I found it crashed the watch and I had to delete it through the App Loader.

    I could be making a stupid mistake. I'm not that familiar with the javascript syntax (still learning, though I have a decent naughts and crosses programme working), it looks like you are adding a public function to the widget within the list of properties.

  • Sorry, that was my bad. I'd written the code wrong so it wasn't valid JS (just fixed now).

    So instead of:

    WIDGETS["activepedom"]={area:"tl",width:­width,draw:draw, getSteps=>()=>stepsCounted};
    

    you want:

    WIDGETS["activepedom"]={area:"tl",width:­width,draw:draw, getSteps:()=>stepsCounted};
    

    If you update with the Web IDE (info on uploading widgets is at http://www.espruino.com/Bangle.js+Widget­s#how-to-develop) then you'll be able to see an error message pointing you at the problem (if there is one). You can also just re-upload if it makes the watch stop working.

  • Yeah. Pull request made.

    I managed to test with a ped.face.js clock face. Using the following code.

    () => {
    
      function getFace(){
    
      function draw() {
          let steps = -1;
          let show_steps = false;
    
          // only attempt to get steps if activepedom is loaded
          if (WIDGETS.activepedom !== undefined) {
             steps = WIDGETS.activepedom.getSteps();
             show_steps = true;
          }
    
          var d = new Date();
          var da = d.toString().split(" ");
          var time = da[4].substr(0,5);
    
          g.reset();
          g.clearRect(0,24,239,239);
          g.setFont("Vector", 80);
          g.setColor(1,1,1);  // white
          g.setFontAlign(0, -1);
          g.drawString(time, g.getWidth()/2, 60);
    
          if (show_steps) {
              g.setColor(0,255,0);  // green
              g.setFont("Vector", 60);
              g.drawString(steps, g.getWidth()/2, 160);
          }
      }
    
      function onSecond(){
          draw();
      }
    
        return {init:draw, tick:onSecond};
      }
    
      return getFace;
    
    })();
    

    There are probably improvements that can be made to the above code. EG it flickers.
    I also tried

      function onSecond(){
        var t = new Date();
        if ((t.getSeconds() % 5) === 0) draw();
      }
    
    

    I can see from the other multiclock examples that there are better ways of writing the display to avoid flicker.

    I attempted to check ped.js into github multiclock/ped.js but when I updated the json file, my personal App loader would not show the latest version id ?

  • That looks great!

    my personal App loader would not show the latest version id ?

    I think it's just that you needed to update the version in apps.json too.

    I can see from the other multiclock examples that there are better ways of writing the display

    There are a few ways, but the easiest is probably just to use clearRect on just the area you're writing text to, just before you update it (rather than clearing the whole screen).

    You could also do something like if (steps == lastSteps) return; just to stop it updating the screen if nothing has changed...

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

Active Pedometer / Widget and having it shown on a page / clock face

Posted by Avatar for HughB @HughB

Actions