IR help

Posted on
  • I'm trying to get the IR timings from a Remote and play them back using Puck.IR

    I got the correct times from a website and they work using Puck.IR but I cannot get the correct timings using times recorded from a connected IR Receiver, I have a few different IR receivers and they all give more or less the same result - firmware was 1.89 and also tested with the new beta 1.89.35

    I've been using the examples given on the site, 1 issue i've noticed is when using this snippet

    var times =[];
    var currentWatch;
    function startWatching() {  
      currentWatch = setWatch(function(e) {
        var pulseLen = (e.time - e.lastTime);
        if (pulseLen < 1000) {
        } else {
          times = [];  
      }, D1, {repeat:true});
    function stopWatching() {
      currentWatch = null;

    The times given back are to max 3 decimal places e.g. [ 0.009, 0.004, 0.001, 0, 0.001, 0.001, 0, 0.002, 0, ... Is this expected behavior from e.time and e.lastTime? It's not really accurate enough for this.

    I set up my own timers using the onPulseOn and OnPulseOff examples (­+Control) and get better accuracy, however these still do not work when played back and are quite a bit different to the ones i got off the website

    Website times (ms): 9.024 ,4.512 ,0.564 ,0.564 ,0.564 ,0.564 ,0.564 ,1.692 ,0.564

    Puck recorded times (ms): 8.9993, 4.57763671875, 0.9765625, 1.06811523437, 0.94604492187, 1.0986328125, 0.91552734375, 1.12915039062, 0.91552734375

    Any help would be appreciated

  • Things that are already time critical become even more so when handled interpretatively, as Espruino - to be precise: the JavaScript part of Espruino - is doing, even though events are queued to not slow down the catching and registering of them. In addition to that, for replay the pauses between the pulses matter as well and have to be considered (I do not know what the example does).

    My stab at this would be to just record the times in the loop and do all math afterwards... To prep the values for replay, you may even adjust them for the execution time used by Espruino.

    I have no feeling for the actual figures / numbers, I'm just thinking through what happens... and all needs time, and since you expect actually an over-all accuracy of 4 digits, 1 millisecond matters...

    var rTs = []; // raw times
    var times = []; // calculated from raw times
    var recordingWatch;
    function startRecording() {
      rTs = []; 
      recordingWatch = setWatch(function(e) {
      }, D1, { repeat: true, edge: "both", debounce: 0 });
    function stopRecording() {
      currentWatch = null;
    // times[] array will include calculates the pulse on and off times
    // even-indexed values are on-times,  odd-indexed ones are off-times
    function calculateTimes() {
      var tCurrent, tLast; // t-current and t-Last
      times = [];
      rTs.forEach(function(e, idx){
          if (idx === 1) {
             tLast = e.time;
          } else {
             times.push((tCurrent = e.time) - tLast);
             tLast = tCurrent;

    Sequence of events are:

    1. upload code
    2. connect wires to remote
    3. console command startRecording()
    4. perform command on remote
    5. console command stopRecording()
    6. console command calculateTimes()
    7. console.command console.log(times) to show the calculated times

    Do you see any difference?

  • At IR frequencies, what @MattC has done should really be fine. It's interesting that the first few things are spot on and it's the later ones that are off though.

    You could check that E.getErrorFlags() is [] - just on the offchance that the input buffer got overflowed.

    The timings are only recorded on Puck.js using the RTC - which runs at 32kHz - so you don't get super-accurate, but it should be enough for IR. The Espruino boards use the internal high-speed oscillator and measure to 1MHz, but on the Puck I've had to try and aim more for minimum power usage.

    I was actually planning on doing a video on this today, so I'll have a poke around and see if something's not working right.

    It's also possible that you're just not recording the right signal - I've found that IR remote controls also send different codes - like a Volume up key might send a 'volume up' command followed by what looks like a much shorter 'repeat' command if you hold the button down.

    If you wanted a second opinion it's relatively easy to wire the receiver up with a battery and to then connect it to your PC's line in/mic jack. You can then use some audio recorder software like audacity to analyse the signal you're getting.

  • Thanks for the replies.

    After my initial post I tried something similar to what @allObjects is suggesting:

    var rawtimes = [];
    var calculatedTimes = [];
    function onPulseOn(e) { 
    function onPulseOff(e) {
    setWatch(onPulseOff, D1, { repeat:true, edge:"rising" });
    setWatch(onPulseOn, D1, { repeat:true, edge:"falling" });
    setWatch(function(e) { 
      // if we have timings
      if (rawtimes.length > 0)
        calculatedTimes = [];
        var lasttime = 0;
        rawtimes.forEach(function(rawTime) {  
          if(lasttime != 0)
            var newTime = 1000 * (rawTime - lasttime);
          lasttime = rawTime;
       //send to IR
       calculatedTimes = [];  
    }, BTN, { repeat: true, edge: 'rising', debounce: 50 });

    This gets me close to what I'm expecting but still does not perform the function when replayed via the puck ir. I believe the tolerance for IR signals is +-10% which some of my recorded times fall out of.

    Here's the a snippet my new recorded times:
    [ 8.972, 4.547, 0.61, 0.763, 0.61, 0.763, 0.579, 1.19, 0.61, ...

    Correct working times are:
    [ 9.024 ,4.512 ,0.564 ,0.564 ,0.564 ,0.564 ,0.564 ,1.692, 0.564, ...

    So the pattern seems to be there. I wonder if it's due to the reading at 32kHz?

    I'll try @allObjects code out tonight see if I get any closer.

    Also @Gordon is it correct that with the code below e.time and e.lastTime are rounded to 3 decimal places or is this a bug/limitation?

    setWatch(function(e) {    
        var pulseLen = (e.time - e.lastTime);

    I look forward to your video on this :)

  • is it correct that with the code below e.time and e.lastTime are rounded to 3 decimal places

    It could just be the way they are converted to strings more than anything else. It's actually surprisingly hard to come up with a good set of rules for outputting floating point numbers as strings without doing things like accidentally outputting 0.999999 instead of 1.

    I should look at using the C library functions again - when I started the library functions pulled in loads of extra code and memory usage so I had to write my own, but the situation may have improved now.

    I guess if you multiply by 1000 you find you've got all the information there.

  • The esp32 idf stuff is using newlib would that be useful?

  • That's what I'm now using (I changed from using the original Math library a while back). JavaScript does have some interesting differences from the C implementation though (eg NaN and Infinity handling), so I'd have to be careful to only use it in the right circumstances - and also careful that it wasn't one of the functions that uses malloc for no good reason - it's not as easy as a simple swap.

  • @MattC you're totally right - there's something wrong with setWatch and it's not reporting times accurately enough (it's not anything to do with converting numbers to strings, so ignore my last comments).

    As @allObjects said, when using getTime you're not going to be as accurate, and that won't be helping. I'll see what I can do in the firmware and I'll let you know.

  • Fixed it - if you try uploading the attached firmware then it should work.

    Sorry about that - turns out it was a simple error in the code that converts system time to milliseconds that must have been left over from the initial port.

    When I did the Puck demo I actually used an Espruino Pico to record the remote because it was easier to do on breadboard :)

    I'll release a 1v90 version today sometime that should have that fix in

    1 Attachment

  • Excellent thanks @Gordon, I shall test it out this evening :)

  • I can confirm the new firmware fixes the issue :)

    The puck can now replay the IR pulses perfectly

    Code below if anyone is interested

    var times = [];
    var currentWatch;
    function startWatching() {
      currentWatch = setWatch(function(e) {
        // work out how long the pulse was, in milliseconds
        var pulseLen = 1000 * (e.time - e.lastTime);
        // then save it, if it was less than 1 second
        if (pulseLen < 1000) {
        } else {
          times = [];
      }, D1, {repeat:true});
    function stopWatching() {
      currentWatch = null;
    setWatch(function(e) {
    }, BTN, { repeat: true, edge: 'rising', debounce: 50 });

    Thanks for your help.

  • Great, thanks for letting me know!

    I also did a video about it on Friday:­

  • Thanks for the video, i will check it out later :)

    My next issue is the limited range of the IR led. I'm getting approx 50cm range with the on-board IR led any way of boosting this?
    I can get about 2m with an external IR led (taken from a tv remote) which is better but I need it closer to 4m. I was going to try a transistor unless you have any better suggestions?

  • To be honest it looks like you've basically done what's in the video anyway, but I guess the Web Bluetooth side might be interesting :)

    Yes, the range isn't great, especially if it's through silicone - it was only meant to be something you'd stick pretty near to the receiver.

    You could attempt to short out the SMD resistor near the IR transmitter - it shouldn't be a big problem when used for short periods of time.

    But otherwise yes, a transistor would work well (Puck.js uses both sides of the LED though - it uses the diode bit of the LED to 'gate' the 40kHz carrier, so you might want to be careful).

    Chances are that you'll find that you can't get much more current out of the CR2032 battery though, so you might need to move to something that'll supply a bit more power.

  • Hi Matt,

    I'm also having trouble with the limited range of the IR led. But the 2 meters you achieved with an external IR led are enough for me. Can you give some more detail of what you've done. You just took the IR led from a remote and inserted directly? On which pins? How do you call it? Just Puck.IR()?


  • Wed 2019.12.18

    Hello @user106855 it is unlikely that Matt would respond as activity in the forum ended (right click on his name to view profile) in August of 2017 and this thread is three years old.

    There have been many firmware updates since, along with several tutorial examples and of course there are the many implementations with different discreet device types. The setup in question is too vague to start to offer ideas at this point.

    My suggestion would be to start a unique new thread, with a title you own, laying out the design requirement. Post the links to the tutorial(s) being used, the datasheet of the discreet device and/or upload images of the setup currently in use. Others will be able to quickly offer their assistance.

    While waiting your thread, peruse the forum by typing ir into the forum search field, and also into the main web site page search field. You may find ideas there, as their are ten to twenty examples in each.

    I have many observations I have seen over the years that I shall add to that original thread.

  • Hi Robin,

    I had noticed that the thread was really old but it was the one which was closely related to my goal.
    I've managed to use an external IR LED anyway. The procedure is actually quite simple. Unfortunately I couldn't extend the range any further, probably I used a poor quality LED.
    Maybe I'll try using another one. Can you recommend a good IR LED (long range and wide angle) for the puck?

  • I did this so long ago i can't remember what i did, sorry not very helpful i know.

    Looking through my emails i did purchase these IR Led's from ebay so maybe worth a try­5-880nM-40-degree-IR-LEDs-Qty-5-NEW-Osra­m-parts/112424821596

  • Just to add that newer firmwares (I can't remember which ones, but it was a year or so ago) managed to increase IR output range.

    But if you use an external IR LED then you can just use Puck.IR with the pins you used specified as arguments. Details are in the function reference at­_IR

  • Even with the firmware updates and an external IR LED I couldn't achieve the 2 meters. It was close but it is very directional, you have to very precisely point (much more than a TV remote) to the IR receiver otherwise it won't work. Additionally the external IR LED makes it more difficult to press the button. I'm a little bit disappointed, I'll have to think of another use for the puck.js.

  • Wed 2020.01.08

    'I'm a little bit disappointed'

    As an observer, it appears your frustration @user106855 is premature.

    From posts #15, #17 and #20 please follow along as an outside viewer of this progress

    To we readers, we have been able to determine you are working with an IR type LED and using it with a Puck. Upon one recomendation, updated firmware has been attempted.

    and, . . . that's it.

    Back in post #16 three weeks ago, in order to get a better understanding of what the goal was and was attempted, I requested the following:

    Start a new thread post please as the responses most likely will get long winded, and,

    'Post the links to the tutorial(s) being used, the datasheet of the discreet device and/or upload images of the setup currently in use.'

    There are so many combinations and possibilities, that without that detail, all we are able to assist with is to just plain guess, and that won't solve the issue at hand.

    Things to consider, TV remotes typically have three or five transmit LED's and fixed with a slight ~10 degree angle, so as not to be directional. Are we working with a basic on/off detection or a pulse train? Has the use of a cell phone camera been used to view the transmit LED? (not 100% sure the recent smart phone cameras work this way, but I have an older 2G 'Flip phone' which when pointed at the transmit LED super saturates the vieweable image. This works as a great distance estimator) Do you have access to a voltmeter and scope? What is the knowledge background, from the physics side of things for light, the magnetic spectrum and the application of a bit of math for luminance, power disipation etc? What tid-bits does the datasheet provide?

    FYI, with one type of setup, I've gotten fifteen feet, with multiple transmit LED's and within a room whose walls are all white. The reflective nature of this paint maybe, assists here as I'm even able to bounce the signal off the wall!

    So you can see there are too many variables without the much needed requested detail.

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

IR help

Posted by Avatar for MattC @MattC