• I've recreated and adapted the Smart meter tutorial. What I've noticed is, after I upload the code to the Puck, it watches the flashes correctly and will continue until I connect from the web page. From that moment on, it is as if the watch on the pin is removed. The Puck no longer flashes when the electric meter flashes, and there are no further records of the flashes. The variables stored in the Puck remain and are not reset, it seems it is just the watch method which has an issue after connection from the web page.

    I'm not sure how to debug this issue. The only place clearWatch() is called is in the onInit() function on the Puck. The connection code from the web page seems simple, and I cannot see anywhere there that might clear the watch. Any ideas on how I can further debug this issue?

    Here is the code from the website connection script (I don't call any Puck functions anywhere else apart from here):

    function connectDevice() {
        const button = document.getElementById('connect-button'­)
    
        // Disable connect button
        button.disabled = true
        button.textContent = 'Connecting...'
    
        // Connect, issue Ctrl-C to clear out any data that might have been left in REPL
        Puck.write("\x03", function () {
            setTimeout(function () {
                // After a short delay ask for the battery percentage
                Puck.eval('E.getBattery()', function (batteryPercentage) {
                    if (!batteryPercentage) {
                        console.log('Battery error:')
                        button.textContent = 'Failed to connect'
                        return
                    }
    
                    button.textContent = 'Connected'
    
                    // Update battery meter
                    const batteryEl = document.getElementById('battery-contain­er')
                    batteryEl.textContent = `Battery: ${batteryPercentage}%`
    
                    document.documentElement.classList.remov­e('not-connected')
    
                    Puck.eval('years', function (years) {
                        // Ensure a valid array is returned
                        if (typeof years !== 'object' || years.length < 20) {
                            return
                        }
    
                        console.log(years)
                        window.usageData = years
                    });
    
                    Puck.eval('currentkWh', function (currentkWh) {
                        window.currentkWh = currentkWh
                    })
                })
            }, 1000 * 1);
        });
    }
    
  • Just a guess: do you use print or console.log? Maybe this one in the troubleshooting My code works when I'm connected via Bluetooth but stops when I disconnect

    Or do you use any other library that might contain a clearWatch?

  • Thanks. I don't print or log anything on the Puck itself, there's no libs used and the only code that interacts with the Puck from the web page is that shown above. I tried the possible fix from the link, but the issue still persists.

    It doesn't always stop working on the first connect from the web page, but usually by the second or third time it's stopped.

  • Can you post your code for the Puck up since it sounds like you've modified the code on it a bit?

    What happens if you use the unmodified original code for the tutorial? Does that work? I'm using it here and it's been running for a month or more just fine.

    One thing that could be an issue is you're calling Puck.eval twice one after the other. Usually you should nest the calls, so that one is called after the other one completes (because it's asynchronous) but you'll be sending currentkWh before the first has completed. I seem to recall the Puck library tries to account for this but I can't be 100% sure.

  • Just to add: the setWatch could still be there - you can type dump() when connected in the IDE and see if a setWatch is reported.

    One option is that you may be getting an error before the watch completes. For example:

    var x = 0;
    setWatch(function() {
     x++;
    ...
    },...);
    

    works fine, but if you'd called delete x then x++ would create an error and stop execution.

  • You're correct that the original code did work without issue. Thanks for the suggestion about nesting Puck.eval. I've now implemented that, but the issue has occurred again. Not sure if it's related, but it seemed to stop watching the flashes after I received gattserverdisconnected error (although I haven't noticed that happen before in relation to it stopping working).

    The current Puck code is as follows:

    const years = []
    let lastFlashTime = Date.now()
    let currentkWh = 0
    
    
    /**
     * Get the last 2 digits of full year
     * @param {number} year Year to parse
     * @return {number}
     */
    function getYear(year) {
        return parseInt(year.toString().substr(-2))
    }
    
    /**
     * Increment count, create new year, month, date, hour as needed
     */
    function increment() {
        const d = new Date()
        const hour = d.getHours()
        const date = d.getDate()
        const month = d.getMonth()
        const year = d.getFullYear()
    
        // 2-digit year, as number
        const yr = getYear(year)
    
        if (years[yr]) {
            if (years[yr][month]) {
                if (years[yr][month][date]) {
                    if (years[yr][month][date][hour]) {
                        years[yr][month][date][hour]++
                    } else {
                        // No hour in current date
                        years[yr][month][date][hour] = 1
                    }
                } else {
                    // No date in current month
                    years[yr][month][date] = new Uint16Array(24)
                    years[yr][month][date][hour] = 1
                }
            } else {
                // No month in current year
                years[yr][month] = []
                years[yr][month][date] = new Uint16Array(24)
                years[yr][month][date][hour] = 1
            }
        } else {
            // Current year not yet created
            years[yr] = []
            years[yr][month] = []
            years[yr][month][date] = new Uint16Array(24)
            years[yr][month][date][hour] = 1
        }
    }
    
    /**
     * Set the current usage in kWh from timings of flashes
     */
    function setCurrentUsage() {
        const currentTime = Date.now()
        const diffMs = currentTime - lastFlashTime
        const diffSec = diffMs / 1000
    
        const kWh = (3600 / diffSec) * 0.001
        const decimalPlaces = 2
    
        currentkWh = Number(Math.round(kWh + 'e' + decimalPlaces) + 'e-' + decimalPlaces)
        lastFlashTime = currentTime
    }
    
    /**
     * Watch fires an update
     */
    function update() {
        increment()
        setCurrentUsage()
    }
    
    /**
     * Initialization function
     */
    function onInit() {
        clearWatch()
        D1.write(0)
        pinMode(D2, 'input_pullup')
        setWatch(function (e) {
            update()
            digitalPulse(LED1, 1, 1) // Show activity
        }, D2, { repeat: true, edge: 'falling' })
    }
    

    When I type dump() into the IDE whilst it's broken, I still see the setWatch there, nothing seems out of place.

    Regarding your comment about an error in setWatch, how would I go about catching an error in there? I guess a try/catch?

  • @Gordon actually I was mistaken in the last message. When I check the dump() again, I can see that the setWatch code is repeated at the bottom. Surely this has to be the issue? What could cause the duplication of the setWatch script?

  • @Gordon This is what the end of the dump() looks like


    1 Attachment

    • Screen Shot 2019-08-02 at 19.57.23.png
  • Hi - that's what you'd expect - so what happens is dump() tries to recreate the current state of the interpreter as code. Because onInit has already run, the watch was added already so it creates code for it.

    So that all looks good. What happens if you're connected via Bluetooth when the LED flashes? Do you get any error messages? You could try putting digitalPulse before update to see if that helps - because if update created an error then execution would stop before it got run.

    ... or maybe:

        setWatch(function (e) {
            try {
              update()
              digitalPulse(LED2, 1, 1) // Show activity
            } catch (e) {
              digitalPulse(LED1, 1, 1) // Show activity
              console.log(e);
            }
        }, D2, { repeat: true, edge: 'falling' })
    

    That'll flash green if it's ok, red if there was an error.

    Could you check E.getBatteryPercentage()? It just might be your battery is on the way out?

    gattserverdisconnected usually happens either if the Puck forces a disconnect (which you're not doing) or if it reboots.

  • It looks like you were right about the battery. Although when I checked, it showed around 50%, every time I checked the percentage varied considerably. It was an old battery, so I changed it for a new one. It's been many days in now and there's not been a single issue with the watch not working.

    Many thanks for helping to fix this issue!

  • Fri 2019.08.09

    @Fisu should you be curious, we just wrapped up a discussion on the electrical characteristics, battery life and what to look out for with this exact same battery. Includes datasheet links and explanations:

    http://forum.espruino.com/conversations/­304667/#comment14851181

  • Thanks for the link. Some interesting stuff there.

  • I was so sure it was the battery that's the issue as it was working for 4-5 days without issue. Then last night (still with the new battery) it stopped working again.

    So whilst it is broken, when the light on the electric meter flashes, I don't get any light flashing on the Puck (I did implement the try/catch above, but neither the red nor green light flashes). I get no error messages when connected in the IDE. I wondered could it have something to do with the memory slots, but doing process.memory().free showed 2016, which I assume is more than enough.

    Would you happen to have any other ideas what I could try?

  • Sat 2019.08.10

    So that you are not waiting, wondering,

    Did you catch this post?

    Out of office, 9th to 26th Aug


    I'm not able to assist as we don't have that type of meter here in the US. However, have you attempted to go back to the original source that Gordon references in #4 and give that a go?

    Are you able to restart and continue, e.g. this is only a run time issue after a period of time, or are you forced to reboot/re-upload?

    Is it possible there is a counter or something related to the date that reaches an upper limit, then causes an over flow or error? Could placing that section inside a try/catch help in identifying a possible cause to investigate further?

    'but doing process.memory().free showed 2016'

    Plenty.

    'but neither the red nor green light flashes'

    Wow, I would expect one or the other, so it appears that setWatch() is no longer seeing edges. It would appear that function update() is stuck in an endless loop. To check, place another console.log() outside of the try/catch in #9 with an additional counter, then monitor. Will/may take a few days before halting, as you pointed out. Not sure if this would work, but at that point, is it possible to block copy that #9 on the left-hand console side of the WebIDE and see if pulses can then be detected? e.g. Espruino is still running and the issue IS in the update() function.

    Try placing a try/catch block(s) inside the update function to see if errors can be trapped, rather than bubbling up and possibly missed.

    As a last resort, pepper the entire flow with console.log() statements and see which one is last recorded.

  • Many thanks. Plenty of ideas to try there. I'll implement what you suggest and report back what happens when it fails again.

  • Just spotted this:

    Fr L#60 function setCurrentUsage() {

    Here is a likely spot. There are two division equations. If the divisor is ever zero, a divide by zero error will be thrown. Place the try/catch just inside this function wrapping all, or create two separate to isolate. Maybe a system call to time is not completing timely.

    Is L68 an acceptable practice? (combining a float with string text 'e' to return a number inside round?) parseFloat() or parseInt() are required to provide the Math object with a valid number.
    or

    https://www.w3schools.com/jsref/jsref_to­exponential.asp

    https://developer.mozilla.org/en-US/docs­/Web/JavaScript/Reference/Global_Objects­/Math
    "Math is a built-in object that works with the Number type"



    Could the const keyword be blocking a later assignment to that corresponding declaration.
    Try changing all const to var to test. Not likely, but worth a shot.

    Add a clearWatch() in every catch to immediately stop execution. Label each with a useful descriptor like a line number. Hopefully there will be enough previous console.log detail prior to the clearWatch() call to review.

    Run time debugging is a challenge and can be a real pain, . . . just waiting.

  • Good catch with the division. I've now added the try/catch to see if the issue is with that.

    Regarding L68, I'm not sure it is acceptable practice, but it was a trick I found to round a number to x decimal places. If that is the issue, then the try/catch should catch that, although I've been using the same snippet in other work, so I'd be surprised if that is the issue.

    Thanks for the tips, I've updated the Puck code so I'll wait and see what gets logged out.

  • I think you don't have to format the currentkWh on the puck.

    Just use toFixed on the display page. For example:

    var kwh = 1234.56789;
    console.log(kwh.toFixed(2))
    "1234.57"
    

    Separation of data & display concerns :)

  • Sun 2019.08.11

    You beat me to it toFixed() @AkosLukacs, as I was in the process of documenting a discovered anomaly while prepping my response.

    Math.round() doesn't follow specification for exact 0.5

    as a mod to your example will show

    >var kwh = 1234.505;
    >console.log(kwh.toFixed(2))
    1234.50
    



    Is this another anomaly but with toFixed()? (re: "The number is rounded if necessary" )

    https://developer.mozilla.org/en-US/docs­/Web/JavaScript/Reference/Global_Objects­/Number/toFixed
    "toFixed() returns a string representation of numObj that does not use exponential notation and has exactly digits digits after the decimal place. The number is rounded if necessary, and the fractional part is padded with zeros if necessary so that it has the specified length."



    YES just posted

    Number.toFixed() not rounding per specification

  • The result of toFixed looks like a number, because you console.log it, so there are no parenthesis around the printed value.

    >var fixed = kwh.toFixed(2);
    ="1234.50"
    
    >typeof fixed
    ="string"
    

    And yes, looks like some rounding anomaly:

    >2134.506.toFixed(2)
    ="2134.50"
    >2134.507.toFixed(2)
    ="2134.51"
    
  • Our posts are crossing each other and I hadn't finalized that post. Discovered the difference while ping-ponging between MDN and the WebIDE. Is an interesting subtlety one needs to be aware of. Thanks for confirming.

    'so there are no parenthesis '    (double quotes)

    May I inquire as to which Espruino version those tests were done? (same 2v04 ?)


    Had a thought, could this anomaly be related to the floating point number of digits to right of zero not matching different browsers and node.js output? hmmmm. . . .

    http://forum.espruino.com/conversations/­336605/
    test files #1

  • Yes, you're right, I should just format it on the page. Thanks.

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

Subsequently connecting to Puck seems to clear pin watch

Posted by Avatar for Fisu @Fisu

Actions