Success callback function called on failure. Possible bug? - lua

I'm working on a little project, using an ESP8266 with NodeMCU and Lua. I suspect I've found a bug, but since I'm new to Lua (and the other two too!), I'm hoping for some help in confirming if I'm right, or if I've missed something (more likely!).
The NodeMCU firmware contains a built-in SNTP client module which updates the synchronised time to a system clock (rtctime module). The success callback function seems to get called when (or possibly before) the NTP sync fails. This happens for example if the wifi is not connected, or sometimes on the first sync attempt after boot (with wifi connected). According to the doco, rtctime.get() returns zero if current time is not available; this is the result I get, further showing that the NTP sync hasn't been successful. I can't work out why the success function is being called at this point, in advance of, or instead of the failure function (as I would have expected).
The sntp module I'm referring to is here - unfortunately, the C source code was a bit over my head: https://nodemcu.readthedocs.io/en/master/en/modules/sntp/
My (minimal) code:
-- Define callback function for ntp sync success
function ntpSyncSuccess (sec, usec, server, info)
print('SNTP time sync successful!')
print("rtctime.get() returns: ", rtctime.get())
end
-- Configure and start NTP time sync with auto repeat enabled
sntp.sync("0.au.pool.ntp.org",
ntpSyncSuccess(sec, usec, server, info), --success callback
function() -- error callback
print('SNTP time sync failed!')
end,
1 -- enable autorepeat (SNTP sync every 1000 seconds (~17 min))
)
Serial output result when I boot the device and run the code (Note the 2nd and 3rd last lines):
NodeMCU custom build by frightanic.com
branch: master
commit: 11592951b90707cdcb6d751876170bf4da82850d
SSL: false
modules: cron,file,gpio,i2c,net,node,rotary,rtctime,sntp,struct,tmr,uart,wifi
build created on 2019-01-16 03:11
powered by Lua 5.1.4 on SDK 2.2.1(6ab97e9)
lua: cannot open init.lua
> print(uart.setup(0, 115200, 8, 0, 1, 1 ))
115200
> dofile("ntpTest.lua")
SNTP time sync successful!
rtctime.get() returns: 0 0 0
> SNTP time sync failed!

