1
votes

I have a NodeMCU Lua application that uses two timers. Each timer invokes a function that causes an HTTP request to be made to a local server.

After a few iterations, one of the timers stops, and the other timer continues. The number of iterations before the timer stops seems to be random. I have run the test script many times and the point at which the timer stops is never the same. Note: it is not always the same timer that halts.

Here is some test code that reliably demonstrates this problem:

ctr1=0
ctr2=0

local function doCmdChk()
    ctr1 = ctr1 + 1
    http.get( "http://192.168.2.38/ICmd.py?i=" .. ctr1 , nil, 
    function(rspCode, payload)
        tmr.start(1)
    end)
end

local function sendData()
    ctr2 = ctr2 + 1
    local msgBdy = '{"s":"' .. ctr2 .. '","i":"test23", "d":"heap='..node.heap()..'"}'

    http.post("http://192.168.2.38/DeviceScan.py", "Content-Type: text/json\r\n", msgBdy,
    function(rspCode, payload)
        tmr.start(2)
    end)
end

--mainline start:
tmr.alarm(1, 3000, tmr.ALARM_SEMI, doCmdChk)
tmr.alarm(2, 5000, tmr.ALARM_SEMI, sendData)

My application doesn't fire off the HTTP requests as quickly as the test code, but when the application runs for several hours the same result eventually occurs (i.e. one of the timers stops running). Reducing the time between HTTP requests makes the error occur sooner.

Has anyone encountered this issue? Does anyone have any ideas as to how to troubleshoot this issue? (not being able to reliably send continuous HTTP requests is a show stopper for this application).

2

2 Answers

1
votes

The solution is to set up flags so that only one http request is outstanding at any given time. Here is the previous test script that includes the flags:

ctr1=0
ctr2=0
sendFlag=true

local function doCmdChk()
    if sendFlag then
        sendFlag=false        
        ctr1 = ctr1 + 1
        http.get( "http://192.168.2.38/ICmd.py?i=" .. ctr1 , nil, 
        function(rspCode, payload)
            sendFlag=true
            tmr.start(1)
        end)
    else
        tmr.alarm(3, 1000, tmr.ALARM_SINGLE, doCmdChk)
    end
end

local function sendData()
    if sendFlag then
        sendFlag=false        
        ctr2 = ctr2 + 1
        local msgBdy = '{"s":"' .. ctr2 .. '","i":"test23", "d":"heap='..node.heap()..'"}'

        http.post("http://192.168.2.38/DeviceScan.py", "Content-Type: text/json\r\n", msgBdy,
        function(rspCode, payload)
            sendFlag=true
            tmr.start(2)
        end)
    else
        tmr.alarm(3, 1000, tmr.ALARM_SINGLE, sendData)
    end
end

--mainline start:
tmr.alarm(1, 3000, tmr.ALARM_SEMI, doCmdChk)
tmr.alarm(2, 5000, tmr.ALARM_SEMI, sendData)

I ran this script for several hours and both http send functions continued to work as expected.

I tried the node.task.post() option, test script as follows:

ctr1=0
ctr2=0

local function doCmdChk()
        ctr1 = ctr1 + 1
        http.get( "http://192.168.2.38/ICmd.py?i=" .. ctr1 , nil, 
        function(rspCode, payload)
            sendFlag=true
            tmr.start(1)
        end)
end

local function sendData()
        ctr2 = ctr2 + 1
        local msgBdy = '{"s":"' .. ctr2 .. '","i":"test23", "d":"heap='..node.heap()..'"}'

        http.post("http://192.168.2.38/DeviceScan.py", "Content-Type: text/json\r\n", msgBdy,
        function(rspCode, payload)
            sendFlag=true
            tmr.start(2)
        end)
end

--mainline start:
tmr.alarm(1, 3000, tmr.ALARM_SEMI, function() node.task.post(node.task.MEDIUM_PRIORITY, doCmdChk) end)
tmr.alarm(2, 5000, tmr.ALARM_SEMI, function() node.task.post(node.task.HIGH_PRIORITY, sendData) end)

But after a couple of hours of running one of the http callbacks was not invoked, so there must have been a collision.

0
votes

I don't know much about NodeMCU, but according to the reference manual the http.post and http.get callback functions are invoked when a response is received. Hence timers are only restarted when a response is received. Any chance there is a delay or maybe you never get a response?

Restarting a timer after some third party stuff has responded would add a variable delay and therefor should not be very precise. I would not expect it to be as accurate as some test code.

For debugging I suggest you print the actual delays between invoked callbacks or the delay between post/get and response.