ESP8266 Tcp-to-uart with reprogramming ability - esp8266

I'm using this example from nodemcu repo:
uart.setup(0,9600,8,0,1,0)
sv=net.createServer(net.TCP, 60)
global_c = nil
sv:listen(9999, function(c)
if global_c~=nil then
global_c:close()
end
global_c=c
c:on("receive",function(sck,pl) uart.write(0,pl) end)
end)
uart.on("data",4, function(data)
if global_c~=nil then
global_c:send(data)
end
end, 0)
But, since I'm using uart module, I'm no longer able to communicate with my chip via LuaLoader and can not upload updated init.lua files. Instead, I have to put chip into flash-upload mode, then flash initial nodemcu firmware and then my updated init.lua. Too much steps.
How can I retain ability to communicate via LuaLoader? I've tried something like this:
uart.on('data', '\n', handleUartResponse, 0)
...
...
function handleUartResponse(response)
if response == 'flash\n' then
g_flash = true
toggleOutput(true)
uart.write(0, 'flash mode')
elseif response == 'endflash\n' then
g_flash = false
uart.write(0, 'normal mode')
toggleOutput(false)
elseif g_flash then
node.input(response)
else
if g_conn ~= nil then
g_conn:send(response, function(sock)
closeConnection(sock)
g_conn = nil
end)
end
end
end
function toggleOutput(turnOn)
if turnOn then
node.output(nil, 1)
else
node.output(silent, 0)
end
end
It prints flash mode and normal mode in another serial terminal, but it doesn't work in LuaLoader. I think the problem is in uart setup, maybe it should not be \n, but other condition, I don't know what.

Got it! Not sure if it is the best option, since I'm new to lua, but it works.
function handleNormalMode(response)
if response == 'flash\r' then -- magic code to enter interpreter mode
toggleFlash(true)
else -- tcp-to-uart
if g_conn ~= nil then
g_conn:send(response, function(sock)
closeConnection(sock)
g_conn = nil
end)
end
end
end
function ignore(x)
end
function uartSetup(echo)
uart.setup(0, 115200, 8, 0, 1, echo)
end
function toggleFlash(turnOn)
if turnOn then
uart.on('data') -- unregister old callback
uartSetup(1) -- re-configure uart
uart.on('data', 0, ignore, 1) -- this allows lua interpreter to work
node.output(nil) -- turn on lua output to uart
uart.write(0, 'flash mode') -- notify user
else
node.output(ignore, 0) -- turn off lua output to uart
uart.on('data') -- unregister old callback
uartSetup(0) -- re-configure uart
uart.on('data', '\r', handleNormalMode, 0) -- turn on tcp-to-uart
uart.write(0, 'normal mode') -- notify user
end
end
I'm calling toggleFlash(false) at the beginning of script. Then, typing flash\r enters lua interpreter mode and to switch back I'm just typing toggleFlash(false) and it works! That simplifies updating init.lua every time.

Related

Attemp to call a nil value (field ‘ShowInventory’) [ESX2]

I just installed ESX 2 into my new server, im Really new at lua and i dont really know what i should do with some resources or how to start coding
I wan to work in the inventory system based on es_extended, but, it doesnt work.
I press the Inventory Key informed in the cofig file \server-data\resources\es_extended\config\default\config.lua
“Config.InventoryKey = “REPLAY_START_STOP_RECORDING_SECONDARY” – Key F2 by default”
module.InitESX = function()
module.RegisterControl(module.Groups.MOVE, module.Controls[Config.InventoryKey])
module.On('released', module.Groups.MOVE, module.Controls[Config.InventoryKey], function(lastPressed)
print("Comment before show The Inventory")
ESX.ShowInventory()
-- if Menu.IsOpen ~= nil then
-- if (not ESX.IsDead) and (not Menu.IsOpen('default', 'es_extended', 'inventory')) then
-- ESX.ShowInventory()
-- end
-- end
end)
end
I literally change a little bit the code to directly execute the ShowInventory() Function but i got this error
the original code look like this
module.InitESX = function()
module.RegisterControl(module.Groups.MOVE, module.Controls[Config.InventoryKey])
module.On('released', module.Groups.MOVE, module.Controls[Config.InventoryKey], function(lastPressed)
if Menu.IsOpen ~= nil then
if (not ESX.IsDead) and (not Menu.IsOpen('default', 'es_extended', 'inventory')) then
ESX.ShowInventory()
end
end
end)
end
but when i press the key dont do nothing and doesnt show anything in the console.

