The wifi.sta module connects if a loop is running? - lua

Im trying to detect when the module actually connects to my wifi AP, since .connect does not have a callback im doing something simple like this:
wifi.sta.config("SSID","password")
wifi.sta.connect()
tmr.delay(1000000)
i = 0
while(wifi.sta.status() ~= 5 and i < 10) do
print("Waiting")
print(wifi.sta.status())
i = i + 1
tmr.delay(1000000)
end
But the output of .sta.status() is always 1 inside the loop. When it finish, if I send the command =wifi.sta.status() manually from the IDE it tells me 5. Why?

If you use a recent dev firmware you can do something really event based :
wifi.setmode(wifi.STATION)
wifi.sta.config(SSID, PASSWORD)
function Success()
tmr.stop(0)
if (SERIAL_PRINT) then
print("IP: " .. wifi.sta.getip())
end
wifi.sta.eventMonStop()
wifi.sta.eventMonReg(wifi.STA_GOTIP, "unreg")
dofile("mainProgram.lua")
end
function Failure()
if (SERIAL_PRINT) then
print("Unable to connect")
end
wifi.sta.eventMonStop()
wifi.sta.eventMonReg(wifi.STA_GOTIP, "unreg")
return 0
end
tmr.alarm(0,30000,0, function() Failure() end)
wifi.sta.connect()
wifi.sta.eventMonReg(wifi.STA_GOTIP, function() Success() end)
wifi.sta.eventMonStart()
EDIT: Please have a look to the documentation for a list of all events. If you wish to use this code, you'll have to handle the failure more cleanly.

Using tmr.delay doesnot let run the event loop, you should use a timer callback.
Then the code could be something like :
wifi.sta.config("SSID","password")
wifi.sta.connect()
i=0
tmr.alarm(1, 1000, 1, function()
if (wifi.sta.status() ~= 5 and i < 10) then
print("Status:"..wifi.sta.status())
i = i + 1
else
tmr.stop(1)
if (wifi.sta.status() == 5) then
print("IP:"..wifi.sta.getip())
else
print("Status:"..wifi.sta.status())
end
end
end)

Related

Lua function returns string, but calling function gets nil

