AN08 Cyclic traffic lights in Lua according to a defined table | NETIO products: Networked power sockets
User library

AN08 demonstrates the use of a Lua script to switch 230V sockets on/off according to a table. The example table contains 8 states. Each state has a defined duration (1s minimum). This example can be used as cyclic “traffic lights”

Do you have any questions?


Supported devices: 



In this Section 1, the Lua script described in this Application Note contains a user-defined table with 8 states that periodically turns on/off four 230V sockets (or 110/230V IEC-320 outlets in case of NETIO 4C). Each of these 8 states has a defined duration (5th number separated by a comma).

More states (table rows) can be added.

The action value for each output can 0, 1, 2, 3, 4 or 5. 

These values of 0 to 5 correspond to the values used in all M2M APIs of NETIO products

0 = Output switched off (Off)

1 = Output switched on (On)

2 = Output switched off for a short time (short Off) 

3 = Output switched on for a short time (short On)

4 = Output switched from one state to the other (toggle) 

5 = Output state unchanged (no change) 


Actions 2 and 3 create a pulse of a defined width. For example, a state can last 5 seconds but it causes an output to be switched on for 2 seconds only (state2 in the example).

Action 5 is useful if the corresponding output is controlled by other means (button, mobile app, web interface). Action value 5 means that the output is unchanged. 


Creating the rule in Lua scripting language

To create and run the Lua script, do the following:

1) In the Actions section of NETIO 4 web administration, click Create Rule to add a rule


2) Fill in the following parameters:

  • Enabled: checked
  • Name: Traffic lights (user-defined)
  • Description: Cyclic switching of the outputs (user-defined)
  • Trigger: System started up
  • Schedule: any (does not affect the function in this configuration)


3) Copy the following code and paste it into the field for the Lua script:

------------Section 1------------
local states = {"0000,1", --state1
                "3001,5", --state2
                "0010,1", --state3
                "1011,1", --state4
                "1100,1", --state5
                "0101,1", --state6
                "0110,1", --state7
                "0111,1"} --state8

local shortTimeMs = 1000 -- time used in states 2 and 3
---------End of Section 1---------

local currentState = 1 -- internal variable, do not change
local value -- internal variable
local time -- internal variable

local function checkFormat()
  for i=1,#states do
    local time = tonumber(states[i]:sub(6))
    if time == nil or time<-1 then
      logf("Time in state %d is invalid!",i)
      return false
    local comma = states[i]:sub(5,5)
    if comma ~= "," then
      logf("Time in state %d is not separated by comma!", i)
      return false
    for j=1,4 do
      local test = tonumber(states[i]:sub(j,j))
      if test == nil or test>5 or test<0 then
        logf("Value in state %d for outlet %d is invalid!", i,j)        
        return false
  return true

local function trafficLights()
  --logf("Current state: %d",currentState)
  time = tonumber(states[currentState]:sub(6))
  for i=1,4 do
    value = tonumber(states[currentState]:sub(i,i))
    if value == 0 then -- turn off
      devices.system.SetOut{output = i, value = false}
    elseif value == 1 then -- turn on
      devices.system.SetOut{output = i, value = true}
    elseif value == 2 then -- short off
      devices.system.SetOut{output = i, value = false}
      milliDelay(shortTimeMs,function() short(i,true) end)
    elseif value == 3 then -- short on
      devices.system.SetOut{output = i, value = true}
      milliDelay(shortTimeMs,function() short(i,false) end)   
    elseif value == 4 then -- toggle
      if devices.system["output" ..i.. "_state"] == 'on' then  
        devices.system.SetOut{output=i, value=true}
    elseif value == 5 then
      -- do nothing
  currentState = (currentState%#states) + 1
  delay(time,function() trafficLights() end)

local function short(outlet,state)

if checkFormat() then


4) To finish creating the rule, click Create Rule at the bottom of the screen.



Method of operation of the Lua script in networked power sockets NETIO

  • First, the script uses the checkFormat function to verify that the states are correctly specified.
  • The time variable holds the time after which the outputs switch to the next state.
  • In a loop, all outputs are set according to the respective action value (0 - off, 1 - on, 2 - short off, 3 - short on, 4 - toggle, 5 - no change). For actions 2 and 3, the short function is used to create the pulse.
  • After the outputs are set, the currentState variable is set to the next state and the trafficLights function is called with the appropriate delay.