Just so that we can "close" this Q here (once you accept the answer). It has to be a function reference rather than a function invocation.
sntp.sync("0.au.pool.ntp.org",
ntpSyncSuccess, -- no (), no parameters
function() -- error callback

Related

Nao robot IMU data rates

I'm trying to stream data from the Nao's inertial unit in its trunk. However the update rate is quite slow ~ 1Hz. Is there any way to improve it? For reference, I issued the following command using qicli to measure the rates:
qicli call --json ALMemory.getListData "[[\"Device/SubDeviceList/InertialSensor/AngleY/Sensor/Value\"]]"
In this example I retrieve the tilt angle of the trunk around the Y-axis (pitch).
To execute this command, I established an SSH connection to the Nao. I timed it using the linux time command. I also tried to force a faster read rate by issuing the above command in a loop with 5 milliseconds of sleep between each iteration:
for i in {1..100}; do qicli call --json ALMemory.getListData "[[\"Device/SubDeviceList/InertialSensor/AngleY/Sensor/Value\"]]"; sleep 0.005; done
But even in this case I could see that the data was read at about a rate of 1Hz.
I tried it on Nao versions 5 and 6. I also connected both over WiFi and a link-locally using an ethernet cable.
This data is available every 10ms, but a qicli call takes a long time to init the connection.
Try using the api in python, create a proxy then call the getData in the loop, refer to the API documentation here.
As a side note, best way to record data or to monitor it efficiently is to process it directly on the NAO. Connect using ssh upload your program and run it, or use choregraphe to create and run it directly on the robot easily.
# edit: adding simple script to be run directly on NAO (untested)
import time
import naoqi
mem = naoqi.ALProxy("ALMemory","localhost",9559)
while 1:
val = mem.getData("Device/SubDeviceList/InertialSensor/AngleY/Sensor/Value")
print(val)
time.sleep(0.01)

Lua script in FreeSWITCH exits bridge immediately when bypass_media = true

How do I make the script wait for the bridge to terminate before continuing when I have "bypass_media" set to true?
This snippet -
freeswitch.consoleLog("err","session before="..tostring(session:ready()).."\n")
session:execute("set","bypass_media=true")
session:execute("bridge","sofia/gateway/carrierb/12345678")
freeswitch.consoleLog("err","session after="..tostring(session:ready()).."\n")
from an audio perspective, it works perfectly with bridge_media set to either true or false, and a wireshark trace shows the audio either passing through (false) or end to end (true).
But with bypass set to true, the script continues without pausing, and the session is no longer ready (session:ready() == false).
The channel seems to go into a hibernate state, but I have housekeeping to do after the bridge is finished which I simply cannot do.
Same happens if i do the bridge in XML dialplan, immediately carries on causing my housekeeping to fire early.
FreeSWITCH (Version 1.6.20 git 43a9feb 2018-05-07 18:56:11Z 64bit)
Lua 5.2
EDIT 1 -
I can get "api_hangup_hook=lua housekeeping.lua" to work, but then I have to pass tons of variables and it fires up a new process/thread/whatever, which seems a little overkill unless that's the only way.
I have a workaround, but would still like an answer to the question if anyone has one (ie how to stop the bridge exiting immediately).
If I set this before the bridge :
session:execute("set","bypass_media=true")
session:execute("set","session_in_hangup_hook=true")
session:execute("set","api_hangup_hook=lua housekeeping.lua "..<vars>)
then "housekeeping.lua" fires when the bridge actually terminates (which is long after the script does).
In housekeeping.lua I can then do :
session:getVariable("billmsec")
and it seems to have the correct values in them, allowing me to do my housekeeping.
My problem with this is the uncertainty of playing with variables from a session that appears to have gone away from a script that fires at some point in the future.
Anyway, it'll have to do until I can find out how to keep control inside the original script.

Why is wifi.sta nil even after wifi.setmode(wifi.STATIONAP)?

EDIT: what I'm trying to do is essentially configure the station after
the softap is running a TCP server.
I get a panic error for wifi.sta being nil when I call wifi.sta.config(station_cfg) even after I configured it properly before.
When I do:
function connectHib()
wifi.setmode(wifi.STATIONAP)
[AP config here]
station_cfg={}
station_cfg.ssid = ""
station_cfg.pwd = ""
station_cfg.save = false
station_cfg.auto = false
wifi.sta.config(station_cfg)
end
It works fine, but when I call it, then start a server with srv=net.createServer(net.TCP) and then call the following function:
function validateSTA()
station_cfg={}
station_cfg.ssid = _G.wifi
station_cfg.pwd = _G.senha
station_cfg.save = false
station_cfg.auto = false
wifi.sta.config(station_cfg) -- this creates an error
wifi.sta.connect()
end
It gives me a PANIC error on the commented line. I'm just trying to reconfigure the STATION module only and then tell it to connect so I can validate the conection.
I'm using:
NodeMCU custom build by frightanic.com
branch: master
commit: 67027c0d05f7e8d1b97104e05a3715f6ebc8d07f
SSL: false
modules: adc,file,gpio,net,node,pwm,sjson,tmr,uart,wifi
build created on 2018-04-16 13:55
powered by Lua 5.1.4 on SDK 2.2.1(cfd48f3)
What bugs me is why it seems like it has not been "declared" before, but it works on the first function... I thought wifi. was global like _G. variables.
It also works if I call the functions separately on the ESPlorer command line on an ESP without my init.lua.
I also tried the debug firmware and the only odd thing I saw poping up was wifi_event_monitor_handle_event_cb that is called every 4 secconds or so.
Thanks guys, any help is apreciated as I'm stuck about a week now.
Like many other script languages, lua doesn't have declarations, only assignments.
You should perform checks what is wifi's value during the first and the second calls. It seems that at first you are using it as a table, and in the second function you try to use it as a string in the station_cfg.ssid = _G.wifi.
Or the reason is that global variables are not "like _G", they're stored in _G.

NodeMCU tmr.alarm always returns false

I have a problem with NodeMCU, trying to start a tmr.alarm on a esp8266.
tmr.alarm never starts the timer, and always returns false.
I've tried changing the timer, and even changing the type of the alarm (AUTO, SINGLE...) but i always have the same result.
Here's part of the code, i'm trying to comunicate with a DS18B20 (OneWire temperature sensor) once every 5 seconds or so.
if not tmr.alarm(1, 5000, tmr.ALARM_AUTO, function()
-- Comunication with the sensor
end)
then print("Comunication with DS18B20 couldn't be started.") end
The output is always
Comunication with DS18B20 couldn't be started.
Don't use the old 0.9.x NodeMCU binaries from https://github.com/nodemcu/nodemcu-firmware/releases they're no longer supported and contain lots of bugs. Build a custom firmware from the dev or master branch.
I'm not aware of any timer bugs in recent versions.

MQTT on ESP8266 with NodeMCU - problems with publishing

I'm building a battery powered IoT device based on ESP8266 with NodeMCU.
I use mqtt to periodically perform measurements and publish results.
I know, that to allow network stack running, I should avoid tight loops and rely on callback functions. Therefore it seemed to me that the right organization of my measurement code should be:
interval=60000000
function sleep_till_next_sample()
node.dsleep(interval)
end
function close_after_sending()
m:close()
sleep_till_next_sample()
end
function publish_meas()
m:publish("/test",result,1,0,close_after_sending)
print("published:"..result)
end
function measurement()
-- The omitted part of the function accesses
-- the hardware and places results
-- in the "result" variable
m = mqtt.Client("clientid", 120, "user", "password")
m:connect("172.19.1.254",1883,0, publish_meas)
end
The init.lua ensures, that the node has connected to the WiFi AP (if not, it retries up to 20 times, and if no connection is established, it puts the node on sleep until the next measurement time).
After WiFi connection is done, it calls the measurement function.
The interesting thing is, that the above code doesn't work. There are no errors displayed in the console, but the mqtt broker does not receive published messages.
To make it working, i had to add additional idle time, by adding timers in the callback functions.
The finally working code looks like below:
interval=60000000
function sleep_till_next_sample()
node.dsleep(interval)
end
function close_after_sending()
m:close()
tmr.alarm(1,500,0,function() sleep_till_next_sample() end)
end
function publish_meas()
m:publish("/test",result,1,0,function() tmr.alarm(1,500,0,close_after_sending) end)
print("published:"..result)
end
function measurement()
-- The omitted part of the function accesses
-- the hardware and places results
-- in the "result" variable
m = mqtt.Client("clientid", 120, "user", "password")
m:connect("172.19.1.254",1883,0, function() tmr.alarm(1,500,0, publish_meas) end)
end
The above works, but I'm not sure if it is optimal. To conserve the battery power I'd like to minimize the time before the node is put on sleep after the measurement is completed and results published.
Is there any better way to chain the necessary calls to m:connect, m:publish, m:close and finally node.dsleep so, that the results are correctly published in the minimal time?
Perhaps this was solved by more recent firmware. I am working through a problem that I thought might be somewhat explained by this issue, so tried to reproduce the problem as described.
My simplified test code is substantially similar; it calls dsleep() from the PUBACK callback of mqtt.Client.publish():
m = mqtt.Client("clientid", 120, "8266test", "password")
m:lwt("/lwt", "offline", 0, 0)
function main(client)
print("connected - at top of main")
m:publish("someval",12345,1,0, function(client)
rtctime.dsleep(SLEEP_USEC)
end)
end
m:on("connect", main)
m:on("offline", function(client) is_connected = false print ("offline") end)
m:connect(MQQT_SVR, 1883, 0, mainloop,
function(client, reason) print("failed reason: "..reason) end)
and when run, does successfully publish to my MQTT broker.
I am using:
NodeMCU custom build by frightanic.com
branch: master
commit: 81ec3665cb5fe68eb8596612485cc206b65659c9
SSL: false
modules: dht,file,gpio,http,mdns,mqtt,net,node,rtctime,sntp,tmr,uart,wifi
build built on: 2017-01-01 20:51
powered by Lua 5.1.4 on SDK 1.5.4.1(39cb9a32)

Resources