Post your best Lua script examples here

User avatar
By Musti
#11781 Hi folks,

I have put together a simple setup to capture the data from a number of analog channels on Arduino, send the data over to ESP running nodemcu lua and display raw values on the web server and change the color of WS2812B LEDs, one per analog input channel.

ESP and Arduino are connected over serial, with LUA command interface present on the serial. Arduino simply changes the variable through the command interface every 50ms. ESP then based on the value changes the color of the LED and shows data on the web interface, which is auto refreshed ever second.

Firmware from this thread: viewtopic.php?f=21&t=1143 (until WS2812B support is in the official build)

Arduino code, simply enter the channels you wish to measure in the array:
Code: Select allchar rssi_channels[]={A0,A1,A2,A5,A12,A13,A14,A15,A6};

void setup(){
  delay(500);
  //make sure the baudrate is the same as defined on ESP
  Serial.begin(115200);
}

void loop(){
  Serial.print("arr={");
  for(char i=0;i<sizeof(rssi_channels);i++){
    Serial.print(analogRead(rssi_channels[i]));
    Serial.print(",");
  }
  Serial.println("0}");
  delay(50);
}


ESP code is split into several functions.

For development and easier recovery from failed scripts (manually send timer stop), there is a 3s delay before custom code is initiated:
init.lua
Code: Select all--setup baudrate
uart.setup(0,115200,8,0,1)
--3s delay before starting with the program, sufficient break execution if needed
tmr.alarm(0,3000,0,function() dofile("init2.lua") end)

The actual init for the program is thus in
init2.lua
Code: Select all--custom application init
uart.setup(0,115200,8,0,1)
--define the variable received from arduino
arr={0,0,0,0,0,0,0,0,0}
--update leds every 50ms
tmr.alarm(0,50,1,function() dofile("led.lua") end)
--start webserver
dofile("webserver.lua")


LEDs are controlled from a separate script called from init2 every 50ms. There is a really simple function just changing the color based on the value, with 3 colors possible. This will/should be upgraded to proper color scale encoding.
led.lua
Code: Select all--colormapping function from single value to rgb
function colormap (v)
      r=0
      g=0
      b=0
   if v>1000 then
      r=led_range
   elseif v>500 then
      g=led_range
   elseif v>100 then
      b=led_range
   end
   return string.char(g, r, b)
end

--create an empty string
led_string=""
--set brightness of LED
led_range=100
--concatenate grb values in to this string for WS2812B
for i,v in ipairs(arr) do
   led_string=led_string .. colormap(v)
end
--send to WS2812B
ws2812.write(3, led_string)


Finally, the webserver is defined to print out all elements of variable arr:

webserver.lua
Code: Select allsrv=net.createServer(net.TCP)
srv:listen(80,function(conn)
   conn:on("receive",function(conn,payload)
   --print(payload) -- for debugging only
   strstr={string.find(payload,"GET / HTTP/1.1")}
   if(strstr[1]~=nil)then
   --generate the measurement string from arr list of measurements
   --create an empty string
   values_string="Measurements:"
   for i,v in ipairs(arr) do
      --concatenate measurements into a string
      values_string=values_string .. v .. " "
   end
   --generates HTML web site, autorefreshes at 1s interval, prints measurements
   conn:send('HTTP/1.1 200 OK\r\nConnection: keep-alive\r\nCache-Control: private, no-store\r\n\r\n\
   <!DOCTYPE HTML>\
   <html><head><meta content="text/html;charset=utf-8"><title>ESP8266 Arduino analog measurements</title><meta http-equiv="refresh" content="1" /></head>\
   <body bgcolor="#ffe4c4"><h2>'..values_string..'</h2>') end
   conn:on("sent",function(conn) conn:close() end)
    end)
end)


Advice, thoughts how to make better and more efficient are welcome, but this simplified example should help a few people get started. If anyone has a good solution or would like to help code a good color mapping function to display one numerical value as rgb, check out: https://github.com/FastLED/FastLED/wiki ... HSV-Colors
User avatar
By Musti
#11852 ESP does not directly read the serial commands, but continuously reads the variable, which happens to be updated over serial. This works as following:

Arduino periodically sends the following string (values are randomly chosen for the example): arr={1234,4213,243,254}
led.lua is triggered via alarm and periodically updates LED color based on the values in arr
webserver.lua prints out all the values of arr

Before any data is received from Arduino arr is simply 0 as initialized in init2.lua.

For what you are after, which is basically triggering an event upon receiving commands from Arduino, I can suggest the following solution (untested). Create commands.lua script and inside create a number of functions, for example:
Code: Select allfunction cmd_1(value)
      value=value+1;
               --do something here
   return value
end


Now from Arduino you can simply send a string cmd_1(1234) and the above function will run. You can issue this commands firstly manually through LuaLoader.

This all is not really a neat approach, but as the title states, it is making it simplified.
User avatar
By StefanL38
#12390 Hi Musti,
thank you very much for your explanations so far.

Now I was able to write a small testcode for serial dataexchange
Code: Select all-- simple example for receiving serial commands
-- this is a small testcode for using with LuaLoader or any other
-- serial terminal software to show how sending serial data to the ESP826 under the nodeMCU-firmware works:


-- setup UART for receiving data
-- parameters uart.setup( UART-id, baud, databits, parity, stopbits, echo )
uart.setup(0,9600,8,0,1)

print ("uart.setup(0,9600,8,0,1) finished")
print ("waiting for serial data....")

-- My opinion: Lua is crazy flexible
-- You just send the NAME of a function with parameters and Lua knows what do to
-- Execute the defined function with parameters
-- example: sending the following string to the ESP makes the code execute function 'cmd_2'
-- with parameter '78'    string to send towards ESP "cmd_2(78)"

function cmd_1(value)
  print("cmd_1("..value..") received")
end

function cmd_2(value)
  print("cmd_2("..value..") received")
end


best regards

Stefan