NodeMCU timeout when using while loop

前提是你 提交于 2020-01-06 20:02:56

问题


I have a Lua script that sends an email to myself via SMTP. Everything works fine when uploading to the NodeMCU and saying dofile("sendemail.lua").

-- sendmail.lua    

-- The email and password from the account you want to send emails from
    MY_EMAIL = "REDACTED"

EMAIL_PASSWORD = "REDACTED"

-- The SMTP server and port of your email provider.
-- If you don't know it google [my email provider] SMTP settings
SMTP_SERVER = "isp.smtp.server"
SMTP_PORT = 25

-- The account you want to send email to
mail_to = "REDACTED"

-- Your access point's SSID and password
SSID = "REDACTED"
SSID_PASSWORD = "REDACTED"

-- configure ESP as a station
wifi.setmode(wifi.STATION)
wifi.sta.config(SSID,SSID_PASSWORD)
wifi.sta.autoconnect(1)

email_subject = ""
email_body = ""
count = 0


local smtp_socket = nil -- will be used as socket to email server

-- The display() function will be used to print the SMTP server's response
function display(sck,response)
     print(response)
end

-- The do_next() function is used to send the SMTP commands to the SMTP server in the required sequence.
-- I was going to use socket callbacks but the code would not run callbacks after the first 3.
function do_next()
            if(count == 0)then
                count = count+1
                IP_ADDRESS = wifi.sta.getip()
                smtp_socket:send("HELO "..IP_ADDRESS.."\r\n")
            elseif(count==1) then
                count = count+1
                smtp_socket:send("AUTH LOGIN\r\n")
            elseif(count == 2) then
                count = count + 1
                smtp_socket:send("REDACTED".."\r\n")
            elseif(count == 3) then
                count = count + 1
                smtp_socket:send("REDACTED".."\r\n")
            elseif(count==4) then
                count = count+1
               smtp_socket:send("MAIL FROM:<" .. MY_EMAIL .. ">\r\n")
            elseif(count==5) then
                count = count+1
               smtp_socket:send("RCPT TO:<" .. mail_to ..">\r\n")
            elseif(count==6) then
                count = count+1
               smtp_socket:send("DATA\r\n")
            elseif(count==7) then
                count = count+1
                local message = string.gsub(
                "From: \"".. MY_EMAIL .."\"<"..MY_EMAIL..">\r\n" ..
                "To: \"".. mail_to .. "\"<".. mail_to..">\r\n"..
                "Subject: ".. email_subject .. "\r\n\r\n"  ..
                email_body,"\r\n.\r\n","")

                smtp_socket:send(message.."\r\n.\r\n")
            elseif(count==8) then
               count = count+1
                 tmr.stop(0)
                 smtp_socket:send("QUIT\r\n")
                 print("msg sent")
            else
               smtp_socket:close()
            end
            print(count)
end

-- The connectted() function is executed when the SMTP socket is connected to the SMTP server.
-- This function will create a timer to call the do_next function which will send the SMTP commands
-- in sequence, one by one, every 5000 seconds. 
-- You can change the time to be smaller if that works for you, I used 5000ms just because.
function connected(sck)
    tmr.alarm(0,5000,1,do_next)
end

-- @name send_email
-- @description Will initiated a socket connection to the SMTP server and trigger the connected() function
-- @param subject The email's subject
-- @param body The email's body
function send_email(subject,body)

     count = 0
     email_subject = subject
     email_body = body
     smtp_socket = net.createConnection(net.TCP,0)
     smtp_socket:on("connection",connected)
     smtp_socket:on("receive",display)
    smtp_socket:connect(SMTP_PORT, SMTP_SERVER)     
end
-- Send an email
send_email("ESP8266", "[[Hi, How are your IoT projects coming along? Best Wishes,ESP8266]]")

However, I want to use a loop to monitor an analog input value and only send the email when certain analog input values are detected. Therefore, I added this code at the end of the script, after the sendemail() function definition and immediately before the function sendmail('subject', 'body') is called

vp = 0
gpio.mode(vp, gpio.INPUT)

while true do

    local v = adc.read(vp)
    if v < 840 or v > 870 then
        print(v)
        break
    end
    tmr.wdclr()
end
sendmail('subject', 'body')

The while loop works perfectly, waiting indefinitely for input from the analog pin. Once that input is found, it breaks correctly and calls the sendmail function. However, once that function is called, NodeMCU eventually resets. Sometimes it will get as far as successfully authenticating the SMTP credentials with the server, and sometimes it will not even make the HELO before it shuts down. What could possibly be causing this? Why would the sendmail.lua script work fine then suddenly decide not to work when adding this one small while loop that appears to work perfectly fine on its own?


回答1:


A little quote from the NodeMCU reference:

tmr.wdclr() Feed the system watchdog.

In general, if you ever need to use this function, you are doing it wrong.

The event-driven model of NodeMCU means that there is no need to be sitting in hard loops waiting for things to occur. Rather, simply use the callbacks to get notified when somethings happens. With this approach, there should never be a need to manually feed the system watchdog.

Please note the second line. :)

Not sure what your problem is, but why do you use a while loop in the first place? Why not use timer events to poll your ADC regularly?

Maybe the watchdog is triggered because your feed comes to late for some reason. In the if case you don't feed it at all befor you leave the loop.




回答2:


Even if it may not be the definite answer I post it as such since the comment input is too small.

First, I suggest you use the script I posted for your previous question. This one isn't handling WiFi setup correctly. You need to wait in a timer until the device got an IP before you can continue. Remember, wifi.sta.config is non-blocking. And since it uses auto-connect=true if not set explicitly it'll try to connect to the AP immediately. That's also the reason why wifi.sta.autoconnect(1) is superfluous.

I don't understand the ADC reading code you posted.

vp = 0
gpio.mode(vp, gpio.INPUT)

Seems unnecessary to me because a) you don't do anything with GPIO 0 and b) adc.read only supports 0.

Rather than using a busy loop and constantly feeding the watch dog, which is a very bad sign, I suggest you use an interval based timer. Furthermore, I guess you don't wanna break the loop the first time the condition is met and never come back? So, you need to stay in the loop and keep triggering send mail, no? Something like this maybe (untested):

tmr.alarm(0, 200, tmr.ALARM_AUTO, function()
  local v = adc.read(0)
  if v < 840 or v > 870 then
    node.task.post(function()
      send_email("ESP8266", "[[Hi, How are your IoT projects coming along? Best Wishes,ESP8266]]")
    end)
  end
end)


来源:https://stackoverflow.com/questions/38232100/nodemcu-timeout-when-using-while-loop

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!