Digital Loggers

Customize your power controller using simple, powerful Lua scripting.


Updated 07/17/2023

Advanced Power Control - Lua Scripting

On its own, a power switch isn't very smart.  Add custom functionality using the built-in simple Lua scripting language. It's really simple. No programming experience is required.  Give it a try!

 

Hardware Requirements

This page describes the Lua based scripting language used in DLI products with WiFi.  If you're using a product without the WiFi option, look here for the BASIC scripting reference.

 

Entering Scripts

First, review this website for a quick overview of the Lua language.  Log in as admin and use the scripting feature.  Click the Scripting link on the left.  Review these sample scripts to start:

Example - Turn lights (relays) on and off on a weekday schedule. Now includes an alternate event driven example.
Example - Switch an outlet on and off daily. Now includes an alternate event driven example.
Example - Turn on a sign during workdays - excluding holidays.
Example - Reboot a modem weekly

We have some additional sample custom scripts here.

Need additional help? Email support@digital-loggers.com
--[[ This is a sample/test set of scripts for DLI controllers.
The scripting implementation has changed, and is no longer compatible
with the older BASIC implementation. The most important changes are:
- Now Lua-based.
- No more line numbers, blocks of code identified by functions.
- Most of ON, OFF, etc. are kept as legacy functions, which can be called like
 e.g  ON(2345), ON("2345") or ON "2345", your choice.
Execution is still based on threads. Now threads are more visible and
manageable. Try starting some and you'll see them appearing in the
list.
]]--
function turn_outlets_on()
    ON(1)
    ON(2)
    ON(3)
    ON(4)
    ON(5)
    ON(6)
    ON(7)
    ON(8)
end
function turn_outlets_off()
    OFF(12345678)
end
-- Hope this looks familiar so far.
-- Indentation is useful but not mandatory:
function toggle_stuff_and_log()
	LOG "One"
	ON(1)
	OFF(1)
	LOG "Two"
	ON(2)
	OFF(2)
	LOG "Done"
end
function do_some_lua_stuff()
	for i=1,8 do
		if i>4 then OFF(i) else ON(i) end
	end
end
function test_display()
	DISPLAY "\1Percent %%\v"
	DISPLAY "\2Backslash \\\v"
	-- These power displays only apply to the EPCR5 and EPCR6 
	DISPLAY "\1%a\v" --  current Bus A
	DISPLAY "\2%A\v" --  voltage Bus A
	DISPLAY "\1%b\v" -- current Bus B
	DISPLAY "\2%B\v" -- voltage Bus B
	DISPLAY "\1%o\v" -- Outlets state in the form "12456" (ON are displayed)
	DISPLAY "\1%O\v" -- Outlets state in the form "++-+++--"
	DISPLAY "\1%n\v" -- Serial number
	DISPLAY "\2%f\v" -- Firmware version
	DISPLAY "\f"     -- Clear screen, first line intentionally blank
	DISPLAY "\2%d\v" -- System time/date
	DISPLAY "\1%M\v" -- MAC address of the power controller
	DISPLAY "\2%i\v" -- IP address of the power controller
	DISPLAY "\1%m\v" -- IP network mask
	DISPLAY "\2%g\v" -- IP gateway
end
--[[ Some additional scripts that may be of use. wait_until is used and required for many of these.
- The wait_until function is built-in, but shown here for reference and as an example
- local functions and variables must be declared before they are used - local functions will not be displayed in the selection web UI box and cannot be used externally - Firmware version 1.7.x introduced a new event system which can be used instead of the wait_until function and has more capabilities. ]]--
-- Swap the state of outlets 7 and 8 function flip_flop_7_8() if(outlet[7].state == on) then outlet[7].off() outlet[8].on() else outlet[7].on() outlet[8].off() end end

-- Cycle an outlet daily at 1:00am function cycle_outlet_daily() while true do wait_until({hour=1,min=0}) outlet[2].cycle() delay(60) -- prevent it from running more than once in the same minute end end
-- Cycle an outlet Sunday mornings at 2:00am
-- In the wait_until function, listed below, wday - the day of the week, Sunday = 1
function cycle_outlet_weekly() while true do wait_until({wday=1,hour=2,min=0}) outlet[2].cycle() delay(60) -- prevent it from running more than once in the same minute end end
-- toggle outlet 5 every 15 minutes past the hour
-- This example uses an event driven approach
function outlet_5_toggle_schedule()
  for i,t,data in event.stream(event.local_time({min=15})) do
    if outlet[5].state == on then
      outlet[5].off()
    else
      outlet[5].on()
    end
    log.notice("Outlet 5 was toggled")
  end  
end
-- returns true if it's a weekend day
local function weekend(day_of_week)
	return day_of_week==7 or day_of_week==1
end
-- returns true if it's a weekday day
local function weekday(day_of_week)
	return day_of_week<7 and day_of_week>1
end
-- Turn on switches 1-5 on weekday mornings
function turn_on_lights_weekdays()
	while true do 
		wait_until({wday=weekday,hour=8,min=0})
		for i=1,5 do
			outlet[i].on()
		end
		delay(120) -- prevent it from running more than once in the same minute
	end
