Digital Loggers

Customize your power controller using simple, powerful Lua scripting.


Updated 07/02/2019

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!

Main Lua scripting page

Turn on a sign workdays, during business hours. Exclude holidays.


To start automatically upon power up, set the start script

-- Starts all of the threads
function start_my_scripts()
    -- The third parameter allows me to limit the number of threads running
    thread.run(schedule_sign_workdays, "Turn on the sign during work hours", "Sign_On_Schedule")
    -- Schedule additional threads here
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

-- 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 < start_hours
  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 during work hours.
-- The limitation here is that this schedule cannot be overridden unless this script is stopped.
function schedule_sign_workdays()
  thread.limit(1) -- Allow only one occurance of this thread
  local sign=5
  while true do
    if is_working_day(os.date("*t")) and is_now_between(8,0,17,0) then -- 8am-5pm workdays
        outlet[sign].on()
    else
        outlet[sign].off()
    end
    delay(1) -- Don't be a CPU hog or it will get killed by the system
  end
end 

-- Schedule the sign on during work hours and work days.
-- The limitation here is that this schedule cannot be overridden unless this script is stopped.
function schedule_sign_workdays()
  thread.limit(1) 
  while true do
    if is_working_day(os.date("*t")) and (IsNowBetween(8,0,17,0) then
       outlet[5].on()
    else
      outlet[5].off()
    end
    delay(1) -- Don't be a CPU hog or it will get killed by the system
  end
end 

-- Holiday table for a given year accounting for adjustments

local holiday_table_year

-- Table index is the day of year
local holiday_table

-- Constants for convenience
local Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec=1,2,3,4,5,6,7,8,9,10,11,12

local Sun,Mon,Tue,Wed,Thu,Fri,Sat=1,2,3,4,5,6,7

local function normalized_date(date)
  return os.date("*t",os.time(date))
end

-- Generate a holiday table for US
local function make_US_holiday_table(base_year)
    local ret={}
    -- Nested local function we'll use further
    local function holiday(name,month,day,year)
    year=year or base_year
    local yday
    if type(day)=="number" then
        local date={year=year,month=month,day=day}
        date=normalized_date(date)
        if date.wday==Sun then
            -- Holidays on Sunday get adjusted to following
            -- Monday, that's 1 day later
            date.day=date.day+1
            date=normalized_date(date)
        elseif date.wday==Sat then
            -- Holidays on Saturday get adjusted to preceding
            -- Friday, that's 1 day earlier
            date.day=date.day-1
            date=normalized_date(date)
        end
        -- If a holiday moves to a different year as a result of
        -- an adjustment, it's not counted
        if date.year==base_year then
            yday=date.yday
        end
    else
        local index=day[1]
        local wday=day[2]
        local all_matching_days={}
        -- We could really speed this up, but it's simpler this way
        local date={year=year,month=month,day=0}
        while true do
            date.day=date.day+1
            date=normalized_date(date)
            if date.month~=month then
                break
            end
            if date.wday==wday then
                all_matching_days[#all_matching_days+1]=date.yday
            end
        end
        if index>0 then
            yday=all_matching_days[index]
        else
            yday=all_matching_days[#all_matching_days+1+index]
        end
    end
        if yday then
            ret[yday]=name
        end
    end
    holiday("New_Year's_Day",         Jan, 1                   )
    -- New Year is special, as it can move in from the next year,
    -- e.g. see 2010->2011
    holiday("New_Year's_Day",         Jan, 1,      base_year+1 )
    holiday("Martin_Luther_King_Day", Jan, {3,  Mon}           )
    holiday("Presidents'_Day",        Feb, {3,  Mon}           )
    holiday("Memorial_Day",           May, {-1, Mon}           )
    holiday("Independence_Day",       Jul, 4                   )
    holiday("Labor_Day",              Sep, {1,  Mon}           )
    holiday("Columbus_Day",           Oct, {2,  Mon}           )
    holiday("Veterans_Day",           Nov, 11                  )
    holiday("Thanksgiving_Day",       Nov, {4,  Thu}           )
    holiday("Christmas_Day",          Dec, 25                  )
    holiday("New_Year's_Eve",         Dec, 31                  )  
    -- You can add more to your liking
    return ret
end

--Returns true if it's a work day 
function is_working_day(d)
  if holiday_table_year~=d.year then
    holiday_table=make_US_holiday_table(d.year)
    holiday_table_year=d.year
  end
  return d.wday>=Mon and d.wday<=Fri and not holiday_table[d.yday]
end

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

engineering@digital-loggers.com