This is a read-only snapshot of the ComputerCraft forums,
taken in April 2020.
Background timer program
Started by le nub, 02 February 2013 - 10:41 AMPosted 02 February 2013 - 11:41 AM
I would like to create a program that will turn the lights on at night and off during the day, automagically. I know how to right this program.. How can i run this program in the background and still do other stuff on my computer? like edit other programs, etc…
Posted 02 February 2013 - 12:39 PM
You could use coroutines to accomplish this. If don't mind running a second instance of the shell to do this, here is an example: (You can also use NeverCast's injection method to run your coroutine on top of the parent shell).
You will have to replace "– Add light switching logic here" with your own code to have it work the way you want.
I'd be happy to answer any questions you have.
--[[
Light Switch PaymentOption
1 February 2013
This is a simple script using
coroutines to demonstrate
multi-tasking with the shell to
control lights as requested by
le nub.
]]--
--========================================================
-- Variables:
local LIGHT_TOGGLE_TIME = "12:00 AM" -- This is the string that must be matched in order to toggle the time.
local LIGHT_UPDATE_TIME = 1 -- This is how much time there will be in between timer event throws to update the light checking thread.
local lightTimer = nil -- This will hold the timer value which will throw an event in order to update the light checking thread.
-- This table contains all of the threads to be run with
-- the shell and receive events. NOTE: Any thread here
-- will need to have a call to coroutine.yield!
local threads = {
["shell"] = coroutine.create(function()
while true do
local eventData = { os.pullEvent() }
local hasFinished = coroutine.resume(os.run({["shell"] = shell}, "rom/programs/shell"), unpack( eventData ))
-- If our shell instance has executed, then treat this like the parent shell and shut down the computer.
if hasFinished then
os.shutdown()
end
end
end),
-- This is where your function will handle switchin the lights
-- on and off based on the time.
["lights_thread"] = coroutine.create(function()
-- Start the timer.
lightTimer = os.startTimer(LIGHT_UPDATE_TIME)
while true do
local eventData = { os.pullEvent() }
-- Restart the timer only if it has triggered.
if eventData[1] == "timer" and eventData[2] == lightTimer then
lightTimer = os.startTimer(LIGHT_UPDATE_TIME)
end
-- Check the current time and toggle the lights if we need to.
if textutils.formatTime(os.time(), true) then
-- Add light switching logic here.
end
end
end)
}
--========================================================
--========================================================
-- Thread handling:
local function executeThreads()
term.clear()
term.setCursorPos(1, 1)
-- Queue a couple of char events to get the new shell going.
os.queueEvent("char", '')
os.queueEvent("char", '')
while true do
local eventData = { os.pullEvent() }
for threadIndex, thread in pairs(threads) do
if coroutine.status(thread) ~= "dead" then
coroutine.resume(thread, unpack( eventData ))
else
error("Thread " .. threadIndex .. " is dead. Halting...")
sleep(1)
return
end
end
end
end
--========================================================
--========================================================
-- Main entry point:
executeThreads()
--========================================================
You will have to replace "– Add light switching logic here" with your own code to have it work the way you want.
I'd be happy to answer any questions you have.
Posted 02 February 2013 - 02:35 PM
Why not just use the parallel API? It does all of the coroutine creation/handling for you.
Where the "lights" program is whichever program toggles your lights at day and night. I originally thought there would be problems with this but I tried it and it works perfectly fine. This was my test lights program:
local function runLights()
shell.run 'lights'
end
local function runShell()
shell.run 'shell'
end
shell.run 'clear'
parallel.waitForAny(runLights, runShell)
os.shutdown()
Where the "lights" program is whichever program toggles your lights at day and night. I originally thought there would be problems with this but I tried it and it works perfectly fine. This was my test lights program:
while true do
local so = rs.setOutput
so('bottom', true)
sleep(0.5)
so('bottom', false)
sleep(0.5)
end
Posted 02 February 2013 - 03:08 PM
Why not just use the parallel API? It does all of the coroutine creation/handling for you.local function runLights() shell.run 'lights' end local function runShell() shell.run 'shell' end shell.run 'clear' parallel.waitForAny(runLights, runShell) os.shutdown()
Where the "lights" program is whichever program toggles your lights at day and night. I originally thought there would be problems with this but I tried it and it works perfectly fine. This was my test lights program:while true do local so = rs.setOutput so('bottom', true) sleep(0.5) so('bottom', false) sleep(0.5) end
It's kind of a control thing. Using the parallel API is much cleaner, but I just prefer to have all of the code accessible to me, even if I know how the API I am using is working. I find my method to be useful for larger scripts, but it just makes a mess if you're trying to achieve something relatively simple.
Posted 02 February 2013 - 06:06 PM
You could use coroutines to accomplish this. If don't mind running a second instance of the shell to do this, here is an example: (You can also use NeverCast's injection method to run your coroutine on top of the parent shell).--[[ Light Switch PaymentOption 1 February 2013 This is a simple script using coroutines to demonstrate multi-tasking with the shell to control lights as requested by le nub. ]]-- --======================================================== -- Variables: local LIGHT_TOGGLE_TIME = "12:00 AM" -- This is the string that must be matched in order to toggle the time. local LIGHT_UPDATE_TIME = 1 -- This is how much time there will be in between timer event throws to update the light checking thread. local lightTimer = nil -- This will hold the timer value which will throw an event in order to update the light checking thread. -- This table contains all of the threads to be run with -- the shell and receive events. NOTE: Any thread here -- will need to have a call to coroutine.yield! local threads = { ["shell"] = coroutine.create(function() while true do local eventData = { os.pullEvent() } local hasFinished = coroutine.resume(os.run({["shell"] = shell}, "rom/programs/shell"), unpack( eventData )) -- If our shell instance has executed, then treat this like the parent shell and shut down the computer. if hasFinished then os.shutdown() end end end), -- This is where your function will handle switchin the lights -- on and off based on the time. ["lights_thread"] = coroutine.create(function() -- Start the timer. lightTimer = os.startTimer(LIGHT_UPDATE_TIME) while true do local eventData = { os.pullEvent() } -- Restart the timer only if it has triggered. if eventData[1] == "timer" and eventData[2] == lightTimer then lightTimer = os.startTimer(LIGHT_UPDATE_TIME) end -- Check the current time and toggle the lights if we need to. if textutils.formatTime(os.time(), true) then -- Add light switching logic here. end end end) } --======================================================== --======================================================== -- Thread handling: local function executeThreads() term.clear() term.setCursorPos(1, 1) -- Queue a couple of char events to get the new shell going. os.queueEvent("char", '') os.queueEvent("char", '') while true do local eventData = { os.pullEvent() } for threadIndex, thread in pairs(threads) do if coroutine.status(thread) ~= "dead" then coroutine.resume(thread, unpack( eventData )) else error("Thread " .. threadIndex .. " is dead. Halting...") sleep(1) return end end end end --======================================================== --======================================================== -- Main entry point: executeThreads() --========================================================
You will have to replace "– Add light switching logic here" with your own code to have it work the way you want.
I'd be happy to answer any questions you have.
thanks for your detailed reply. I hada feeling i might have to use a coroutine but i have NEVER had any idea how to use one so thanks for your lengthy solution.. however I think i might go with the suggestion below because it is a far simpler solution for such a simple light timer. But again, thank you thats impressive to me :)/>
Posted 02 February 2013 - 06:10 PM
Why not just use the parallel API? It does all of the coroutine creation/handling for you.local function runLights() shell.run 'lights' end local function runShell() shell.run 'shell' end shell.run 'clear' parallel.waitForAny(runLights, runShell) os.shutdown()
Where the "lights" program is whichever program toggles your lights at day and night. I originally thought there would be problems with this but I tried it and it works perfectly fine. This was my test lights program:while true do local so = rs.setOutput so('bottom', true) sleep(0.5) so('bottom', false) sleep(0.5) end
thank you for your simple solution :)/> However for clarification.. Should i make…
local function runLights()
shell.run 'lights'
end
local function runShell()
shell.run 'shell'
end
shell.run 'clear'
parallel.waitForAny(runLights, runShell)
os.shutdown()
into its own file? And, would i actually type shell.run 'shell' with only single quote around it??
Posted 02 February 2013 - 06:57 PM
for background coroutines, use
Note: shell.run( "/rom/programs/shell" ) just creates a child shell
os.run( {}, "/rom/programs/shell" )
so that the second shell will actually be a parent shellNote: shell.run( "/rom/programs/shell" ) just creates a child shell
Posted 03 February 2013 - 04:18 AM
Yes, make that into it's own file called "startup" so it runs on startup, and name whatever program controls your lights to "lights". To type the single quotes, just type the double quote key without holding shift.thank you for your simple solution :)/>/> However for clarification.. Should i make…
local function runLights()
shell.run 'lights'
end
local function runShell()
shell.run 'shell'
end
shell.run 'clear'
parallel.waitForAny(runLights, runShell)
os.shutdown()
into its own file? And, would i actually type shell.run 'shell' with only single quote around it??
It doesn't really matter that much, at this point it's just an OCD thing, and as long as it works perfectly fine, there's really no problem. The program shuts down after the child shell has excecuted, so it acts as a parent shell anyway.for background coroutines, useso that the second shell will actually be a parent shellos.run( {}, "/rom/programs/shell" )
Note: shell.run( "/rom/programs/shell" ) just creates a child shell