This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
Alatreon's profile picture

Creating an on switch that loops but can also be turned off

Started by Alatreon, 06 February 2017 - 09:59 PM
Alatreon #1
Posted 06 February 2017 - 10:59 PM
So I recently got into LUA and am trying to create a timer that ticks and can be turned off when it receives a certain message from the rednet.

The first part of my code is activated to send when the user pushes the monitor, entire code of that written below



mon = peripheral.wrap("top")
status = "off"
rednet.open("right")

function check()
if status ~= "on" or "off" then
local status = "off"
end
end

function display()
mon.setBackgroundColor(32768)
mon.clear()
mon.setCursorPos(1,1)
mon.setTextColor(1)
mon.write("Smelter program")
mon.setCursorPos(1,2)
mon.write("Current status: ")
end

function displayColor()
mon.setCursorPos(17,2)
mon.setTextScale(1.5)
if status == "off" then
mon.setTextColor(16384)
elseif status == "on" then
mon.setTextColor(8192)
end
mon.write(status)
end


function toggleWords()
mon.setCursorPos(1,7.5)
mon.setTextColor(1)
mon.write("Switch :")

if status == "on" then
mon.setCursorPos(8,7.5)
mon.setBackgroundColor(colors.green)
mon.write("ON")
mon.setCursorPos(11,7.5)
mon.setBackgroundColor(colors.red)
mon.setTextColor(1)
mon.write("OFF")

elseif status == "off" then
mon.setCursorPos(8,7.5)
mon.setBackgroundColor(colors.red)
mon.write("ON")
mon.setCursorPos(11,7.5)
mon.setBackgroundColor(colors.green)
mon.setTextColor(1)
mon.write("OFF")
end

end

function input()
event, side, xcord, ycord = os.pullEvent()
if xcord >= 8 and xcord <= 9 and ycord == 7 and status == "off" then
status = "on"
print("should be on")
elseif xcord >= 11 and xcord <= 13 and ycord == 7 and status == "on" then
status = "off"
print("should be off")
end
end

function tick()
if status == "on" then
rednet.send(20,"run")
elseif status == "off" then
rednet.send(20,"stop")
end
end


function forgeDisplay()
check() -- checks the status on startup
display() -- refreshed display and uses new status
displayColor() -- dislays the color of "status"
toggleWords() -- sees what the status is, changes "on" and "off" button background depending on variable "status"
end


function runIt()
while true do
forgeDisplay() -- the function that changes puts the display "Smelter program" and "Smelter status" as well as updating the interactive button background for "ON" and "OFF"
input() -- checks for input from touch screen
tick() -- use the timer to regulate the smelter timer
end
end

runIt()


The problem I'm having is on where the signal goes on through the rednet signal,



function runOutput()
rednet.open("top")
while true do
local id, message = rednet.receive()
print("signal: ".. id, message )
if message == ("run") then
repeat
print("should loop")
redstone.setOutput("left", true)
sleep(1)
redstone.setOutput("left", false)
sleep(14)
print("loop should restart")
print("message currently: " .. message)
local a,b ,c ,msg ,e = os.pullEvent()
until message == "stop"
print("if statement ended")

end
end

end

runOutput()


This code is supposed to activate a smelter to the left with a tick, wait 14 seconds and start again only if the message is still "run". If the message is switched to "stop" I want the computer to stop going through the timer, and wait for "run" again. However the computer is only activated when i type a key in the computer,, I know this is cause by the "local a,b ,c ,msg ,e = os.pullEvent()" but I can't think of any other way to see if the message is "stop". I also tried using "local id, message = rednet.receive()" In place of it but with no results I wanted.
Bomb Bloke #2
Posted 08 February 2017 - 10:52 AM
You may already be aware, but every time your scripts wait for anything - be it user input, a sleep, a rednet message, whatever - they yield and wait for an event to happen in order to do it. Typically they do this via os.pullEvent() - functions which wait for you are therefore usually calling os.pullEvent() for you.

So sometimes you're better off re-writing certain functions so that only one spot within your code is pulling events. For example, say we ditched sleep(), and started manually calling os.startTimer() instead; we could then pull all events at a single location in the code and respond to them according to type:

Spoiler
peripheral.find("modem", rednet.open)  -- Opens all attached modems for rednet usage.

local signal, redstoneSide, pulseOnTime, pulseOffTime, myTimer = false, "left", 1, 14

while true do
	local event, par1, par2 = os.pullEvent()
	
	if event == "rednet_message" then
		print("Signal from ID "..par1..": "..par2)
		
		if par2 == "run" then
			redstone.setOutput(redstoneSide, true)
			signal, myTimer = true, os.startTimer(pulseOnTime)
			
		elseif par2 == "stop" then
			redstone.setOutput(redstoneSide, false)
			signal = false
		
		end
	
	elseif event == "timer" and par1 == myTimer and signal then
		if redstone.getOutput(redstoneSide) then
			redstone.setOutput(redstoneSide, false)
			myTimer = os.startTimer(pulseOffTime)
			
		else
			redstone.setOutput(redstoneSide, true)
			myTimer = os.startTimer(pulseOnTime)
		
		end
	
	end
end
Alatreon #3
Posted 08 February 2017 - 09:54 PM
Thank you for getting back to me in a polite way, I just realized today that was how os.pullEvent worked. Prior I was under the impression that the code kept running while os.pullEvent was there :blink:/>. Again thanks, I will make sure to do further research and debugging before posting a question like that again. :D/>