Таймер NodeMCU неожиданно останавливается

У меня есть приложение NodeMCU Lua, которое использует два таймера. Каждый таймер вызывает функцию, которая вызывает отправку HTTP-запроса на локальный сервер.

После нескольких итераций один из таймеров останавливается, а другой таймер продолжает работу. Количество итераций до остановки таймера кажется случайным. Я запускал тестовый сценарий много раз, и точка остановки таймера никогда не бывает одинаковой. Примечание: не всегда останавливается один и тот же таймер.

Вот тестовый код, который достоверно демонстрирует эту проблему:

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)

Мое приложение не запускает HTTP-запросы так же быстро, как тестовый код, но когда приложение работает в течение нескольких часов, в конечном итоге возникает тот же результат (т.е. один из таймеров перестает работать). Уменьшение времени между HTTP-запросами приводит к тому, что ошибка возникает раньше.

Кто-нибудь сталкивался с этой проблемой? Есть ли у кого-нибудь идеи, как решить эту проблему? (невозможность надежно отправлять непрерывные HTTP-запросы является препятствием для этого приложения).


person Jonathan    schedule 13.05.2016    source источник


Ответы (2)


Решение состоит в том, чтобы установить флаги так, чтобы в любой момент времени выполнялся только один HTTP-запрос. Вот предыдущий тестовый сценарий, который включает флаги:

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)

Я запускал этот сценарий в течение нескольких часов, и обе функции HTTP-отправки продолжали работать, как ожидалось.

Я попробовал опцию node.task.post (), тестовый сценарий следующим образом:

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)

Но после пары часов работы один из обратных вызовов http не был вызван, поэтому, должно быть, произошла коллизия.

person Jonathan    schedule 14.05.2016

Я мало что знаю о NodeMCU, но, согласно справочному руководству, функции обратного вызова http.post и http.get вызываются при получении ответа. Следовательно, таймеры перезапускаются только после получения ответа. Есть ли вероятность, что есть задержка или, может быть, вы никогда не получите ответа?

Перезапуск таймера после того, как какой-то сторонний материал ответил, добавит переменную задержку и поэтому не должен быть очень точным. Я не ожидал, что он будет таким же точным, как какой-нибудь тестовый код.

Для отладки я предлагаю вам распечатать фактические задержки между вызванными обратными вызовами или задержку между публикацией / получением и ответом.

person Piglet    schedule 13.05.2016
comment
Ваш комментарий к функции обратного вызова интересен. У меня был случай в Nodemcu, где два HTTP-запроса выполнялись один за другим, а ответ на второй запрос никогда не вызывал функцию обратного вызова. Эту проблему решила вставка задержки в 1 секунду между HTTP-вызовами. Мне интересно, создают ли два таймера, работающие независимо, аналогичную ситуацию (в которой два HTTP-запроса выполняются близко друг к другу). Я проведу небольшое тестирование, чтобы увидеть, произойдет ли такое столкновение. - person Jonathan; 13.05.2016