How do I execute a global function on a specific day at a specific time in Lua?

StackOverflow https://stackoverflow.com/questions/20109094

  •  03-08-2022
  •  | 
  •  

Вопрос

I'm writing a script in Lua that among many other functions will perform a single loop at a specific time on a specific day. The loop is started when a button is pressed, pondering over this for a while now I have gathered that I will have to check the system time in millis using os.time which in table form can return the date too which is very helpful. The only thing I am stuck with is how to express it, and if it would be possible to include multiple definitions of os.time; so on day (x), loop1 will run and on day (y) loop 2 will occur and so on. I'm most likely over complicating this a lot...

Here's my code so far: (it crashes and burns when called by the button press)

function runiftime()

day1 = a;
day2 = b;
day3 = c;
day4 = d;
status = 0; -- Default status == 0
target = day4;


-- Where a, b, c & d are shown above I would like different os.time outputs which relate to days in the future an example output of os.time is => = os.time() outputs '1384988715'.

    repeat

 if os.time() == "day1" then

    os.execute("Some command");
    result = Shell.Execute("Some program", "open", "", "",     SW_SHOWNORMAL, false);
    status = 1;
end

 if os.time() == "day2" then

    os.execute("Some command");
    result = Shell.Execute("Some program", "open", "", "", SW_SHOWNORMAL, false);
    status = 1;
end

 if os.time == "day3" then

    os.execute("Some command");
    result = Shell.Execute("Some program", "open", "", "",     SW_SHOWNORMAL, false);
    status = 1;
end

 if os.time == "day4" then

    os.execute("Some command");
    result = Shell.Execute("Some program", "open", "", "",     SW_SHOWNORMAL, false);
    status = 1;
end


    if status == 1 then
        Input.SetText("feed", "Routine Successful!                                  Waiting for Command...");
    else
        Input.SetText("feed", "Automated Routine Started!           Waiting for OS Clock...");
    end

until (os.time == target);  
end
Это было полезно?

Решение

I've noticed a few issues with your code. First of all, half the time, you're comparing to os.time which is a function and os.time() which will be a number. Secondly, you're going into an infinite loop with until (os.time == target);, since os.time will never change unless you change it.

Even then, if you were correctly comparing with os.time(), going into an infinite loop to check the time all the time is going to max out CPU usage for the Lua VM, as infinite loops are wont to do. This will probably freeze up the process, which might be what you mean by "crash and burn."

Last but not least, comparing the current time to a time in the future with an == is generally a bad idea, due to the low probability of the condition executing precisely during the exact desired time.

I'd recommend sleeping as long as possible until the earliest task is ready to be carried out. This way, you avoid taking up any unnecessary CPU time with constant polling. From Lua, you could do something like this.

local target = os.time{year = 2013, month = 11, day = 21, hour = 9, min = 30}

local function sleep(s) -- wait for `s` seconds
    if type(s) ~= 'number' then
        error's is not a number'
    elseif s < 1 then
      return
    end
    s = math.floor(s)

    -- Windows (delay range limited to 0-9999)
    --os.execute('choice /n /d:y /t:' .. math.min(s, 9999) .. ' > NUL')

    -- *nix
    os.execute('sleep ' .. s)
end

local d
repeat
    d = target - os.time()
    if d <= 0 then break end
    sleep(d) -- sleep for the difference
until false

print'Target time has arrived.'

Ideally, you'd accomplish something like this by having your operating system's scheduler, such as cron on *nix or Task Scheduler on Windows, control the timing of the script's execution. However, if you plan to handle the timing through Lua, have a look through this page in Programming in Lua.


Edit: Making use of our sleep function from last time, we can easily create the foundation for a complete task scheduler in Lua that can handle multiple events with only a few lines of code.

local alarm = {}
local function sort_alarm(a, b) return a.time > b.time end
local function schedule(when, what)
    if os.time() <= when then
        table.insert(alarm, {time = when, event = what})
        table.sort(alarm, sort_alarm)
    else -- What to do when a scheduled event is in the past?
        what()
    end
end
local function run_scheduler()
    local d
    while #alarm > 0 do
        d = alarm[#alarm].time - os.time()
        if d <= 0 then
            -- Pop the latest alarm from the stack and call it.
            table.remove(alarm).event()
        else
            sleep(d)
        end
    end
end

-- Schedule some events.
schedule(os.time{year = 2013, month = 11, day = 22, hour = 9}, function()
    print'This function runs at a specific point in time.'
end)

schedule(os.time() + 30, function()
    print'This function will run 30 seconds from the start of the script.'
end)

schedule(os.time() + 5, function()
    print'This function will run 5 seconds from the start of the script.'
    schedule(os.time() + 10, function()
        print'You can even schedule new functions this way.'
        print'This one will run 15 seconds from the start of the script.'
    end)
end)

local function repeater()
    print'How about a repeating event?'
    print'This function will run every 10 seconds.'
    schedule(os.time() + 10, repeater)
end
schedule(os.time() + 10, repeater)

-- Start the scheduler loop.
run_scheduler()

-- No more events left at this point, thus the script will end.

In closing, I must note that if you plan to use this seriously, you'll want to replace the sleep function with something more robust in the future. There's a page on the users wiki listing some solutions. I'd say it's easiest to do from LuaJIT using the FFI, if you happen to be using it already.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top