Avatar for Joost

Joost

Member since Jul 2018 • Last active Oct 2018
  • 4 conversations
  • 15 comments

Most recent activity

  • in Puck.js, Pixl.js and MDBT42
    Avatar for Joost

    Hi,

    sorry for opening a new topic again already, but I hope that our notes might help somebody else later on.

    Right now I am connecting like this to my bike sensor:

    NRF.requestDevice({ timeout:5000, filters: [{ services: "0x1816"  /* namePrefix: 'Wahoo' */ }] }).then(function(device) {
      console.log(device);
      return device.gatt.connect();
      }).then(function(gatt_object) {
        gatt = gatt_object;
        s = "Looking for service...";
        g.clear(); g.drawString(s ,0 ,0); g.flip();
        return gatt.getPrimaryService("1816");
        }).then(function(service) {
          s = "Looking for char...";
          g.clear(); g.drawString(s ,0 ,0); g.flip();
          return service.getCharacteristic("0x2A5B");
        }).then(function(characteristic) {
          characteristic.on('characteristicvaluech­anged', OnNotify);
          return characteristic.startNotifications();
          }).then(function() {
            connected = true;
            t = getTime();
            setDisplayMode("livedata");
            gatt.device.on('gattserverdisconnected',­ function(reason) {console.log("gattserverdisconnected, Grund: "+ reason+" Zeit: " + (getTime() -t) + " sec"); disconnect(reason);} ); 
    }
    

    Initially, I even had a timeout of 20 seconds in requestDevice, which led to pretty unreliable connection intitation.
    With nrfConnect I see that the sensor starts advertising really fast with an interval of 330ms initially.
    I wonder if it is possible to cut the timeout short (right now it seems that the code scans for the full timeout before handing back scan results) and return a matching device immediately?

    Or is it preferable to cache the sensor's address and do a direct connect to that later on? That would have the (very small) drawback of needing additional logic to do a full scan if the previous/cached device is not successfully connected, to enable connecting to new/other sensors.

    Thanks,

    Joost

    • 4 comments
    • 165 views
  • in Puck.js, Pixl.js and MDBT42
    Avatar for Joost

    Thank you both,

    this works great it seems:

    gatt.device.on('gattserverdisconnected',­ function(reason) {console.log("gattserverdisconnected, Grund: "+ reason+" Zeit: " + (getTime() -t) + " sec"); disconnect(reason);} ); 
    

    with variable t being set earlier upon successful connect.

    with reason 8 triggered when the BLE server (my sensor) goes out of reach (loss of reception) and reason (int) 19 gets triggered when the sensor shuts down due to inactivity.

    Thanks again,

    Joost

  • in Puck.js, Pixl.js and MDBT42
    Avatar for Joost

    Hi everybody,

    I'm wondering if there is a callback of some sort if/when the espruino device loses connection to a BLE sensor, when subscribed to it's notifications?

    Otherwise I would reset a timer upon reception of every notification, and check say every 15 seconds if the timer was reset (meaning notifications were still received), and disconnect if not.

    What do you think?

    Thanks, Joost

    • 8 comments
    • 192 views
  • in Puck.js, Pixl.js and MDBT42
    Avatar for Joost

    Hi Gordon, thanks a lot!

    The switch/break error seems fixed; now something creeped in giving me

     ____                 _
    |  __|___ ___ ___ _ _|_|___ ___
    |  __|_ -| . |  _| | | |   | . |
    |____|___|  _|_| |___|_|_|_|___|
             |_| espruino.com
     1v99 (c) 2018 G.Williams
    >setDisplayMode:  menu
    Uncaught Error: Cannot read property 'draw' of undefined
     at line 143 col 20
               pixlmenu.draw();
                       ^
    in function "setDisplayMode" called from line 115 col 24
      setDisplayMode("menu");
                           ^
    in function "onInit" called from line 1 col 8
    onInit();
           ^
    

    (also not working if renaming pixlmenu back to "m", as I had in my code before).
    This destroys the larger menu font you helped me with yesterday.

    This being the code right now:

    var actual_menu, gatt;
    var last_wheel_event_time = 0, actual_wheel_event_time;
    var last_cumulative_wheel_revolutions = 0, actual_cumulative_wheel_revolutions = 0, track_cumulative_revolutions = 0;
    var delta_revolutions, delta_event_time, timer = -1;
    var wheel_circumference = 2340;
    var delta_time_in_ms, connected = false;
    
    Pixl._menu = Pixl.menu; //Bug Fix von Gordon, s. Forum
    Pixl.menu = function(m) { Pixl._menu(m); }; //Bug Fix
    
    function connect() {
      print("Starting scan...");
      g.clear();
      var s = "Connecting...";
      g.drawString(s ,0 ,0); g.flip();
      try {
      NRF.requestDevice({ timeout:20000, filters: [{ namePrefix: 'Wahoo' }] }).then(function(device) {
      console.log(device);
      return device.gatt.connect();
      }).then(function(gatt_object) {
        gatt = gatt_object;
        s = "Looking for service...";
        g.clear(); g.drawString(s ,0 ,0); g.flip();
        return gatt.getPrimaryService("1816");
        }).then(function(service) {
          s = "Looking for char...";
          g.clear(); g.drawString(s ,0 ,0); g.flip();
          return service.getCharacteristic("0x2A5B");
        }).then(function(characteristic) {
          characteristic.on('characteristicvaluech­anged', OnNotify);
          return characteristic.startNotifications();
          }).then(function() {
            connected = true;
            setDisplayMode("livedata");
            console.log("Done!");
            // Then call gatt.disconnect(); if/when you want to disconnect
            });
      } catch(error) {
          print("Sensor not found", error);
          g.clear(); g.drawString("No sensor found..." ,0 ,0); g.flip();
        }
    }
    
    function disconnect() {
    ...
    }
    
    function OnNotify(event) {
        ...
    }
    
    var mainmenu = {
      "" : {
        "title" : "-- Main Menu --",
        "fontHeight" : 10
      },
    
      "Connect" : function () { setDisplayMode("connecting"); },
      "Disconnect" : function () { disconnect(); },
      "Live Data" : function() {setDisplayMode("livedata"); },
      "New Track" : function () {},
      "Toggle Backlight" : function() { LED1.toggle(); },
      "-> Settings" : function () {Pixl.menu(SettingsMenu); },
      //"Exit" : function() { Pixl.menu(); },
    };
    
    var SettingsMenu = {
      "" : {
        "title" : "-- Settings --",
        "fontHeight" : 10
      },
      "Set Wheel Circumference" : undefined, // do nothing
      "Set Total Distance Counter" : undefined, // do nothing
      "< Back" : function() { Pixl.menu(mainmenu); },
    };
    
    function showLiveData() {
     
    }
    
    function onInit () {
      require("Font8x12").add(Graphics);
      setDisplayMode("menu");
      setWatch(function () { setDisplayMode("menu"); }, BTN2, {repeat:true, debounce:50});
    }
    
    function setDisplayMode(displaymode) {
     print("setDisplayMode: ", displaymode);
     switch (displaymode) {
             case "switchToConnected":
               Pixl.menu();
               break;
             case "connecting":
               if (timer!==-1) {clearInterval(timer); timer = -1;}
               Pixl.menu();
               connect();
               break;
             case "livedata":
               print("livedata");
               Pixl.menu();
               if (timer==-1) {
                 print("Set timer"); 
                 timer = setInterval( function () {showLiveData(); }, 2000); 
                 print("timer = ", timer);
               }
               break;
             case "menu":
               if (timer!==-1) {clearInterval(timer); timer = -1;}
               pixlmenu=Pixl.menu(mainmenu);
               g.setFont8x12();
               pixlmenu.draw();
               }
    }
    
    onInit();
    
    
  • in Puck.js, Pixl.js and MDBT42
    Avatar for Joost

    Thanks for your answer!

    Here is the complete code:

    var actual_menu, gatt;
    var last_wheel_event_time = 0, actual_wheel_event_time;
    var last_cumulative_wheel_revolutions = 0, actual_cumulative_wheel_revolutions = 0, track_cumulative_revolutions = 0;
    var delta_revolutions, delta_event_time, timer = -1;
    var wheel_circumference = 2340;
    var delta_time_in_ms, connected = false;
    
    function connect() {
      print("Starting scan...");
      g.clear();
      var s = "Connecting...";
      g.drawString(s ,0 ,0); g.flip();
      try {
      NRF.requestDevice({ timeout:20000, filters: [{ namePrefix: 'Wahoo' }] }).then(function(device) {
      console.log(device);
      return device.gatt.connect();
      }).then(function(gatt_object) {
        gatt = gatt_object;
        s = "Looking for service...";
        g.clear(); g.drawString(s ,0 ,0); g.flip();
        return gatt.getPrimaryService("1816");
        }).then(function(service) {
          s = "Looking for char...";
          g.clear(); g.drawString(s ,0 ,0); g.flip();
          return service.getCharacteristic("0x2A5B");
        }).then(function(characteristic) {
          characteristic.on('characteristicvaluech­anged', OnNotify);
          return characteristic.startNotifications();
          }).then(function() {
            connected = true;
            setDisplayMode("livedata");
            console.log("Done!");
            // Then call gatt.disconnect(); if/when you want to disconnect
            });
      } catch(error) {
          print("Sensor not found", error);
          g.clear(); g.drawString("No sensor found..." ,0 ,0); g.flip();
        }
    }
    
    function disconnect() {
      if (gatt) {
          gatt.disconnect();
      }
      connected = false;
      print("Connected: ", connected);
      setDisplayMode("menu");
    }
    
    function OnNotify(event) {
        //console.log("-> "+(event.target.value.getUint8(0, true)>>> 0).toString(2)); //characteristics flags
        actual_cumulative_wheel_revolutions = event.target.value.getUint32(1, true);
        actual_wheel_event_time = event.target.value.getUint16(5, true);
        //console.log("Cumulative wheel Revolutions: " + actual_cumulative_wheel_revolutions);
        //console.log("Last Wheel Event time: "+ actual_wheel_event_time + " ms");
        delta_revolutions = actual_cumulative_wheel_revolutions - last_cumulative_wheel_revolutions;
        //console.log("-> "+event.target.value.getUint16(7, true)); //crank
        //console.log("-> "+event.target.value.getUint16(9, true)); //crank
        if (actual_wheel_event_time >= last_wheel_event_time) {
                    delta_event_time = actual_wheel_event_time - last_wheel_event_time;
            } else {
                    delta_event_time = 65536 - last_wheel_event_time + actual_wheel_event_time;
                }
        delta_time_in_ms =(delta_event_time / 1.024);
        //console.log("delta_time_in_ms:" + delta_time_in_ms);
        last_wheel_event_time = actual_wheel_event_time;
        last_cumulative_wheel_revolutions = actual_cumulative_wheel_revolutions;
        track_cumulative_revolutions += delta_revolutions;
    }
    
    var mainmenu = {
      "" : {
        "title" : "-- Main Menu --",
        "fontHeight" : 10
      },
    
      "Connect" : function () { setDisplayMode("connecting"); },
      "Disconnect" : function () { disconnect(); },
      "Live Data" : function() {setDisplayMode("livedata"); },
      "New Track" : function () {},
      "Toggle Backlight" : function() { LED1.toggle(); },
      "-> Settings" : function () {Pixl.menu(SettingsMenu); },
      //"Exit" : function() { Pixl.menu(); },
    };
    
    var SettingsMenu = {
      "" : {
        "title" : "-- Settings --",
        "fontHeight" : 10
      },
      "Set Wheel Circumference" : undefined, // do nothing
      "Set Total Distance Counter" : undefined, // do nothing
      "< Back" : function() { Pixl.menu(mainmenu); },
    };
    
    function showLiveData() {
      //print("showlivedata");
      g.clear();
      var s = "Cum. Wheel Revolutions: ";
      g.drawString(s ,0 ,0); //95 - g.stringWidth(s) g.getWidth()
      g.drawString(actual_cumulative_wheel_rev­olutions, 0, 11);
      var speed = delta_revolutions * wheel_circumference / delta_time_in_ms * 60 * 60 / 1000;
      s = "Speed: " + String(speed.toFixed(2));
      g.drawString(s, 0, 22);
      s = "Track distance: " + (track_cumulative_revolutions * wheel_circumference / 1000 / 1000).toFixed(2);
      g.drawString(s, 0, 33);
      g.flip();
    }
    
    function onInit () {
      require("Font8x12").add(Graphics);
      setDisplayMode("menu");
      setWatch(function () { setDisplayMode("menu"); }, BTN2, {repeat:true, debounce:50});
    }
    
    function setDisplayMode(displaymode) {
     print("setDisplayMode: ", displaymode);
     switch (displaymode) {
             case "switchToConnected":
               Pixl.menu();
               break;
             case "connecting":
               if (timer!==-1) {clearInterval(timer); timer = -1;}
               Pixl.menu();
               setTimeout(function() {connect();},1);
               break;
             case "livedata":
               print("livedata");
               Pixl.menu();
               if (timer==-1) {
                 print("Set timer"); 
                 timer = setInterval( function () {showLiveData(); }, 2000); 
                 print("timer = ", timer);
               }
               break;
             case "menu":
               if (timer!==-1) {clearInterval(timer); timer = -1;}
               m=Pixl.menu(mainmenu);
               g.setFont8x12();
               m.draw();
               }
    }
    
    onInit();
    
    

    Though sadly your idea with

    setTimeout(connect, 1);

    did not work out; returning the same error. Thanks again!

Actions