AWOX smart bulb tutorial - NRF ERROR 0x8 at ?:0

Posted on
  • Hi,

    I tried the code on the puck.js to be able to turn the AWOX smart light bulb on and off. After a few switches, a message pops up on my control with the following:

    NRF ERROR 0x8 at ?:0

    As soon as this message pops up, the puck lights up all 3 leds once, red flashes once and it goes dead until I reset it by holding the button and reinserting the battery.

    I have tried my own code to be able to detect light and depending on light levels, it switches the bulb on or off; ideal if you have a pet at home and no one is home :) So I tried the basic code tutorial and I get the same problem. My puck.js has been updated with the latest firmware a few weeks ago.

    I also get unhandled promise rejections which I can't catch using try catch blocks.

    Any ideas about these issues?

  • So it's literally just with this code:

    function setLight(isOn) {
      var gatt;
      NRF.connect("98:7b:f3:61:1c:22").then(fu­nction(g) {
        //         ^^^^^^^^^^^^^^^^^  your light's address here
        gatt = g;
        return gatt.getPrimaryService("33160fb9-5b27-4e­70-b0f8-ff411e3ae078");
      }).then(function(service) {
        return service.getCharacteristic("217887f8-0af2­-4002-9c05-24c9ecf71600");
      }).then(function(characteristic) {
        characteristic.writeValue(isOn ? 1 : 0);
      }).then(function() {
        gatt.disconnect();
        console.log("Done!");
      });
    }
    
    var on = false;
    setWatch(function() {
      on = !on;
      setLight(on);
    }, BTN, { repeat:true, edge:"rising", debounce:50 });
    

    that you're having problems? Is it anything particular that you do that causes the error?

    To catch a promise rejection, just do:

    ....then(function() {
      // .....
    }).catch(function(error) {
       // here
    });
    

    you can't catch them with a try...catch block because the function will have already finished executing by the time the error occurs.

    The majority of errors will probably be because you're pressing the button quickly enough that the Puck won't have finished the last connection before the latest request to connect comes in?

  • Hi Gordon,

    Thanks for the reply. I attach the code I am using using the light sensor and button sensor to result variables and switch the light to an off state. It might be that when len is too short as defined in the setInterval function, it kicks up the NRF error. I have tried longer len times and it resulted in crashes after several hours testing it.

    E.setBootCode();
    let downTime = undefined;
    let allowPush = true;
    let on = false;
    let len = 5000;
    let autoSense = true;
    let flag = false;
    function setLed(led, duration, callback) {
      if (duration === undefined) {
        duration = 10;
      }
    
      digitalPulse(led, 1,[duration]);
    
      setTimeout(function(){
        digitalWrite(led, false);
        if (callback) {
          callback();
        }
      }, duration);
    }
    
    function isDay(){
      var l=0;
      try{
        l = Puck.light();
      }catch(e)
      {
        console.log("Problem with light sensor: "+e);
      }
      if(l > 0.4)
      {
          return true;
      }
      return false;
    }
    
    function alert(led, onDuration, gap) {
      if (onDuration === undefined) {
        onDuration = 50;
      }
    
      if (gap === undefined) {
        gap = 100;
      }
    
      setLed(led, onDuration);
      setTimeout(function(){ setLed(led, onDuration); }, gap);
      setTimeout(function(){ setLed(led, onDuration); allowPush = true; }, gap * 2);
    }
    
    function onUp() {
      const delta = Date().ms - downTime;
      if (delta > 750 && delta < 5000) {
       // toggleBeacon();
        alert(LED1);
        alert(LED2);
        alert(LED3);
        autoSense=true; 
        changeInterval(1,len);
        flag=false;
        setLight(false);
      } else {
        alert(LED2);
      }
    }
    
    function onDown() {
      if (allowPush) {
        allowPush = false;
        downTime = Date().ms;
        autoSense=false; 
        setWatch(onUp, BTN, { edge: 'falling', debounce: 50 });
      }
    }
    function setLight(isOn) {
      var gatt;
      try{
        NRF.connect("98:7b:f3:67:75:33").then(fu­nction(g) {
          gatt = g;
          return gatt.getPrimaryService("33160fb9-5b27-4e­70-b0f8-ff411e3ae078");
        }).then(function(service) {
          return service.getCharacteristic("217887f8-0af2­-4002-9c05-24c9ecf71600");
        }).then(function(characteristic) {
    characteristic.writeValue(isOn);
        }).then(function(){
          gatt.disconnect();
          console.log("Done!");
        });
        flag=isOn;
      }
        catch(e)
        {
          console.log("Problem: "+e);
        }
    }
    
    setWatch(function() {
      onDown();
    }, BTN, { repeat:true, edge:"rising", debounce:50 });
    
    
    setInterval( function()
      {
         try{
          console.log("Looping"); 
          if(autoSense)
          {
            if(!isDay() && !flag)
            {
              setLight(true);
              digitalPulse(LED1,1,50,200,50,200,50);
              console.log("I see darkness - switching on!");
            }
            else{
              if(flag && isDay()){
               setLight(false);
               digitalPulse(LED3,1,50,200,50,200,50);
               console.log("I see light - switching off!");
              }
            }
            changeInterval(1,60000);
          }
         }catch(e){console.log("Problem in Interval: " + e);}
       }
     ,len);
    

    I also added the catch after when writing to the smart bulb and it didn't catch it; the NRF error crept up and crashed the whole thing.

  • It seems you're doing:

    try {
     ...
    } catch (e) {
      ..
    }
    

    but what you need to do to catch promises (like the one in setLight) is:

    ....then(function() {
      // .....
    }).catch(function(error) {
       // here
    });
    

    So not the usual try...catch - it's a bit weird, but it's just the way you have to handle stuff with JS promises.

    While you can catch other errors, unfortunately that NRF Error won't be catchable - it's right from the lower levels of the hardware.

    To me, it looks like you're not doing any checks to see whether you're in the middle of doing something with Bluetooth - so quite likely what'll happen is it'll turn on the light, get too bright, and try and turn itself off - which could happen while Puck.js is trying to disconnect, which could really mess things up?

    Could you try replacing setLight with this?

    var isBusy = false;
    function setLight(isOn) {
      var gatt;
      if (isBusy) throw new Error("Busy!");
      isBusy = true;
      NRF.connect("98:7b:f3:67:75:33").then(fu­nction(g) {
        gatt = g;
        return gatt.getPrimaryService("33160fb9-5b27-4e­70-b0f8-ff411e3ae078");
      }).then(function(service) {
        return service.getCharacteristic("217887f8-0af2­-4002-9c05-24c9ecf71600");
      }).then(function(characteristic) {
        characteristic.writeValue(isOn);
      }).then(function(){
        gatt.disconnect();
        console.log("Done!");
        isBusy = false;
      }).catch(function(e) {
        console.log("Problem: "+e);
        if (gatt) gatt.disconnect();
        isBusy = false;
      });
    }
    
    

    It might help, as it'll refuse to do anything else if it's already in the middle of controlling the light.

  • Hi Gordon,

    I'll give this new code block a try.

    Cheers.

  • I've been looking in to this and I've found a few issues in Espruino that could be causing this. Hopefully I'll have a new version for you soon with it fixed.

    The main issue seems to be really bad timing inside the Bluetooth stack - occasionally you can disconnect, and then the stack will ask Espruino to do something which isn't possible because the device has disconnected!

  • If you update with the puck.js firmware zip from here: http://www.espruino.com/binaries/travis/­47df0cf7e15453bc2485c2d6a9f1756a1de072d4­/

    Then things should be a huge amount better - however there are still some niggling issues I'd like to fix to do with the connection sometimes failing if your code is really busy.

  • Gordon,

    Cheers for this, I have updated my puck and will give this a go. I'll let you know of any progress.

  • Hi Gordon,

    I have tested this over the few days and what I observed is that if there is a timeout error which is caught (sometimes weirdly it doesn't get caught) it will get into a busy state and nothing will happen. What I have to do (manually) is switch the light bulb off from the mains and then back on again and it will resume operation.

  • Thanks! I think that's what I was finding as well. It's actually connected ok, but it failed to tell the rest of the code so is stuck in a connected state but isn't able to disconnect.

    Please could you try a build from here:

    http://www.espruino.com/binaries/travis/­e8ceb5c61bd145e7a74e92a620f4af1cbb96dd78­/

    I think I finally fixed it this morning - at least it seems a lot better for me now.

  • HI Gordon,

    So far, so good - the behaviour is much more stable, but I'm getting an "Out of memory while appending to array" warning as the interval keeps checking for light levels. Is there a way of doing this in JS or is it C level malloc stuff?

  • That's odd - are you sure you're just running that code above and not doing anything else, like scanning for advertisements or checking for light levels really really quickly?

    I'm pretty sure the error happens in this case when the code running in the interrupt is trying to allocate memory, but it can't because Espruino is in the middle of garbage collecting - but generally Espruino garbage collects very rarely and doesn't take long. The only way I could force errors when testing was to run code every few milliseconds, while also connecting.

    I don't think it should actually be that big a deal as it'll be trying to update the GattServer object, which you're not interested in - does it keep working regardless?

  • It's only doing this task, so no advertisement. It's weird. I ran it again, and I don't get it anymore.

    As a precaution, I have set the interval to be 30 seconds. I'll let you know if it kicks up a fuss :)

  • Ok, great! It's something I'm planning on fixing eventually, but it's quite a difficult problem to work around.

  • I can definitely sympathise with you :)

    My code so far is not terribly very clean; there are opportunities to refactor some functions to make it cleaner. Once it's squeaky clean and behaves as it should, I'll post it here.

  • I had a try with some code with an interval of 30 seconds and coded some behaviour that allows some light tolerance so that it does not change back and forth all the time. I noticed that sensing light has some variance and this can cause issues. One odd behaviour I notice from the Puck is that when viewing console output after some time, console looping stops and I need to reconnect again to the puck. Although I find that what works well is to switch the AWOX bulb off and then back on. Is this a sync issue?

    Ill copy my code so far here with some refactoring done.

    E.setBootCode();
    var downTime;
    var allowPush = true;
    var on = false;
    var len =30000;
    var autoSense = true;
    var flag = false;
    var isBusy = false;
    var brightness = 5;
    var toggleT = 0,toggleC = 0;
    //k->v pairs service to char
    var bulbBrightness = ["fff6fe25-469d-42bc-9179-b3a093f19032",­"d8da934c-3d8f-4bdf-9230-f61295b69570"];­ 
    var bulbtemp = ["fff6fe25-469d-42bc-9179-b3a093f19032",­"5b430c99-cb06-4c66-be2c-b538acfd1961"];­
    var bulbIO = ["33160fb9-5b27-4e70-b0f8-ff411e3ae078",­"217887f8-0af2-4002-9c05-24c9ecf71600"];­
    var bulbRGB = ["b882e31b-5096-43d1-90a9-edbf95073337",­"74532143-fff1-460d-8e8a-370f934d40be"];­
    function setLed(led, duration, callback) {
      if (duration === undefined) {
        duration = 10;
      }
      digitalPulse(led, 1,[duration]);
      setTimeout(function(){
        digitalWrite(led, false);
        if (callback) {
          callback();
        }
      }, duration);
    }
    
    function alert(led, onDuration, gap) {
      if (onDuration === undefined) {
        onDuration = 50;
      }
      if (gap === undefined) {
        gap = 100;
      }
    
      setLed(led, onDuration);
      setTimeout(function(){ setLed(led, onDuration); }, gap);
      setTimeout(function(){ setLed(led, onDuration); allowPush = true; }, gap * 2);
    }
    
    function onUp() {
      const delta = Date().ms - downTime;
      if (delta > 750 && delta < 5000) {
       toggle++;
        if(toggle==4){toggle=0;}
        if(toggle==0){colour = 0;}
        if(toggle==1){colour = 25;}
        if(toggle==2){colour = 75;}
        if(toggle==3){colour = 127;}
        alert(LED1);
        alert(LED2);
        alert(LED3);
        autoSense=true; 
        changeInterval(1,len);
        flag=false;
        setBulb(bulbtemp,colour);
        console.log("Press up");
      } else {
        alert(LED2);
      }
    }
    
    function onDown() {
      if (allowPush) {
        allowPush = false;
        downTime = Date().ms;
        autoSense=false; 
        isBusy=false;
        toggleC++;
        if(toggleC==5){toggle=0;}
        if(toggleC==0){rgb = "00-08-08";}
        if(toggleC==1){rgb = "FF-00-00";}
        if(toggleC==2){rgb = "00-FF-00";}
        if(toggleC==3){rgb = "00-00-FF";}
        if(toggleC==4){rgb = "00-00-00";}    
        setBulb(bulbRGB,rgb);
        setWatch(onUp, BTN, { edge: 'falling', debounce: 50 });
      }
    }
    function setBulb(service,val){
        var gatt;
      var ser = service[0];
      var ch = service[1];
      
    if (isBusy) throw new Error("Busy!");
                    isBusy = true;               NRF.connect("98:7b:f3:67:75:33").then(fu­nction(g) {
                      gatt = g;
                      return gatt.getPrimaryService(ser);
                    }).then(function(service) {
                      return service.getCharacteristic(ch);
                    }).then(function(characteristic) {
                          characteristic.writeValue(val);
                    }).then(function(){
                      gatt.disconnect();
                      console.log("Done in setting temp!");
                      isBusy = false; 
                    }).catch(function(e) {
                      console.log("Problem in setting colour temp: "+e);
                      if (gatt) gatt.disconnect();
                      isBusy = false;
                    });
    }
    setWatch(function() {
      onDown();
    }, BTN, { repeat:true, edge:"rising", debounce:50 });
    
    setInterval( function()
    {
    var noLight=true;
    var threshold = 0.35;
    var li=0.0,liUp=0.0,liLow=1.0,avg=0.0;
      for(i=0;i < 10;i++)
      {
        li = Puck.light();
        console.log(li);
        if(liUp < li){liUp = li;}
        if(liLow > li){liLow = li;}
        avg += parseFloat(li);
      }
        li = avg / 10;
        console.log((liLow) + " " + li + " " +(liUp));
        console.log(autoSense);
        noLight = (liUp < threshold);
          if(autoSense)
          {
            if(!flag)
            {
              setBulb(bulbIO,true);
              console.log("I see darkness - switching on!");
              digitalPulse(LED1,1,50,200,50,200,50);
              flag=true;
            }
            else
            {
              if(noLight)
              {
                 if(brightness <= 127)
                  {
                    console.log("Increasing brightness");
                    brightness++;
                    digitalPulse(LED2,50,1);
                    setBulb(bulbBrightness,brightness);
                  }
              }
              else
              {
                 if(brightness > 0 && brightness <= 127)
                 {
                     console.log("Reducing brightness");
                        brightness--;
                        digitalPulse(LED2,50,1);
                        setBulb(bulbBrightness,brightness);
                 }
              }
            }
          }
       }
     ,len);
    
  • What do you mean by 'console looping'? Just printing data to the console?

    When it's not printing anything, is it still working correctly?

  • Hi Gordon,

    I have a piece of code with a for loop (loops only 10 times to get lower, avg and upper bounds of light) inside an interval that outputs to the console - see print screen. It keeps working if it's not printing anything, but sometimes I need to either re-upload or switch off the bulb and then back on. You can also see that there is also a promise that wasn't caught which should have been already caught.


    1 Attachment

    • espruino_output.png
  • Update: after it disconnects on its own, I get the 3 LEDs of death followed by the red LED flashing once.

  • It keeps working if it's not printing anything, but sometimes I need to either re-upload or switch off the bulb and then back on.

    So you need to re-upload/switch the bulb off eventually if it's printing - but it's absolutely fine if you remove the console.log?

    What if you leave the prints in, but then disconnect your PC from the Puck? Does it still stay working ok?

    Also, for the unhandled promise, can you try changing characteristic.writeValue(val); to return characteristic.writeValue(val);? I think that'll be the problem - looks like all Espruino's docs need updating as none of them mentioned that.

  • Also, for the unhandled promise, can you try changing characteristic.writeValue(val); to return ?characteristic.writeValue(val);? I think that'll be the problem - looks like all Espruino's docs need updating as none of them mentioned that.

    I'll give it a try and update.

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

AWOX smart bulb tutorial - NRF ERROR 0x8 at ?:0

Posted by Avatar for Joe @Joe

Actions