Attempt to index global 'websocket' - esp8266

I'm pretty new to the ESP8266. I'm trying to add the WebSockets to the Lua code, but everytime I try to use the WebSocket looking at the documentation, the device throws error as attempt to index global websocket (a nil value). I'm not really sure if there is something to be imported, can anyone please help me with this.
function connectToSocket()
print ("Connect to socket called, OK.")
local ws_client = websocket.createClient()
end
wifi.setphymode(wifi.PHYMODE_N)
wifi.setmode(wifi.STATION)
wifi.sta.config("SSID","PWD")
wifi.sta.eventMonReg(wifi.STA_IDLE, function() print("IDLE") end)
wifi.sta.eventMonReg(wifi.STA_CONNECTING, function() print("CONNECTING...") end)
wifi.sta.eventMonReg(wifi.STA_WRONGPWD, function() print("WRONG PASSWORD!!!") end)
wifi.sta.eventMonReg(wifi.STA_APNOTFOUND, function() print("NO SUCH SSID FOUND") end)
wifi.sta.eventMonReg(wifi.STA_FAIL, function() print("FAILED TO CONNECT") end)
wifi.sta.eventMonReg(wifi.STA_GOTIP, function()
print("GOT IP "..wifi.sta.getip())
connectToSocket()
end)
wifi.sta.eventMonStart()
wifi.sta.connect()

I see three problems with the above code.
The main issue appears to be that your firmware is missing the websocket module. Uncomment https://github.com/nodemcu/nodemcu-firmware/blob/master/app/include/user_modules.h#L75 if you happen to build it manually.
Furthermore, all event handlers need to be registered before the respective events have a chance to be fired. I see you intend to do exactly that. However, by default wifi.sta.config uses auto connect=true in which case the WiFi registration process starts before the event monitor is started.
Lastly, the signature for wifi.sta.config changed a few months ago (see docs for details). Now you'd have to say wifi.sta.config{"SSID","PWD"} thereby passing a Lua table.

Related

PANIC: unprotected error in call to Lua API (init.lua:116: attempt to call field 'alarm' (a nil value))