nodemcu lua dofile - how to invoke another lua file?

I have a working init.lua on my nodemcu esp8266:
-- load credentials, 'SSID' and 'PASSWORD' declared and initialize in there
dofile("credentials.lua")
function startup()
if file.open("init.lua") == nil then
print("init.lua deleted or renamed")
else
print("Running")
file.close("init.lua")
-- the actual application is stored in 'application.lua'
-- dofile("application.lua")
end
end
print("Connecting to WiFi access point...")
wifi.setmode(wifi.STATION)
wifi.sta.config(SSID, PASSWORD)
-- wifi.sta.connect() not necessary because config() uses auto-connect=true by default
tmr.create():alarm(1000, tmr.ALARM_AUTO, function(cb_timer)
if wifi.sta.getip() == nil then
print("Waiting for IP address...")
else
cb_timer:unregister()
print("WiFi connection established, IP address: " .. wifi.sta.getip())
print("You have 3 seconds to abort")
print("Waiting...")
tmr.create():alarm(3000, tmr.ALARM_SINGLE, startup)
end
end)
It runs without errors and the wireless connection is established.
Now I have written a second bme280_mqtt.lua that I want to run automatically:
alt=45 -- altitude of the measurement place
bme280.init(3, 4)
P, T = bme280.baro()
-- convert measure air pressure to sea level pressure
QNH = bme280.qfe2qnh(P, alt)
ldk=string.format("Ld=%d.%03d ", QNH/1000, QNH%1000)
H, T = bme280.humi()
if T<0 then
temp=string.format("T=-%d.%02d°C ", -T/100, -T%100)
else
temp=string.format("T=%d.%02d°C ", T/100, T%100)
end
luftf=string.format("Lf=%d%% ", H/1000, H%1000)
D = bme280.dewpoint(H, T)
if D<0 then
taupu=string.format("Tp=-%d.%02d°C ", -D/100, -D%100)
else
taupu=string.format("Tp=%d.%02d°C ", D/100, D%100)
end
m = mqtt.Client("wetterstation", 120)
m:connect("192.168.1.116", 1883)
m:publish("wetterstation",temp .. taupu .. luftf .. ldk,0,0)
node.dsleep(10*1000000)
Called by hand in ESPlorer via Send to ESP Button everything works fine.
But with
dofile(bme280_mqtt.lua)
I get:
dofile('bme280_mqtt.lua')
bme280_mqtt.lua:25: not connected
stack traceback:
[C]: in function 'publish'
bme280_mqtt.lua:25: in main chunk
[C]: in function 'dofile'
stdin:1: in main chunk
What is the mistake here? And how do I call the bme280_mqtt.lua from init.lua correctly?
Kind regards
how do I call the bme280_mqtt.lua from init.lua correctly?
You do invoke it correctly.
bme280_mqtt.lua:25: not connected
Means that there's an error on/from line 25 from bme280_mqtt.lua.
I didn't count the lines but the problem is right here
m:connect("192.168.1.116", 1883)
m:publish("wetterstation",temp .. taupu .. luftf .. ldk,0,0)
You can only publish once the connection to the broker was established. Look at the example at http://nodemcu.readthedocs.io/en/latest/en/modules/mqtt/#example. You can either use the callback function in the connect function to publish or register an on-connect event handler before you call connect like so:
m:on("connect", function(client)
-- publish here
end)

Computercraft bundled cable program not responding