end
-- Turn off switches 1-5 on weekday evenings
function turn_off_lights_weekday_evenings()
	while true do 
		wait_until({wday=weekday,hour=17,min=30})
		for i=1,5 do
			outlet[i].off()
		end
		delay(120) -- prevent it from running more than once in the same minute
	end
end
-- Combine the minutes and hours to get total minutes
local function get_minutes(hours, minutes) 
	return (hours*60)+minutes
end
-- Checks to see if a time is between two others
local function is__time_between(start_h, start_m, stop_h, stop_m, test_h, test_m)
	-- add 24 hours if endhours < starthours
	if (stop_h < start_h) then
		local stop_h_org=stop_h
		stop_h = stop_h + 24
		if (test_h <= stop_h_org) then -- if endhours has increased the current hour should also increase
			test_h = test_h + 24
		end
	end
	-- The minutes within the day
	local start_t_val = get_minutes(start_h, start_m)
	local stop_t_val = get_minutes(stop_h, stop_m)
	local cur_t_val = get_minutes(test_h, test_m)
	return (cur_t_val >= start_t_val and cur_t_val < stop_t_val) -- cur_t_val < stop_t_val prevents including the last minute
end
-- Check to see if now is between start and end time
local function is_now_between(start_h,start_m,stop_h,stop_m)
	local time = os.date("*t")
	return is__time_between(start_h, start_m, stop_h, stop_m, time.hour, time.min)
end
-- Schedule the switch on between 8:30am and 5:15pm and monitor in between.
-- The limitation here is that this schedule cannot be overridden unless this script is stopped.
-- This requires the supporting local functions above: get_minutes, is__time_between, is_now_between
function schedule_switch_one()
	while true do
		if (is_now_between(8,30,17,15)) then
			if(outlet[1].state == off) then
				outlet[1].on()
			end
		else
			if(outlet[1].state == on) then
				outlet[1].off()
			end
		end
		delay(1) -- Don't be a CPU hog or it will get killed by the system
	end
end
-- Here we use wait_until to turn outlet 4 off at midnight.
function turn_off_light_at_midnight()
	wait_until({hour=0,min=0})
	OFF(4)
end
-- Here's an example function with loops. wait_until sleeps until a specified time
-- *** NOTE: You don't need to add this function to use it. It is built-in to the scripting server.
-- * wait_until parameters *
-- day - the day of the month, starting with 1
-- month - the month, January = 1
-- year - the year, with century
-- wday - the day of the week, Sunday = 1
-- yday - the day of the year, January 1 = 1
-- hour - the hour
-- min - the minute
-- sec - the second
-- ** It is not advised to perform exact matches on seconds since delays of internal 
-- operations may be greater than 1 second. -- ******************************
function wait_until(conditions) repeat local ok=true local date=os.date("*t") for k,v in pairs(conditions) do if type(v)=="function" then ok=v(date[k]) else ok=date[k]==v end if not ok then break end end if not ok then delay(1) end until ok end
-- EPCR5 - EPCR7 only -- Log some meter readings to the system log
function log_meter_readings()
LOG("Old style of logging") LOG(string.format("Bus A voltage: %g, bus A current: %g",meter.buses[1].voltage,meter.buses[1].current)) LOG(string.format("Bus B voltage: %g, bus B current: %g",meter.buses[2].voltage,meter.buses[2].current))
	log.info("This is the new format for logging")
	if(meter.buses[1].voltage > 95 and meter.buses[1].voltage < 130) then
		log.notice("Bus A voltage: %g, bus A current: %g",meter.buses[1].voltage,meter.buses[1].current)
	else 
		log.warning("Warning! Bus A voltage: %g, bus A current: %g",meter.buses[1].voltage,meter.buses[1].current) 
	end
	if(meter.buses[2].voltage > 100) then 
		log.info("Bus B voltage: %g, bus B current: %g",meter.buses[2].voltage,meter.buses[2].current)
	else
		log.warning("Low Voltage Warning - Bus B voltage: %g, bus B current: %g",meter.buses[2].voltage,meter.buses[2].current) 
	end
	if(meter.buses[2].voltage > 120) then 
		log.notice("Bus B voltage: %g, bus B current: %g",meter.buses[2].voltage,meter.buses[2].current)
	else
		log.warning("Bus B voltage: %g, bus B current: %g",meter.buses[2].voltage,meter.buses[2].current) 
	end
end
-- Reverse cycle - Cycle a switch on, then off
-- Remember that the "ON" speed between switches is limited by the "On sequence delay" in the Setup page
-- This function can be called from the autoping page and the switch(es) will be passed.
function reverse_cycle(selected_relays)
	count = #selected_relays
	for i = 1, count do   
		outlet[selected_relays[i]].on()
	end
  
	delay(15)  -- Time "on" delay in seconds
  
	for i = 1, count do   
		outlet[selected_relays[i]].off()
	end 
end

Have a smart script or unique way to use your switch?  Let us know!

engineering@digital-loggers.com