I keep getting an error on this line of code, how can I solve this? Thanks in advance
tmr.alarm(0, 250, tmr.ALARM_AUTO, function()
You are obviously using an outdated example snippet from somewhere. There is no tmr.alarm function in the timer module.
See https://nodemcu.readthedocs.io/en/latest/modules/tmr/ for the current API documentation. There is a alarm() function on a timer object i.e. you first need to create a timer object. The below example is straight from the documentation:
if not tmr.create():alarm(5000, tmr.ALARM_SINGLE, function()
print("hey there")
end)
then
print("whoopsie")
end

lua: init.lua:15: attempt to call method 'alarm' (a nil value)

i am trying to fix a piece of code i did find online. (yeah i know....)
But in case you guys can help me out wihth this error it would be just amazing:
Error: lua: init.lua:15: attempt to call method 'alarm' (a nil value)
Code (from here: https://github.com/Christoph-D/esp8266-wakelight)
dofile("globals.lc")
wifi.setmode(wifi.STATION)
wifi.sta.config(WIFI_SSID, WIFI_PASSWORD)
wifi.sta.sethostname(MY_HOSTNAME)
if WIFI_STATIC_IP then
wifi.sta.setip({ip = WIFI_STATIC_IP, netmask = WIFI_NETMASK, gateway = WIFI_GATEWAY})
end
wifi.sta.connect()
-- Initialize the LED_PIN to the reset state.
gpio.mode(LED_PIN, gpio.OUTPUT)
gpio.write(LED_PIN, gpio.LOW)
tmr.alarm(
MAIN_TIMER_ID, 2000, tmr.ALARM_AUTO, function ()
if wifi.sta.getip() then
tmr.unregister(MAIN_TIMER_ID)
print("Config done, IP is " .. wifi.sta.getip())
dofile("ledserver.lc")
end
end)
What can i do there? Whats wrong?
Cheers and thank you!!!
It is all in the manual. You just have to read it.
There is an example of how to use the alarm method of timer objects.
if not tmr.create():alarm(5000, tmr.ALARM_SINGLE, function()
print("hey there")
end)
then
print("whoopsie")
end
You attempted to call tmr.alarm but it is tobj:alarm. The manual does not mention tmr.alarm. This function was removed from NodeMCU in January 2019.
You're using code you found online that is basedn on an older NodeMCU version. It is using functions that are deprecated by now.
See https://github.com/nodemcu/nodemcu-firmware/pull/2603#issuecomment-453235401
and
https://github.com/nodemcu/nodemcu-firmware/compare/5b22e1f9aee77095ab99dd6240ebd9dddd1cc5a0..c6444ecb6088d20e95197d808d8303c8093faab5
So you have to create a timer object first befvor you can use any of its methods. alarm is not a method of the tmr module anymore.
Edit
First you have to create a timer object https://nodemcu.readthedocs.io/en/latest/modules/tmr/#tobjcreate
local tObj = tmr.create()
Then you have to register a callback and start the timer. There is a convenience function alarm that does both for us.
And when we do not need our timer anymore we have to free the resources by calling
tObj:unregister()
Try something like
-- create a timer object
local tObj = tmr.create()
-- register an alarm
tObj:alarm(2000, tmr.ALARM_AUTO, function ()
if wifi.sta.getip() then
tObj:unregister()
print("Config done, IP is " .. wifi.sta.getip())
dofile("ledserver.lc")
end
end)

nodemcu with Lua and 8266 tmr.stop

Note: This is a copy of a question asked here
Hi
I am completely new to EPS8266 and Lua (but not to programming - my first CPU was an 8080...)
Using a nodemcu HUZZA from adafruit
Anyway I am testing some timer stuff and running into this:
tmr.alarm(0, 500, 1, function()
print("I'm here")
tmr.stop(0)
end)
Without the stop, the loop keeps printing, with it the tmr.stop(0) stops. ... so far so good.
But if I want to start the timer again like:
tmr.alarm(0, 500, 1, function()
print("I'm here")
tmr.stop(0)
-- do some stuff
tmr.start(0)
end)
I get an error: PANIC: unprotected error in call to Lua API...
The documentation says that the tmr is still registered when stop is called.
A call to tmr.state(0) does the same. Only tmr.stop(0) seems to works as expected.
Thanks for your thoughts.
The documentation says to no longer use static timers
Static timers are deprecated and will be removed later. Use the OO API initiated with tmr.create().
If you want complete control over when the functions in the timer callback are executed you need a ALARM_SEMI instance upon which you call start whenever needed. It'll fire exactly once for every time you call start on it.
local mytimer = tmr.create()
mytimer:register(500, tmr.ALARM_SEMI, function() print("I'm here") end)
-- do stuff here
-- then whenever needed trigger the timer
mytimer:start()
Note that mytimer is not unregistered and not garbage collected.
Based on the documentation, you need to use tmr.ALARM_SEMI as your alarm mode.
ALARM_SEMI is described by the documentation as:
tmr.ALARM_SEMI manually repeating alarm (call tmr.start() to
restart)
tmr.ALARM_SEMI is equal to 2. Based on that, this should work:
tmr.alarm(0, 500, 2, function()
print("I'm here")
tmr.stop(0)
-- do some stuff
tmr.start(0)
end)

NodeMCU WiFi auto connect

I am trying to resolve wifi connectivity using Lua language. I have been combing through the api to find a solution but nothing solid yet. I asked a previous question, dynamically switch between wifi networks and the answer did address the question in the way I asked it, but it didn't accomplish what I expected.
Basically, I have two different networks from two different providers. All I want the ESP8266 12e to do is detect when or if the current network has no internet access and automatically switch to the next network. It must continuously try to connect at say a 3 minute interval until it is successful and not just give up.
For testing purposes I tried this code below. The plan is to use the variable "effectiveRouter" and write some logic to switch based on the current router.
effectiveRouter = nil
function wifiConnect(id,pw)
counter = 0
wifi.sta.config(id,pw)
tmr.alarm(1, 1000, tmr.ALARM_SEMI, function()
counter = counter + 1
if counter < 10 then
if wifi.sta.getip() == nil then
print("NO IP yet! Trying on "..id)
tmr.start(1)
else
print("Connected, IP is "..wifi.sta.getip())
end
end
end)
end
wifiConnect("myNetwork","myPassword")
print(effectiveRouter)
When I run that code, I get effectiveRouter as nil on the console. This tells me that the print statement ran before the method call was complete, print(effectiveRouter). I am very very new to lua as this is my first time with the language. I am certain this boiler plate code must have been done before. Can someone please point me in the right direction? I am open to shifting to the arduino IDE as I already have it set up for the NodeMCU ESP8266. May be I can follow the logic better as I come from a java-OOP background.
I eventually sat down and tested my sketch from the previous answer. Two additional lines and we're good to go...
What I missed is that wifi.sta.config() resets the connection attempts if auto connect == true (which is the default). So, if you call it to connect to AP X while it's in the process of connecting to X it will start from scratch - and thus usually not get an IP before it's called again.
effectiveRouter = nil
counter = 0
wifi.sta.config("dlink", "password1")
tmr.alarm(1, 1000, tmr.ALARM_SEMI, function()
counter = counter + 1
if counter < 30 then
if wifi.sta.getip() == nil then
print("NO IP yet! Keep trying to connect to dlink")
tmr.start(1) -- restart
else
print("Connected to dlink, IP is "..wifi.sta.getip())
effectiveRouter = "dlink"
--startProgram()
end
elseif counter == 30 then
wifi.sta.config("cisco", "password2")
-- there should also be tmr.start(1) in here as suggested in the comment
elseif counter < 60 then
if wifi.sta.getip() == nil then
print("NO IP yet! Keep trying to connect to cisco")
tmr.start(1) -- restart
else
print("Connected to cisco, IP is "..wifi.sta.getip())
effectiveRouter = "cisco"
--startProgram()
end
else
print("Out of options, giving up.")
end
end)
You better to migrate a callback based architecture to be sure that you have successfully connected. Here is doc for it :
https://nodemcu.readthedocs.io/en/master/en/modules/wifi/#wifistaeventmonreg
You can listen for
wifi.STA_GOTIP
And make your custom operations in it. Do not forget to start eventmon.
P.s. I am not able to see your variable effectiveRouter in related function.

dynamically switch between wifi networks

I have two WiFi networks at home where I want to use my NodeMCU ESP8266 V1 to control several relays remotely over the web from anywhere in the world.To accomplish this I was thinking to test for WiFi connectivity and if I don't get an IP within 1-minute try the other network until I get an IP. Here is the API docs for tmr which I followed in the code below.
Is there a way to switch between two or more wifi networks programatically using Lua? I am using the Lua language, however I can move to arduino IDE, if required.
wifi.setmode(wifi.STATION)
myRouter = "dlink"
tmr.alarm(1, 60000, tmr.ALARM_SINGLE, function()
if myRouter=="dlink" then
print("Dlink selected")
wifi.sta.config("dlink","password1")
wifi.sta.connect()
if wifi.sta.getip() == nil then
print("NO IP yet! ,Connecting...")
else
tmr.stop(1)
print("Connected, IP is "..wifi.sta.getip())
end
elseif myRouter=="cisco" then
print("Cisco selected")
wifi.sta.config("cisco","passoword2")
wifi.sta.connect()
if wifi.sta.getip() == nil then
print("NO IP yet! ,Connecting...")
else
tmr.stop(1)
print("Connected, IP is "..wifi.sta.getip())
end
else
print("No network is giving an ip")
end
end)
What I am looking for is a callback which fires whenever the timer "tmr" expires. This way I can change the variable to myRouter="cisco". Notice in the code above i was unable to change the "myRouter" variable.
I considered using a software watchdog to monitor the conectivity all the time so if or when the WiFi drops on one network, it will trigger a reconnect by running the code above. I am not sure how to do this or how its usually done, since I am very new to lua. Please advise or point me to a resource which can help in this regard. Thanks guys.
This is an untested piece of code quickly put together.
effectiveRouter = nil
counter = 0
wifi.sta.config("dlink", "password1")
tmr.alarm(1, 1000, tmr.ALARM_SEMI, function()
counter = counter + 1
if counter < 60 then
if wifi.sta.getip() == nil then
print("NO IP yet! Keep trying to connect to dlink")
tmr.start(1) -- restart
else
print("Connected to dlink, IP is "..wifi.sta.getip())
effectiveRouter = "dlink"
startProgram()
end
elseif counter < 120 then
wifi.sta.config("cisco", "password2")
if wifi.sta.getip() == nil then
print("NO IP yet! Keep trying to connect to cisco")
tmr.start(1) -- restart
else
print("Connected to cisco, IP is "..wifi.sta.getip())
effectiveRouter = "cisco"
startProgram()
end
else
print("Out of options, giving up.")
end
end)
It'll first try to connect to 'dlink' for 60s, then to 'cisco' for another 60s, and will eventually give up after that if neither attempts was successful. It uses a semi-automatic timer which is only restarted if there's no IP yet.

Resources