After several revisions, my Lua program still refuses to do anything.
--Let's Go!
--Program Infos
--Mappings
--Pink: Gate 1
--Red: East Tower 2
--Orange: West Tower 3
--Lime: Armoury 4
--Blue: Master Bedroom 5
--Grey: Guest Bedroom 6
--Cyan: Power Generation 7
--arbitrary variables
-- c is the variable for adding and subtracting. keeps track of what is CURRENTLY ACTIVE.
--Beginning values
--Start out with listening for arguments
local args = {...}
arg1=args[1]
arg2=args[2]
--Where are our outputs?
local towere = colors.red
local towerw = colors.orange
local gate = colors.pink
local armoury = colors.lime
local mstr = colors.blue
local guest = colors.grey
local power = colors.cyan
--bundled outputs
local output = "right"
-- ADD AND SUBTRACT MAKE LIFE EASIER CODE
--Courtesy of #Kingdaro on Computercraft Fourm (adapted for practical use in project)
--Original Link: http://www.computercraft.info/forums2/index.php?/topic/7641-redpower-bundled-cable/
--How to close a door
function close(door)
local input = rs.getBundledOutput("right")
rs.setBundledOutput("right", colors.combine(input, door))
end
function open(door)
local input = rs.getBundledOutput("right")
rs.setBundledOutput("right", colors.subtract(input, door))
end
--Make a good base for closing/opening things
--Basically, Functions Galore.
--GATE CONTROLS
function gateclose()
rs.setOutput(top, true)
wait(1)
rs.setOutput(top, false)
close(colors.pink)
end
function gateopen()
open(colors.pink)
end
--Beef of the program
--Start out with all doors open
if args[1] == gate and args[2] == open then --if the command is gate open
gateopen()
elseif args[1] == gate and args[2] == close then --if the command is gate close
gateclose()
end
I've tried and tried, but still, no response. I have the setup (physically, if you could call it that) correct (the bundled cable is on the right) and no error messages, but when run with the 'gate close' arguments, no response from the wires.
Any suggestions? Thanks!
Most probably you want to compare string:
if args[1] == "gate" and args[2] == "open" then --if the command is gate open
gateopen()
elseif args[1] == "gate" and args[2] == "close" then --if the command is gate close
gateclose()
end

Why would this script not work?

The following script breaks between print("2") and print("3") because it cannot find the variable "tag". How would I fix this?
local Humanoid = script.Parent.Zombie -- Or Zombie Or Whatever
function PwntX_X()
print("1")
local tag = Humanoid:findFirstChild("creator")
print("2")
if tag ~= nil then
print("3")
if tag.Value ~= nil then
print("4")
local Leaderstats = tag.Value:findFirstChild("leaderstats")
print("5")
if Leaderstats ~= nil then
print("6")
Leaderstats.Cash.Value = Leaderstats.Cash.Value + 5
print("7")
wait(0.1)`enter code here`
script:remove()
end
end
end
end
Humanoid.Died:connect(PwntX_X)
I already have a script for the leaderboard that works 100%. This script is being used for a game called "ROBLOX". Thanks!
Alright, first off, scriptinghelpers.org was created as a service similar to stackoverflow specifically for Roblox, I suggest next time, you ask there, now on to stuff;
-- If you have further problems, My Roblox username is 'ZeroBits' (REMOVE THIS LINE)
DEBUG = true -- Debug Print, so you can disable it when you're done.
local function print_D(t)
if DEBUG == true then warn(t) end end
print_D("DEBUG MODE, Switch Debug Value to False when finished")
local Humanoid = script.Parent:FindFirstChild("Zombie") -- We'll use FindFirstChild() here
--if not Humanoid then -- Uncomment this statement if you want it to affect objects named Humanoid as well
-- Humanoid = script.Parent:FindFirstChild("Humanoid")
--end
function HumanoidKilled() -- Renamed the function to be a little less cringeworthy
print_D("1") -- switched these print statements with the Print_D() function
local tag = Humanoid:FindFirstChild("creator") -- Capitalized the first letter in FindFirstChild()
print_D("2")
if not tag then
warn("No Tag Found check Humanoid and weapon script") --if this prints, there's either no tag, or a serious problem, and you should check the humanoid object for a tag, or make sure the weapons you use actually generate tags.
else -- changed 'if tag ~= nil then' to 'if not tag then 'do stuff' else' to simplify the code, and add an else statement early on.
print_D("3")
if tag.Value then -- removed '~= nil' because it's just useless clutter
print_D("4")
local Leaderstats = tag.Value:findFirstChild("leaderstats")
print_D("5")
if Leaderstats ~= nil then
print_D("6")
Leaderstats.Cash.Value = Leaderstats.Cash.Value + 5
print_D("7")
wait(0.1)
script:Destroy() -- switched remove() to Destroy(), remove() is deprecated
end
end
end
end
Humanoid.Died:connect(HumanoidKilled)
This fixes all the problems in the script, and makes it more efficient. if there are still problems, it's either in the tag creation script, the tags aren't stored in the humanoid, or the tags aren't named 'creator'
also, I switched over the print statements to a print_D function, which uses warn() rather than print() there's almost no difference, except that the debug text will appear yellow in the console, rather than white.
script is being used for a game called "ROBLOX". Thanks!
It's for a game On Roblox, not a game called Roblox, what you said is akin to saying; I made this mod for Source Engine, when you actually made the mod for Half-Life 2