Setting the variables for Lua script

  • states
    • Contains an array of strings. Each string corresponds to one state. Curly brackets are needed before the first state and after the last one. States are separated by commas
    • String format:
      • Each string has the form of “abcd,e”. The letters stand for:
        • a - action on output no. 1
        • b - action on output no. 2
        • c - action on output no. 3
        • d - action on output no. 4
        • e - duration of this state (in seconds)
      • Strings must be enclosed in double quotes
      • Example: “1205,25”
    • Actions
      • 0 - output switched off
      • 1 - output switched on
      • 2 - “short off”: output is set to 0, and after a delay specified in the shortTimeMs variable, the output is set to 1
      • 3 - “short on”: output is set to 1, and after a delay specified in the shortTimeMs variable, the output is set to 0
      • 4 - “toggle”, if the output was on, it is turned off, or vice versa
      • 5 - the output is unchanged


  • shortTimeMs
    • Specifies (in milliseconds) for how long is the output on and off for actions 2 and 3 respectively
    • The minimum value is 100 ms
    • Example for 2-second pulses: shortTimeMs = 2000


Example: All outputs are switched on and off one by one, each state lasts 30 seconds (the entire cycle takes 240 seconds = 4 minutes).



In state 1, all outputs are switched off. After 30 seconds, the traffic lights transition to state 2 and output 4 is switched on. After another 30 seconds, output 3 is switched on, and so on, until all outputs are switched on in state 5. This state again lasts 30 seconds. Then, outputs are switched off one by one, starting with output 4. In state 8, only output 1 is on. From this state, the traffic lights transition back to state 1 and the cycle repeats.

In state 8, action 5 is used for one of the outputs. If the output has changed while the script was in the previous state, the output is not turned off. This is a difference from action 0.


Frequent issues

  • Incorrect format
    • "0000" - time is not specified
    • "0000.30" - the actions and the time must be separated with a comma (,)
    • "0006,30" - allowed action values are 0 to 5
    • "000x,30" - to leave a socket unchanged, use 5
    •  0000,30  - double quotes missing


Starting the script

After configuring all the parameters and saving the script, the NETIO smart sockets need to be restarted. When the device boots again, the script is started and the outputs start to behave according to the table. If the script doesn’t start, please check the settings.



1) Is it possible to have a different number of states than 8?

Yes. Specify any number of desired states in the state variable. Pay attention to the correct format. Curly brackets are needed before the first state and after the last one, and individual states are comma-separated - as in the figures.

Examples for 4 states and 10 states:



2) Is there a maximum duration of a state?

No. However, for long time intervals (in the order of hours), we recommend to use the Scheduler function instead.


3) I don’t want the cycle to repeat infinitely but only a certain number of times. Is it possible to do that?

Yes; however, the code must be significantly changed. It is necessary to add another variable to count the number of state transitions and compare its value to the desired limit.


4) How can I stop a running script?

First, uncheck Enabled in the script configuration and confirm the settings. Then, restart your NETIO device.


5) I want to control 3 outputs only, is it possible?

Yes. For the outputs that shall not be controlled, set all action values to 5.


6) If the next state contains the action 5 for a given output and this output is changed in the meanwhile e.g. from the mobile app, will the Lua script change this output?

No. Action 5 means that the current output state is unchanged. It does not matter how the output got into its current state.


7) How can I set the pulse duration for actions 2 and 3 to 0.4 s?

The shortTimeMs variable specifies the pulse duration for actions 2 and 3 in milliseconds. So, the desired setting would be: shortTimeMs = 400


8) Is it possible to write the current traffic lights state into the log?

Yes, simply uncomment (by deleting the double dashes) the 

--logf("Current state: %d",currentState) line in the trafficLights function.


9) Is it possible to pause the script for a while and then let it run again?

No, the script runs continuously and it is not possible to pause it. We plan to add such a function in a next firmware release.


Supported FW versions:

3.0.0 a and higher (Archiv firmwware)



Cyclic switching of the outputs, traffic lights, cyclic switching according to table, work with strings in Lua


Ask for a price or technical parameters

For device testing use name/password demo/demo