I am trying to build this project:
https://www.instructables.com/id/Motorized-WiFi-IKEA-Roller-Blind/
having had some problems and still do...
this is my wifi_setup.lau
-- file: setup.lua
local module = {}
config = {}
config.SSID = {}
config.SSID["ssid"] = "password"
function wifi_wait_ip()
if wifi.sta.getip() == nil then
print("IP unavailable, Waiting...")
else
tmr.stop(1)
print("\n====================================")
print("ESP8266 mode is: " .. wifi.getmode())
print("MAC address is: " .. wifi.ap.getmac())
print("IP is " .. wifi.sta.getip())
print("====================================")
end
end
function wifi_start(list_aps)
if list_aps then
for key, value in pairs(list_aps) do
if config.SSID and config.SSID[key] then
wifi.setmode(wifi.STATION);
wifi.sta.config{ssid=key, pwd=config.SSID[key]}
--wifi.sta.connect()
print("Connecting to " .. key .. " ...")
tmr.alarm(1, 2500, 1, wifi_wait_ip)
end
end
else
print("Error getting AP list")
end
end
function module.start()
print("Configuring Wifi ...")
wifi.setmode(wifi.STATION);
wifi.sta.getap(wifi_start)
end
return module
But this is the output:
Configuring Wifi ...
> Connecting to ssid ...
PANIC: unprotected error in call to Lua API (wifi_setup.lua:29: attempt to call field 'alarm' (a nil value))
So anything is wrong with the -String
What can I do?
Thank You Ben for the Hint. I think I managed to correct the problem. For anyone else looking for it - and I hope I coded correctly - here the solution:
`{ -- file: setup.lua
local module = {}
config = {}
config.SSID = {}
config.SSID["ssid"] = "password"
-- create a timer object
local tObj = tmr.create()
-- register an alarm
function wifi_wait_ip()
if wifi.sta.getip() == nil then
print("IP unavailable, Waiting...")
else
--tmr.stop(1)
tObj:unregister()
print("\n====================================")
print("ESP8266 mode is: " .. wifi.getmode())
print("MAC address is: " .. wifi.ap.getmac())
print("IP is " .. wifi.sta.getip())
print("====================================")
end
end
function wifi_start(list_aps)
if list_aps then
for key, value in pairs(list_aps) do
if config.SSID and config.SSID[key] then
wifi.setmode(wifi.STATION);
wifi.sta.config{ssid=key, pwd=config.SSID[key]}
--wifi.sta.connect()
print("Connecting to " .. key .. " ...")
--tmr.create(1, 2500, 1, wifi_wait_ip)
tObj:alarm(2000, tmr.ALARM_AUTO, wifi_wait_ip)
end
end
else
print("Error getting AP list")
end
end
function module.start()
print("Configuring Wifi ...")
wifi.setmode(wifi.STATION);
wifi.sta.getap(wifi_start)
end
return module`
Related
function SearchDatabase(ply, value)
local id = ply:SteamID()
if id == nil then return end
local query = ECLIPSEUSERDATA:query("SELECT " .. value .. " FROM main WHERE usersteamid = '" .. id .. "';")
if not query then return end
query.onData = function(q, d)
if(#query:getData() >= 1)then
print("[SQL]" .. value .. " = " .. tostring(d[value]))
print(tostring(d[value]))
return tostring(d[value])
end
end
query.onError = function(db, err)
print("[SQL] Failed to search database - Error: ", err)
end
query:start()
query:wait()
end
function UpdatePlaytime(ply)
if ply == nil then
return
end
local PlayersPlaytime = SearchDatabase(ply, "playtime")
print(PlayersPlaytime)
local PlaytimeUpdate = PlayersPlaytime + 1
end
The problem i'm currently having is when the value: d[value], is returned to my function UpdatePlaytime() function it is returning a nil value and I have no idea how to fix it.
Console logs:
[SQL]playtime = 0
0
nil
Any help will appreciated thanks!
-D12
I am trying to make a "shell" in lua.
But the main problem is, I can not define the variable name from user input.
Here is the core of what I currently have. I am having an issue with the what[2] = what[3] line with the comment below.
How can I better implement this?
function lsplit(inputstr, sep)
if sep == nil then
sep = "%s"
end
local t={} ; i=1
for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
t[i] = str
i = i + 1
end
return t
end
function def(what)
if (what[1] == "end") then
os.exit(0)
elseif (what[1] == "help") then
print("Commander version 0.0")
elseif (what[1] == "var") then
what[2] = what[3] --Can not define
else
print("[ERR] not a command!")
end
end
while(true) do
io.write("-->")
local usr = io.read("*l")
local cmd = lsplit(usr, " ")
def(cmd)
end
you are overwriting you first parameter with you second one, and not creating a new var... try this code! Should work but it is untested!
local userdefinedVars = { }
function lsplit(inputstr)
words = {}
for word in s:gmatch("%w+") do
table.insert(words, word)
end
end
function def(what)
if (what[1] == "end") then
os.exit(0)
elseif (what[1] == "help") then
print("Commander version 0.0")
elseif (what[1] == "var") then
-- This is how you get your things done!
userdefinedVars[what[2]] = what[3]
else
print("[ERR] not a command!")
end
end
while(true) do
io.write("--> ")
local usr = io.read("*line")
local cmd = lsplit(usr)
def(cmd)
end
I have a completely working esp chip that connects to wifi and creates a server. When I send it an OTA command, it runs a function that downloads a file using a socket connection.
This is the upgrader.lua that I am using:
--------------------------------------
-- Upgrader module for NODEMCU
-- LICENCE: http://opensource.org/licenses/MIT
-- cloudzhou<wuyunzhou#espressif.com> - Heavily modified by aschmois
--------------------------------------
--[[
update('file.lua', 'http://IP.ADRESS/path/file.lua')
]]--
local header = ''
local isTruncated = false
local function save(filename, response)
if isTruncated then
file.write(response)
return
end
header = header..response
local i, j = string.find(header, '\r\n\r\n')
if i == nil or j == nil then
return
end
prefixBody = string.sub(header, j+1, -1)
file.write(prefixBody)
header = ''
isTruncated = true
return
end
----
function update(filename, url, cn)
local tmpError = nil
local running = true
local error = nil
local success = false
print("Downloading from: " .. url)
local ip, port, path = string.gmatch(url, 'http://([0-9.]+):?([0-9]*)(/.*)')()
if ip == nil then
return false
end
if port == nil or port == '' then
port = 80
end
port = port + 0
if path == nil or path == '' then
path = '/'
end
print("-- Detailed Connection Info --")
print("IP: ".. ip)
print("Port: ".. port)
print("Path: ".. path)
print("-- END --")
local function timeout()
error = tmpError
file.remove(filename)
conn:close()
running = false
end
conn = net.createConnection(net.TCP, false)
conn:on('connection', function(sck, response)
tmr.stop(1)
file.open(filename, 'w')
conn:send('GET '..path..' HTTP/1.0\r\nHost: '..ip..'\r\n'..'Connection: close\r\nAccept: */*\r\n\r\n')
tmpError = "READ TIMEOUT"
tmr.alarm(1, 10000, 0, timeout)
end)
conn:on('receive', function(sck, response)
tmr.stop(1)
tmpError = "READ(2) TIMEOUT"
tmr.alarm(1, 10000, 0, timeout)
print(response)
save(filename, response)
end)
conn:on('disconnection', function(sck, response)
tmr.stop(1)
local function reset()
local list = file.list()
for k,v in pairs(list) do
if(filename == k) then
if(v == 0) then
success = false
file.close()
file.remove(filename)
else
file.close()
success = true
end
end
end
print(header)
header = ''
isTruncated = false
if(success) then
print(filename..' saved')
else
print("Could not download `".. filename.."`")
end
running = false
end
tmr.alarm(0, 2000, 0, reset)
end)
conn:connect(port, ip)
tmpError = "CONN TIMEOUT"
tmr.alarm(1, 10000, 0, timeout)
tmr.alarm(2, 1000, 1, function()
if(running == false) then
tmr.stop(2)
local buf = ''
if(success) then
buf = buf.."HTTP/1.1 200 OK\r\nServer: WiFi Relay\r\nContent-Type: text/plain\r\n\r\n"
buf = buf.."1"
else
buf = buf.."HTTP/1.1 500\r\nServer: WiFi Relay\r\nContent-Type: text/plain\r\n\r\n"
buf = buf.."0"
buf = buf.."\n"
if(error ~= nil) then
buf = buf..error
else
buf = buf.."UNKNOWN ERROR"
end
end
cn:send(buf)
cn:close()
end
end)
return true
end
As a test I am sending it: filename = rz.lua and url = http://192.168.1.132/rz.lua. The cn variable is the connection to send back information to the client.
The esp chip prints:
Downloading from: http://192.168.1.132/rz.lua
-- Detailed Connection Info --
IP: 192.168.1.132
Ò_ÇRöfJSúfÊÃjêÐÿ (junk reset data)
The problem seems to be connected with the conn:send() command. If it's inside the on connect function it resets. If it's outside, I will get a read timeout (since on read is never called). I really have no idea what else to do.
This is the ESP firmware info:
NodeMCU custom build by frightanic.com
branch: master
commit: 93421f2702fb02ce169f82f96be7f2a8865511e1
SSL: false
modules: node,file,gpio,wifi,net,tmr,uart
You are resetting. The "junk" is a BootROM message at the wrong baud rate.
Don't do a send followed by a close in the same callback. Use an on('sent', ... ) to trigger the close. So the 21 line body of your alarm 2 callback would be better written:
local response = "HTTP/1.1 200 OK\r\nServer: WiFi Relay\r\nContent-Type: text/plain\r\n\r\n%s"
cn:send(response:format(success and "1" or ("0\n\r" .. (error or "UNKNOWN ERROR")))
cn:on('sent', function(cn) cn:close() end)
On that note your 27 line disconnect callback would be better written:
tmr.stop(1)
tmr.alarm(0, 2000, 0, function()
local len = file.list()(filename)
success = len and len > 0
file.close()
if not success then file.remove(filename)
file.flush()
end)
Note that it's always wise to flush the SPIFFS after writing or removing files.
You use a standard pattern, so why not encapsulate it:
local conn = net.createConnection(net.TCP, false)
local function setTimeout(reason)
-- tmr.stop(1) -- not needed is the next line resets the alarm
tmr.alarm(1, 10000, 0, function ()
-- you don't need tmpError as reason is a local and bound as an upval
error, running = reason, false
file.remove(filename) file.flush()
return conn:close()
end)
end
I could go on but I leave this to you. With a little thought, your code would be a third of the size and more readable.
I can't be sure but the problem seems to have been a memory error (weird since there was no panic) so this is what I did to fix it:
local request = table.concat({"GET ", path,
" / HTTP/1.1\r\n",
"Host: ", ip, "\r\n",
"Connection: close\r\n",
"Accept: */*\r\n",
"User-Agent: Mozilla/4.0 (compatible; esp8266 Lua;)",
"\r\n\r\n"})
conn = net.createConnection(net.TCP, false)
conn:on('connection', function(sck, response)
tmr.stop(1)
tmpError = "READ TIMEOUT"
tmr.alarm(1, 10000, 0, timeout)
conn:send(request)
end)
I created the request using the table.concat method and using a table instead of one big string. Hopefully this will help those in need.
Okay I am working on a script for my Oxide Lua Plugin, and I am also just learning Lua Script so I am not real sure how to do this.
-- *******************************************
-- Broadcasts a Server Notification
-- *******************************************
function PLUGIN:cmdNotice( netuser, args )
table.concat(args," ")
local allnetusers = rust.GetAllNetUsers()
if (allnetusers) then
for i=1, #allnetusers do
local netuser = allnetusers[i]
rust.Notice(netuser, args[1]))
rust.SendChatToUser(netuser, "Message Sent:" .. args[1])
end
end
end
What I am trying to do is fix this so I do not have to manually encase my notice in "".
For example, as the code stands, while I am in game in rust if I use the /notice command I have two outcomes.
Example 1
/notice hello everone
will only produce
hello
but if I do
/notice "hello everyone"
will give the entire message. So I am a little confused.
So my new code should look like this
-- *******************************************
-- Broadcasts a Server Notification
-- *******************************************
function PLUGIN:cmdNotice( netuser, args )
table.concat(args," ")
local allnetusers = rust.GetAllNetUsers()
if (allnetusers) then
for i=1, #allnetusers do
local netuser = allnetusers[i]
rust.Notice(netuser, table.concat(args, " " ))
rust.SendChatToUser(netuser, "Message Sent:" .. table.concat(args, " "))
end
end
end
Edit 3/15/2014
Okay cool so in a since I can also do this as well correct?
function PLUGIN:cmdNotice( netuser, args )
if (not args[1]) then
rust.Notice( netuser, "Syntax: /notice Message" )
return
end
local allnetusers = rust.GetAllNetUsers()
if allnetusers then
for i=1, #allnetusers do
local netuser = allnetusers[i]
local notice_msg = table.concat(args," ")
rust.Notice(netuser, notice_msg)
rust.SendChatToUser(netuser, "Message Sent:" .. notice_msg)
end
end
end
To clarify what #EgorSkriptunoff said, table.concat returns the joined table, but it does not change the value of args. Since you don't save the joined return value, your line 1 inside the function is useless. As an alternative to his approach, you could do rust.SendChatToUser ( netuser, "Message Sent:" .. table.concat(args, " " ).
My guess is that you were thinking (?) that the joined strings would be saved in the args table as the first item in the table? That's not what happens. The table itself remains unchanged, so when you print args[1], you get only the first string of the array. It "works" when you quote the message because in that case the entire message goes in as one thing, and the array only has an arg[1].
Here's what is going on
t = { "hello", "I", "must", "be", "going"}
-- Useless use of concat since I don't save the return value or use it
table.concat(t, " ")
print(t) -- Still an unjoined table
print(t[1]) -- Prints only "hello"
print(table.concat(t, " ")) -- Now prints the return value
Edit: In response to the follow-up question, see my comments in the code below:
function PLUGIN:cmdNotice( netuser, args )
table.concat(args," ") -- This line is not needed.
local allnetusers = rust.GetAllNetUsers()
-- Lua doesn't count 0 as false, so the line below probably doesn't do
-- what you think it does. If you want to test whether a table has more
-- than 0 items in it, use this:
-- if #allnetusers > 0 then...
if allnetusers then
for i=1, #allnetusers do
local netuser = allnetusers[i]
rust.Notice(netuser, table.concat(args, " " ))
rust.SendChatToUser(netuser, "Message Sent:" .. table.concat(args, " "))
end
end
end
I'v tested & uploaded my app on appStore it's inapp purchases was working perfectly fine, I was able to restore the app too.
But now I want to test it's version 2 but now am able to buy but restore isn't working.
module(..., package.seeall)
require("store")
require("ui")
local inappfile = require("inappfile")
local validProducts, invalidProducts = {}, {}
local listOfProducts =
{
-- These Product IDs must already be set up in your store
-- We'll use this list to retrieve prices etc. for each item
-- Note, this simple test only has room for about 4 items, please adjust accordingly
-- The iTunes store will not validate bad Product IDs
"com.tinytapps.pandamath.fullpack",
}
-------------------------------------------------
-- we store everything inside this group at the end
local newActivity = display.newGroup()
-----------------------------------------------------
---------------- IN APP CODE STARTS HERE ------------------
checkIfPurchased = function()
local filePath = system.pathForFile( "purchased.txt", system.DocumentsDirectory )
local file = io.open( filePath, "r" )
if file then
_G["isPurchased"] = true
--AdMediator.hide()
else
_G["isPurchased"] = false
--local_configuration()
end
end
callforpurchase = function()
if _G["isPurchased"] == false then
local cerateFile = function()
_G.noOfQuestionCompleted=0
local filePath = system.pathForFile( "purchased.txt", system.DocumentsDirectory )
local file = io.open( filePath, "r" )
print(file)
if file then
_G["isPurchased"] = true
io.close( file )
else
file = io.open( filePath, "w" )
_G["isPurchased"] = true
io.close( file )
end
end
function showTitle()
if isSimulator then
local myAlert = native.showAlert( "iTunes Store not available in Corona Simulator",
"Offline testing: see console for output.",
{ "OK" } )
end
end
-------------------------------------------------------------------------------
-- Product IDs should match the In App Purchase products set up in iTunes Connect.
-- We cannot get them from the iTunes store so here they are hard coded;
-- your app could obtain them dynamically from your server.
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
-- Process and display product information obtained from store.
-- Constructs a button for each item
-------------------------------------------------------------------------------
function unpackValidProducts()
local buttonSpacing = 5
-- Utility to build a buy button
-- Handler for buy button
function newBuyButton (index)
local buttonDefault = "add/buybtn.png"
local buttonOver = "add/buybtn.png"
local buyThis = function ( product )
print ("Purchasing " ..product)
-- Purchase the item
if store.canMakePurchases then
store.purchase( {product} )
else
native.showAlert("Store purchases are not available, please try again later",
{ "OK" } )
end
end
function buyThis_closure ( index )
-- Closure wrapper for buyThis() to remember which button
return function ( event )
buyThis (validProducts[index].productIdentifier)
return true
end
end
local hideDescription = function ( )
--descriptionArea.text = "Select a product..."
end
local describeThis = function ( description )
print ("About this product: " ..description)
end
function describeThis_closure ( index )
-- Closure wrapper for describeThis() to remember which button
return function ( event )
describeThis (validProducts[index].description)
return true
end
end
buyButton = ui.newButton{
default = buttonDefault, over = buttonOver,
onPress = describeThis_closure (index), onRelease = buyThis_closure (index),
}
_G.buyButton=buyButton
return buyButton
end
-- Utility to build a restore button
function newRestoreButton ()
local buttonDefault = "add/restorebtn.png"
local buttonOver = "add/restorebtn.png"
local restore = function ( product )
-- Ask the iTunes Store to initiate restore transaction sequence
print ("Restoring " )
store.restore()
end
local hideDescription = function ( )
--descriptionArea.text = "Select a product..."
end
local describeThis = function ()
-- Display info in description area
print ("Test restore feature")
end
--local label = "Test restore"
restoreButton = ui.newButton{
default = buttonDefault, over = buttonOver,
onPress = describeThis, onRelease = restore,
}
_G.restoreButton = restoreButton
return restoreButton
end
print ("Loading product list")
if not validProducts then
native.showAlert( "In App features not available", "initStore() failed", { "OK" } )
else
print ("Product list loaded")
print( "Country: " .. system.getPreference( "locale", "country" ) )
local buttonSpacing = 5
print( "Found " .. #validProducts .. " valid items ")
-- display the valid products in buttons
for i=1, #validProducts do
-- Debug: print out product info
print ("Item " .. i .. ": " .. validProducts[i].productIdentifier
.. " (" .. validProducts[i].price .. ")")
print (validProducts[i].title .. ", ".. validProducts[i].description)
---------------------------------------------------------------------------
-- create and position product button
local myButton = newBuyButton(i)
myButton.x = 570 --centerX - 200
myButton.y = 450 --centerY + 250
--myButton.xScale = 0.6
--myButton.yScale = 0.6
--newActivity:insert(buyButton)
myButton:toFront()
end
local restoreButton = newRestoreButton()
restoreButton.x = 200 --centerX + 200
restoreButton.y = 450 -- centerY + 250
--restoreButton.xScale = 0.6
--restoreButton.yScale = 0.6
--newActivity:insert(restoreButton)
restoreButton:toFront()
for i=1, #invalidProducts do
-- Debug: display the product info
native.showAlert( "Item " .. invalidProducts[i] .. " is invalid.",
{ "OK" } )
print("Item " .. invalidProducts[i] .. " is invalid.")
end
end
end
-------------------------------------------------------------------------------
-- Handler to receive product information
-- This callback is set up by store.loadProducts()
-------------------------------------------------------------------------------
function loadProductsCallback( event )
-- Debug info for testing
print("In loadProductsCallback()")
print("event, event.name", event, event.name)
print(event.products)
print("#event.products", #event.products)
io.flush() -- remove for production
-- save for later use
validProducts = event.products
invalidProducts = event.invalidProducts
unpackValidProducts ()
end
-------------------------------------------------------------------------------
-- Handler for all store transactions
-- This callback is set up by store.init()
-------------------------------------------------------------------------------
function transactionCallback( event )
local infoString
print("transactionCallback: Received event ", event.name)
if event.transaction.state == "purchased" then
cerateFile()
_G["isPurchased"] = true
--AdMediator.hide()
if buyButton ~= nil then
buyButton=nil
end
if restoreButton ~= nil then
restoreButton=nil
end
infoString = "Transaction successful!"
print (infoString)
inappfile.onClose()
print("transactionCallback() method called inappfile.onClose()")
elseif event.transaction.state == "restored" then
print ("Success! Product restored")
cerateFile()
_G["isPurchased"] = true
if buyButton ~= nil then
buyButton=nil
end
if restoreButton ~= nil then
restoreButton=nil
end
infoString = "Transaction successful!"
print (infoString)
inappfile.onClose()
print("transactionCallback() method called inappfile.onClose()")
elseif event.transaction.state == "cancelled" then
infoString = "Transaction cancelled by user."
elseif event.transaction.state == "failed" then
infoString = "Transaction failed, type: ",
event.transaction.errorType, event.transaction.errorString
else
infoString = "Unknown event"
end
-- Tell the store we are done with the transaction.
-- If you are providing downloadable content, do not call this until
-- the download has completed.
store.finishTransaction( event.transaction )
end
-------------------------------------------------------------------------------
-- Setter upper
-------------------------------------------------------------------------------
function setupMyStore (event)
store.loadProducts( listOfProducts, loadProductsCallback )
print ("After store.loadProducts, waiting for callback")
if isSimulator then
-- No Store, so no callbacks, so exercise our GUI "manually"
validProducts[1] = {}
validProducts[1].title = "Panda Math"
validProducts[1].description = "A wonderful product of Math for testing"
validProducts[1].price = 1.99
validProducts[1].productIdentifier = "com.tinytapps.pandamath.full"
unpackValidProducts()
end
end
-------------------------------------------------------------------------------
-- Main
-------------------------------------------------------------------------------
-- Show title card
showTitle ()
-- Connect to store at startup
store.init (transactionCallback )
print ("After init")
-- Hide title card, run store
timer.performWithDelay (1000, setupMyStore)
end
end