how do you properly use a pipe with lua to get the output of a program?

I am using Lua with the luaposix library to get the the output of some commands, and sometimes send some too. I am using this code, or variants of this to do my work, but I sometimes get stuck at posix.wait(cpid) or sometimes the command doesn't seem to finish.
-- returns true on connected, else false
function wifi.wpa_supplicant_status()
-- iw dev wlan0-1 link
local r,w = posix.pipe()
local cpid = posix.fork()
if cpid == 0 then --child writes to pipe
--close unused read end
local devnull = posix.open("/dev/null", posix.O_RDWR)
posix.close(r)
posix.dup2(devnull, 0)
posix.dup2(w, 1)
posix.dup2(devnull, 2)
local dir = wifi.wpa_supplicant_dir()
local iface = posix.basename(dir)
iface = string.gsub(iface, "wpa_supplicant%-",'')
posix.exec('/usr/sbin/iw', {'dev', iface, 'link'})
posix._exit(-1)
elseif cpid > 0 then
--parent reads from pipe, close write end
posix.close(w)
local buf = ''
while true do
local tmp = posix.read(r, 100)
if tmp ~= nil and #tmp > 0 then
buf = buf .. tmp
else
break
end
end
-- TODO, check exit value, to see if entry exists or not
while posix.wait(cpid) ~= cpid do print("waiting in wpa_supplicant_status") end
print("status is "..buf)
if string.find(buf, "Connected to", 1, true) then
return true
else
return false
end
end
end
This is what I understand what I have to do(to just get output):
create a single pipe
fork
if child,
close read end of pipe
dup2(write_end, stdout)
exec() to desired process
if parent
close write end of pipe
do blocking reads to read end of pipe, till you get a 0 byte read, which means the child process has terminated, closing the pipe
Am I missing something?
You should have a look at the answers in this question How do you construct a read-write pipe with lua?
to get an idea of the difficulties to implement this. One thing that strikes me is that nobody seems to be able to get it to work with only one child process.
However, In the example you give, it seems you only want to get the output of the command, so I would suggest simply doing this:
function os.capture(cmd)
local f = assert(io.popen(cmd, 'r'))
local s = assert(f:read('*a'))
f:close()
return s
end
function wifi.wpa_supplicant_status()
local dir = wifi.wpa_supplicant_dir()
local iface = posix.basename(dir):gsub("wpa_supplicant%-",'')
local cmd = ('/usr/sbin/iw dev %s link'):format(iface)
local buf = os.capture(cmd)
return buf:find("Connected to", 1, true) ~= nil
end
This is not even tested, but you should get the idea.

Resources