I'm writing a function for Nodemcu (esp8266) Lua to build command strings from UART (someone typing). When it finishes capturing characters, it's supposed to return the string to the calling function, but the calling function only gets nil. I'm new to Lua, What am I missing?
local function getcmd()
local t = { }
local cmd
-- Callback function
uart.on("data", 0, function(data)
if data~='\r' then
--Echo input
t[#t+1] = data
uart.write(0,t[#t])
-- BACKSPACE/DEL
if t[#t] == '' then
t[#t] = nil
t[#t] = nil
end
-- NEED <TAB> handling here too
else
--Disables callback
--uart.on("data")
-- Print table, convert to string.
for i = 1, #t do
uart.write(0, t[i])
if i==1 then
cmd = tostring(t[i])
else
cmd = cmd .. tostring(t[i])
end
end
t = { }
if cmd ~= nil then
uart.write(0, "Before Return> "..cmd)
-- type() String
return cmd
end
end
end,0)
end
local function config()
local cmdstr
-- Testing
cmdstr = getcmd()
print("func() "..getcmd())
if cmdstr ~= nil then
uart.write(0, cmdstr.."> ")
end
end
Thanks to #EgorSkriptunoff for helping me understand what was happening.
Below is the code that works (so far). What I tried was a While loop around the event handler inside of getcmd(). This fails because it stops execution of all the background events that keep things like wifi and other essential functions that keep the ESP8266 running, so it crashes/reboots repeatedly.
What I did instead of returning from getcmd() was call config() directly and pass it the input I collected in the event handler, like this: config(cmd)
The potential problem is, the event handler is still running since it never reached the end and that could cause some stack/memory issues if I don't return from config() before calling another function.
Anyway, here is the code that is working for the moment:
function getcmd()
local t = { }
cmd=nil
uart.on("data", 0, function(data)
if data~='\r' then
--Echo input
t[#t+1] = data
uart.write(0,t[#t])
-- BACKSPACE/DEL
if t[#t] == 'BS' then
t[#t] = nil
t[#t] = nil
end
else
--uart.on("data")
if #t ~= nil then
uart.write(0,"\r\n"..#t.."\r\n")
end
for i = 1, #t do
uart.write(0, t[i])
if i==1 then
cmd = tostring(t[i])
else
cmd = cmd .. tostring(t[i])
end
end
t = { }
if cmd ~= nil then
-- Calling config() here doesn't allow event handler on.uart() to end.
config(cmd)
end
end
end,0)
end
------------------------------------------------------
function config(cmd)
print("\r<<"..cmd..">>\r")
-- Now parse cmd and return.
end

Tarantool fiber behavior with fiber.yield() and fiber.testcancel()

I ran into an unexpected behavior while building Tarantool app based on fibers.
Simple reproducer of my code looks like this:
local log = require('log')
local fiber = require('fiber')
box.cfg{}
local func = function()
for i = 1, 100000 do
if pcall(fiber.testcancel) ~= true then
return 1
end
fiber.yield()
end
return 0
end
local wrapfunc = function()
local ok, resp = pcall(func)
log.info(ok)
log.info(resp)
end
for _ = 1, 100 do
local myfiber = fiber.create(wrapfunc)
fiber.sleep(0.02)
fiber.kill(myfiber)
end
and it prints to log false, fiber is cancelled. Moreover, if I use the following func:
local func = function()
for i = 1, 100000 do
if pcall(fiber.testcancel) ~= true then
return 1
end
pcall(fiber.yield)
end
return 0
end
it prints to log true, 1, and if I use
local func = function()
for i = 1, 100000 do
if pcall(fiber.testcancel) ~= true then
return 1
end
if pcall(fiber.yield) ~= true then
return 2
end
end
return 0
end
it prints to log true, 2.
I expected that after yielding from running myfiber, if control returns to the external fiber and it calls fiber.kill(myfiber), the next time control returns to the cancelled myfiber we will be in the end of cycle iteration and on the next iteration code will successfully return 1. However, the work of func ends with throwing error fiber is cancelled, not with return. So how the real life cycle of yielding fiber works?
Actually, there is no unexpected behaviour here. I believe it mostly documentation issue. Let me explain. I've simplified your example a bit:
#!/usr/bin/env tarantool
local fiber = require('fiber')
local f1 = function() fiber.yield() end
local f2 = function() pcall(fiber.yield) end
local func = function(fn)
fn()
if not pcall(fiber.testcancel) then
return 'fiber.testcancel() failed'
end
end
local fiber1 = fiber.create(function() print(pcall(func, f1)) end)
fiber.kill(fiber1)
local fiber2 = fiber.create(function() print(pcall(func, f2)) end)
fiber.kill(fiber2)
The output would be:
false fiber is cancelled
true fiber.testcancel() failed
When you call fiber.kill, fiber.yield() or fiber.sleep() just raises an error, so your fiber is not able to reach fiber.testcancel and just dies. When you do pcall(fiber.yield), you basically suppress this error and proceed. Then fiber.testcancel checks its fiber status and reraise an exception. But this is a silly example.
Now, with bigger chunks of code, when lots of function invocations involved, you usually want to catch those errors during yield, do some finalisation work and call fiber.testcancel() to promote error upwards (imagine multiple checks of this kind in different parts of big stacktrace). I believe it is the basic use case, fiber.testcancel was introduced for, besides discussions if its design is usable or not.
P.s. And yes, occasional exceptions of such yield calls are not documented. At least I could not find anything in the fiber page

Web request event driven Lua code

What i have seen and currently implemented in my Lua scripts running on my ESP8266 WiFi module, are polling the server page every few seconds and than checking whether the value has changed or not. If value has changed than take some action.
Here's my code
tmr.alarm(1,10000, 1, function()
if (wifi.sta.getip() == nil) then
print("IP unavaiable, Waiting...")
else
tmr.stop(1)
tmr.alarm(1,10000, 1, function()
event_driven_func()
end)
end
end)
function event_driven_func()
print("Inside event_driven_func function"..node.heap());
conn = nil
conn=net.createConnection(net.TCP,0)
conn:on("receive", function(conn, payload)
-- local buf = "";
startRead = false
Data = ""
print("payload : "..payload)
for i = 1, #payload do
c = payload:sub(i,i)
if (c=="{") then
startRead=true
end
if (startRead) then
Data=Data..c
end
if (c=="}") then
startRead=false
print("json string detected Do something now ...");
end
end
conn:close()
collectgarbage("collect");
end)
conn:connect(80,"my_server.co.in")
conn:on("connection", function(conn, payload)
conn:send("GET /xyz.php HTTP/1.0\r\nHost: my_server.co.in\r\nConnection: keep-alive\r\nAccept: */*\r\n\r\n")
end)
end
But this is highly inefficient.
How to implement or better a pseduo-code, a event driven code where whenever the value changes there's an interrupt to the code and then event_driven_func executes ?
Or any better efficient way.
Application example :
Say i've number of youtube subscribers showing on a server page, whenever the subscribers change it should make a "POST" web request to one of my json page xyz.php (this will be done using IFTTT ) and then a event will execute the function in Lua code so that value will be reflected.

HTTP GET in LUA/NodeMCU

I'm trying to send a HTTP GET each time I press a button :
wifi.setmode(wifi.STATION)
wifi.sta.config("SSID","PWD")
function loop()
if wifi.sta.status() == 5 then
-- Stop the loop
tmr.stop(0)
else
print("Connecting...")
end
end
tmr.alarm(0, 100, 1, function() loop() end)
print(wifi.sta.getip())
outpin_led = 1
inpin_button = 3
gpio.mode(outpin_led,gpio.OUTPUT)
gpio.mode(inpin_button,gpio.INPUT)
light_on = false
function light()
if not light_on then
-- turn the light on
gpio.write(outpin_led,gpio.HIGH)
light_on = true
http.get("https://google.com", function(clt, data)
print(data)
end)
else
-- turn the light off
gpio.write(outpin_led,gpio.LOW)
light_on = false
end
end
gpio.trig(inpin_button,"down",light)
The line containing http.get is throwing this error message :
> PANIC: unprotected error in call to Lua API (stdin:6: attempt to index global 'http' (a nil value))
I made sure my NodeMCU build contained the http module by compiling it through http://nodemcu-build.com/
Any idea ?
Thanks.
As Marcel Stör pointed out, it was indeed an issue during the flashing of the firmware.
Thanks a lot for your reply and for your work on http://nodemcu-build.com/.

Recalling functions inside the same function to try and catch failure in a loop

When I run this code on my phone, It runs through every step and then when it finds a fault it will revert backwards to the beginning of the code then alarms out. What I want it to do is run each function exactly the way its been doing, but, only to Alert me when the last function is run. Log print at the end of the code.
--Step 1 Open Quests
questopen = function()
log("Opening Quests")
local step1 = getColor(64, 803)
log("Fetched Quest Icon")
if step1 == 9127481 then
tap(64, 803)
log("Matched Quest Icon")
else
log("Failed Quest Icon")
alert("Out of Sync - Check Logs for failure")
collectgarbage()
end
end
--Step 2 Accept Quest
questaccept = function()
log("Accepting Quest")
local step2 = getColor(426, 1004)
log("Fetched Accept Quest")
if step2 == 2300441 then
tap(426, 1004)
log("Matched Accept Quest")
else
log("Failed Accept Quest")
collectgarbage()
questopen()
end
end
--Step 3 Skip Dialogue
skip = function()
log("Skipping Dialogue")
local step3 = getColor(564, 1083)
log("Fetched Skip Dialogue")
if step3 == 2300441 then
tap(564, 1083)
log("Matched Skip Dialogue")
else
log("Failed Skip Dialogue")
collectgarbage()
questaccept()
end
end
--Step 4 Quest Confirm
confirm = function()
log("Confirming Quest")
local step4 = getColor(124, 578)
log("Fetched Confirm Quest")
if step4 == 15921906 then
tap(124, 578)
log("Matched Confrim Quest")
else
log("Failed Confirm Quest")
collectgarbage()
skip()
end
end
--Step 5 Quest Go
go = function()
log("Quest Go")
local step5 = getColor(424, 990)
log("Fetched Quest Go")
if step5 == 13750737 then
tap(424, 990)
log("Matched Quest Go")
else
log("Failed Quest Go")
collectgarbage()
confirm()
end
end
questopen()
usleep(3000000)
questaccept()
usleep(3000000)
skip()
usleep(3000000)
confirm()
usleep(3000000)
go()
usleep(3000000)
I have specifically designed this to test the detection methods, So I expect it to fail at Step 2 Accept Quests. But currently I want to work a better method of error detection, I want the alert. But it alerts each and every failure.
I want the code to work backwards at the first failure, but I don't want it to keep moving forward at the same time, which the error reports will show.
Gyazo image of error log

Resources