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

having trouble altering my program to auto wrap reactors

Started by Caleb Ragnarok, 25 September 2015 - 03:54 AM
Caleb Ragnarok #1
Posted 25 September 2015 - 05:54 AM
I'm trying to convert my program to autodetect and wrap all connected reactors, but I'm running into an issue when I try to get the connected status of the first reactor.

This is a snipet of my code. the error is in the last line.


local ReactorCount = 0
local Reactor = {}

for a,b in pairs(peripheral.getNames()) do

  if peripheral.getType(B)/> == "BigReactors-Reactor" then
    print("Reactor Found.")
    Reactor[ReactorCount] = peripheral.wrap(B)/>
    ReactorCount = ReactorCount + 1
    sleep(.2)
  else
    print("Incorrect Device")
    sleep(.2)
  end
end 

local capacitor = peripheral.wrap("back")
local modem = peripheral.wrap("left")
local monitor = peripheral.wrap("top")
-- local reactor = peripheral.wrap("BigReactors-Reactor_0")
local turbine_0 = peripheral.wrap("BigReactors-Turbine_6")
local turbine_1 = peripheral.wrap("BigReactors-Turbine_5")
monitor.clear()

--Capacitor Bank Calculations--
CapCount = 1073
CapBasic = 1000000
CapStandard = 5000000
CapVibrant = 25000000
CapType = (CapBasic)
TotalCapacity = (CapCount) * (CapType)

--Debug--
Debug = true

if Debug == true then
  monitor.clear()
  monitor.setCursorPos(1,1)
  print("Debug On")
  print("Reactor Connected:   ", Reactor_0.getConnected())
 


Any help would be appreciated.
valithor #2
Posted 25 September 2015 - 10:35 PM
From what I can tell you are storing all of the reactors in a table. So the problem is actually how you are referencing the table:


Reactor[1].getConnected()

Also, in the loop where you are wrapping the peripherals, you should be using b instead of B.

Posted from my phone, so sorry for any short or under explained parts.
Edited on 26 September 2015 - 03:33 PM
Bomb Bloke #3
Posted 26 September 2015 - 12:54 AM
Also, in the loop where you are wrapping the peripherals, you should be using b instead of B.

Odds are he is - for whatever reason, the board's emoticon-handling system interferes with strings it recognises when you preview / edit posts, and "B)" is a match.
Caleb Ragnarok #4
Posted 26 September 2015 - 02:45 PM
I am using a lowercase "b". Bomb is correct. I pirated most of that function from a post he did awhile back.

Thanx for the help, I figured out my mistake last night. Now I'm running into another issue. Does anyone know of a way to automatically shutdown all the computers on a network if the main disk is ejected from the networked drive and then starts all computers when the dis is inserted? I can get them to all turn off, but I can get them to come back on.
TYKUHN2 #5
Posted 26 September 2015 - 04:36 PM
Caleb please post the fix for your original issue in this thread. If anyone for whatever reason has a similar issue they can use your solution.

Have a networked computer that doesn't shutdown. It can use the computers like a peripheral and turn them on.
Caleb Ragnarok #6
Posted 26 September 2015 - 05:13 PM
I can turn them on ok. I got a program to turn on all connected computers and keep them running.. I just don't know how to have them automatically turn off once I pull the disk from a networked drive. I'll post the code for the reactor program when I get home

Valithor got the problem.. I changed the last line to reactor[1].getActive()
Edited on 26 September 2015 - 03:15 PM
valithor #7
Posted 26 September 2015 - 05:24 PM
When a disk is removed from a disk drive a "disk_eject" event is fired. You could have all of the computers on the network listen for that event and shutdown when it is received, or you could have one computer listen for the event and run the following code when it is received:


os.pullEvent("disk_eject")
local computers = {peripheral.find("computers")} --# finds all of the computers on the network
for k,v in pairs(computers) do --# loops through them
  v.shutdown() --# turns off all other computers
end
os.shutdown() --# turns itself off
Edited on 26 September 2015 - 03:25 PM
Caleb Ragnarok #8
Posted 26 September 2015 - 07:52 PM
Thnx man..I'll try that when I get home. I'm using a program called "on" by a member here..can't remember the name of the author though. It works great and keeps all the mainframe computers active. I want to try to incorporate "on" into my code.. can I use that code you just gave me to also turn on all the computers when I put the disk in the server computer? Instead of .shutDown, use .turnOn?
valithor #9
Posted 26 September 2015 - 07:53 PM
Thnx man..I'll try that when I get home. I'm using a program called "on" by a member here..can't remember the name of the author though. It works great and keeps all the mainframe computers active. I want to try to incorporate "on" into my code.. can I use that code you just gave me to also turn on all the computers when I put the disk in the server computer? Instead of .shutDown, use .turnOn?

Yes, but you would also need to change the event type to "disk" instead of "disk_eject"
Caleb Ragnarok #10
Posted 26 September 2015 - 10:16 PM
Here is my code so far

http://pastebin.com/Y3t635PK

It searches for three types of peripherals right now and starts a reactor management program.
Caleb Ragnarok #11
Posted 27 September 2015 - 01:54 AM
I'm not sure how I would code a change in event. how would I implement it my program? Im not sure how event work yet.
valithor #12
Posted 27 September 2015 - 02:21 AM
There would be two good ways to incorporate the code i posted into your program. The first is using os.startTimer instead of sleep, and listening for the timer event along with the two disk events. The other one is coroutines. I am only going to explain the first one as it is much simpler to understand, and I only have limited time to explain.

So in case you did not know this, all the sleep function does is starts a timer, and then listens for the event the timer throws when it fires. So if you tell something to sleep for 5 seconds it starts a 5 second timer, and then checks all events to see if it was the timer it started. So if you want to listen to other events at the same time you are sleeping you can do something like the following:


while true do
  local myTimer = os.startTimer(5) --# starting a timer to fire after 5 seconds
  local event = {os.pullEvent()} --# catching the events and all the parameters in a table
  if event[1] == "timer" and event[2] == myTimer then --# checking to see if the event is a "timer" event, and checking if the timer event is the one we are looking for
	--# you have waited for 5 seconds so do whatever you want
  elseif event[1] == "another event" then
	--# it was a different event, so do other stuff
  end
  os.cancelTimer(myTimer) --# you need to make sure to cancel the timer, or you will experience problems later on
end

If you need any help changing this to work in your script just post again, and I will help. I am about to go out for a few hours with some friends, so I am sorry for the short explanation.
Edited on 27 September 2015 - 12:23 AM
Caleb Ragnarok #13
Posted 28 September 2015 - 02:59 AM
Would you mind giving me a hand? LUA is not my strong suit yet
valithor #14
Posted 28 September 2015 - 04:28 AM
Okay so if I understand completely what you are trying to do, then you want your code to be running, while also listening for a disk to be inserted or removed form the system. If the disk is inserted start all of the computers, if it is removed, then shut them all down.

Applying it to your code:


local on = true --# I will explain the importance of this below

while true do
  local myTimer = os.startTimer(5) --# starting a timer to fire after 5 seconds
  local evt = {os.pullEvent()} --# catching the events and all the parameters in a table
  if event[1] == "timer" and event[2] == myTimer and on then --# checking to see if the event is a "timer" event, and checking if the timer event is one we are looking for, I will explain "on" below
	--# this is essentially replacing the sleep that you had at the end of your original code
	CapEnergyStored = Capacitor[1].getEnergyStored()
	EnergyStored = (CapEnergyStored) * (CapCount)

	if Debug == true then
	  print(EnergyStored)
	end

	if EnergyStored <= EmptyLevel or EnergyStored == 0 then
	  Reactor[1].setAllControlRodLevels(11)
	  Turbine[1].setFluidFlowRateMax(1270)
	  Turbine[2].setFluidFlowRateMax(1270)

	elseif EnergyStored >= EmptyLevel and EnergyStored <= LowLevel then
	  Reactor[1].setAllControlRodLevels(11)
	  Turbine[1].setFluidFlowRateMax(1260)
	  Turbine[2].setFluidFlowRateMax(1260)

	elseif EnergyStored >= LowLevel and EnergyStored <= MedLevel then
	  Reactor[1].setAllControlRodLevels(37)
	  Turbine[1].setFluidFlowRateMax(1260)
	  Turbine[2].setFluidFlowRateMax(550)

	elseif EnergyStored >= MedLevel and EnergyStored < HighLevel then
	  Reactor[1].setAllControlRodLevels(61)
	  Turbine[1].setFluidFlowRateMax(1260)
	  Turbine[2].setFluidFlowRateMax(0)

	elseif EnergyStored >= HighLevel and EnergyStored <= FullLevel then
	  Reactor[1].setAllControlRodLevels(82)
	  Turbine[1].setFluidFlowRateMax(550)
	  Turbine[2].setFluidFlowRateMax(0)

	elseif EnergyStored >= FullLevel then
	  Reactor[1].setAllControlRodLevels(100)
	end
  elseif evt[1] == "disk" then
	--# a disk was just added to the system
	local computers = peripheral.find("computer")
	for k,v in pairs(computers) do --# begin looping through and turning on all computers
	  v.turnOn()
	end
	on = true --# i will explain the importance of this below
  elseif evt[1] == "disk_eject" then
	--# a disk was just removed from the system
	local computers = peripheral.find("computer")
	for k,v in pairs("computer") do --# begin looping through and turning off all computers
	  v.shutdown()
	end
	on = false --# I will explain the importance of this below
  end
  os.stopTimer(myTimer) --# I will further explain this below
end

So the "on" variable, keeps track of whether or not there is a disk in a disk drive, with the assumption that when the computer is first turned on there is one (defined as true in the beginning). So in the first if statement it checks the event to see if the event was the correct timer event, and it checks if the variable "on" is true. If it is then it will and the other two checks were true, then it will run the section of the code. If it is not, then it will go onto the next two checks. The first of the next two checks checks to see if the event was a disk being added to the system. If it is then it turns on all the computers and sets the variable to true, which causes the main part of the program to run. If that check is false, then it goes onto the last one which checks for if a disk was removed. If a disk was removed, then it shuts all the computer down, and sets the variable to false, which disables the main part of the program, while still listening for a disk to be added.

Importance of os.stopTimer: I really do not know how to explain this… but I will try using examples.


while true do
  local myTimer = os.startTimer(1)
  os.pullEvent()
  print("hi")

If you were to run that code, if you did not hit any button after running it, you would notice it would print "hi" every one second. However, if you were to hit a key, which fires a event, it would then start printing "hi" every half of a second. This is because the original timer is still running, but you have created another one before it has fired. So you have 2 timers running with a 1 second interval.

I think I have hit everything. If you need anything specific feel free to ask. :D/>

edit:

For anyone who is looking back on any of this code just know there is some errors in it. I wrote it at midnight one night, and am too lazy to fix all of them right now. This is more showing what goes where than anything, it is not for copy paste use. :P/>
Edited on 29 September 2015 - 04:10 AM
Caleb Ragnarok #15
Posted 29 September 2015 - 04:54 AM
I get through the boot up and initializing peripherals, but at the

os.stopTimer(myTimer) line, I get an attempt to call nil error

heres the program http://pastebin.com/WB1SAXVN
valithor #16
Posted 29 September 2015 - 05:09 AM
I get through the boot up and initializing peripherals, but at the

os.stopTimer(myTimer) line, I get an attempt to call nil error

heres the program http://pastebin.com/WB1SAXVN

Sorry that was a typo. It should be os.cancelTimer(myTimer)
Caleb Ragnarok #17
Posted 29 September 2015 - 05:15 AM
ok, that got me passed that error. Now, when I yank the disk, I get a bad argument: table expected, got string on line 222.

I see why..let me fix that
Edited on 29 September 2015 - 03:33 AM
valithor #18
Posted 29 September 2015 - 05:26 AM
ok, that got me passed that error. Now, when I yank the disk, I get a bad argument: table expected, got string on line 222.

I see why..let me fix that

Lol yea sorry… I did not test the code I gave you in any way. It is more of a example than anything.
Caleb Ragnarok #19
Posted 29 September 2015 - 05:33 AM
Yup, that got it. I had already gotten all the computers on the network and put them in a table called 'Computers'. You also had one of the elseif statements looking for a ("computers" and not (computers). Since I already had the data needed in the 'Computers' table, I just used that.. worked perfectly. Now the only problem I'm having with the code is with the systemStart(). I cant get the program to turn a PC back on after the first cycle. The come on, and shut off now just fine…but its not turning a PC back on after I turn it off. Am I calling the status wrong?
valithor #20
Posted 29 September 2015 - 06:02 AM
worked perfectly. Now the only problem I'm having with the code is with the systemStart(). I cant get the program to turn a PC back on after the first cycle. The come on, and shut off now just fine…but its not turning a PC back on after I turn it off. Am I calling the status wrong?

It is probably just because it is late for me and I am tired, but could you explain the problem you are having? I having trouble following.

So you turn them all on with the systemStart function, and then they turn off by what? If you are using updated code that is significantly different from the previous code please upload.
Just noticed you are updating the pastebin.

Edit:

I see what you were asking now. I actually have no idea what the getActive function does of a wrapped computer, but what you are looking for, If i remember correctly, is b.isOn()

edit2:

If you are ever unsure of what functions a certain peripheral has you can check them in one of two ways (you can use whichever is easier).


periph = peripheral.wrap(some side)
for k,v in pairs(periph) do
  print(k) --# will print all of the function names that the peripheral has
end

or


print(textutils.serialize(peripheral.getMethods(some side))) --# prints all of the function names of whatever peripheral is on the side specified.
Edited on 29 September 2015 - 04:17 AM
Caleb Ragnarok #21
Posted 29 September 2015 - 06:49 AM
ok, so if I change line 132 from

if b.getActive() == false do

to

if b.isOn() == false do
it should work

YUP! It worked!
all computers turn on when I insert the disk, and turn off when I take it out. and all computers connected turn back on when they are turned off. So I have my control computers for turbines, reactors and such shutdown the computer when there is an error and the script on the control disk reboots them..

perfect!
Edited on 29 September 2015 - 04:53 AM
Caleb Ragnarok #22
Posted 29 September 2015 - 04:45 PM
Valithor,

Thanx for all the help.

How would I change that event code, so if a certain disk(labeled ShipRegistration) is already IN the drive, the program just runs its program and doesnt wait for a disk to be ejected and then inserted?

I also want to add to my peripheral code so I can wrap a local disk drive but I want to do it as the code checks all peripherals. I got this so far, but its not wrapping.
Latest code here http://pastebin.com/G1SFcsjX


--Peripheral Search--
function peripheralSearch()

  print("Initializing Connections...")
  sleep(.2)
  
  for a,b in pairs(peripheral.getNames()) do

	if peripheral.getType(B)/>/> == "BigReactors-Turbine" then
	  print("Turbine Synced.")
	  Turbine[#Turbine+1] = peripheral.wrap(B)/>/>
	  TurbineCount = TurbineCount + 1
	  sleep(.15)
	
	elseif peripheral.getType(B)/>/> == "tile_blockcapacitorbank_name" then
	  print("Capacitor Bank Synced.")
	  Capacitor[#Capacitor+1] = peripheral.wrap(B)/>/>
	  CapConnections = CapConnections + 1
	  sleep(.15)
	
	elseif peripheral.getType(B)/>/> == "BigReactors-Reactor" then
	  print("Reactor Synced.")
	  Reactor[#Reactor+1] = peripheral.wrap(B)/>/>
	  ReactorCount = ReactorCount + 1
	  sleep(.15)
		  
	elseif peripheral.getType(B)/>/> == "computer" then
	  print("Computer Synced.")
	  Computers[#Computers+1] = peripheral.wrap(B)/>/>
	  CompCount = CompCount + 1
	  sleep(.15)
	
	elseif peripheral.getType(B)/>/> == "drive" then
	 TestDrive = peripheral.wrap(B)/>/>
	 for k,v in pairs(rs.getSides()) do
	  
	   if peripheral.getType(v) =='drive' then
		 LocalDrive = peripheral.wrap(v)	
	   end
	 end
		
	 if TestDrive == LocalDrive then
	   print("Command Drive Initialized")
	   sleep(.15)
	  
	 else
	   print("Incompatible Drive.")
	   wait = read()
	  
	 end

	else  
	  print("Incompatible Device.")
	  sleep(.15)
	end
  end

Edited on 29 September 2015 - 02:47 PM
valithor #23
Posted 29 September 2015 - 05:06 PM
So essentially if I understand, you want it to automatically restart the computers (would cause the disk startup to run/rerun), if a disk with a certain name is in the drive. Unfortunately I am in class right now, so I do not remember the exact function names, but I know that if you wrap a disk drive you can get the disk's name from that.

Since no event will be fired from the disk simply being in the drive you would want to put this in the if statement that checks for the timer event, so it would check for the disk in the drive every 5 seconds. That brings up the problem of the computers being restarted every 5 seconds, so you will also need a variable to keep track of whether or not the computers have been rebooted since you have inserted/removed a disk.

Below is more sudo code than anything, since I do not know the function names.

local hasRun = false
local drive = peripheral.wrap(drive side)

while true do
  local myTimer = os.startTimer(5) 
  local evt = {os.pullEvent()} 
  if evt[1] == "timer" and evt[2] == myTimer and on then

    if not hasRun and drive.getDiskLabel()=="label name" then --# checking if it has been run yet or not
      hasRun = not hasRun
      for k,v in pairs({peripheral.find("computer")}) do
        v.reboot() --# I think this is function name
      end
    end

    if Status == "normal" then
      normalOperation()
      systemStart(Started)

    elseif Status == "economy" then
      economy()
      systemStart(Started)

    end

  elseif evt[1] == "disk" then
    hasRun = false --# Changing hasRun back to false for the new disk
    for a,b in pairs(Computers) do 
      b.turnOn()
    end
    on = true 

  elseif evt[1] == "disk_eject" then

    for a,b in pairs(Computers) do 
      b.shutdown()
    end
    on = false 
  end
  os.cancelTimer(myTimer) 
end

If no one else has answered your other question by the time I get home, then I will answer it. The second question is one I would rather test before answering, as I do not wrap disk drives as peripherals very often.
Caleb Ragnarok #24
Posted 16 October 2015 - 03:42 AM
You're code you gave me for it to check for the disk works, however I need to to eject and reinsert the disk for the program to run. I can't get it to skip the timer and just run the program if the command disk is in the drive already.
valithor #25
Posted 16 October 2015 - 03:56 AM
You're code you gave me for it to check for the disk works, however I need to to eject and reinsert the disk for the program to run. I can't get it to skip the timer and just run the program if the command disk is in the drive already.

The code I gave you should check every 5 seconds if a disk with a specific label exists, and if it does then it will reboot all computers. However, once it runs the program on the disk, it will not run it again until a new disk is inserted. If I understand, then it is rebooting them, but it is also running all of the code in the timer as well as rebooting them. You can prevent this simply by adding a else to the place where you check for the disk.


local hasRun = false
local drive = peripheral.wrap(drive side)

while true do
  local myTimer = os.startTimer(5)
  local evt = {os.pullEvent()}
  if evt[1] == "timer" and evt[2] == myTimer and on then

	if not hasRun and drive.getDiskLabel()=="label name" then --# checking if it has been run yet or not
      hasRun = not hasRun
      for k,v in pairs({peripheral.find("computer")}) do
        v.reboot() --# I think this is function name
      end
    else --# will only run this code if there is not a disk, and it has not run yet

      if Status == "normal" then
        normalOperation()
        systemStart(Started)

      elseif Status == "economy" then
        economy()
        systemStart(Started)

      end
    end --# ending the else

  elseif evt[1] == "disk" then
    hasRun = false --# Changing hasRun back to false for the new disk
    for a,b in pairs(Computers) do
      b.turnOn()
    end
    on = true

  elseif evt[1] == "disk_eject" then

    for a,b in pairs(Computers) do
      b.shutdown()
    end
    on = false
  end
  os.cancelTimer(myTimer)
end
Edited on 16 October 2015 - 01:58 AM
Caleb Ragnarok #26
Posted 16 October 2015 - 04:10 AM
here's the full code. I cant get it to run without reinserting the disk

http://pastebin.com/Q8tMfBm1
valithor #27
Posted 16 October 2015 - 04:14 AM
here's the full code. I cant get it to run without reinserting the disk

http://pastebin.com/Q8tMfBm1

I believe the problem is with the on variable. On line 12 you are setting it to the variable on (at this point the variable on is nil), instead of true. Try changing that line to:

local on = true
Caleb Ragnarok #28
Posted 16 October 2015 - 04:21 AM
I get an error on line 339. attempt to index ? (a nl value)
Bomb Bloke #29
Posted 16 October 2015 - 06:18 AM
Well, 339 reads:

    if not hasRun and CommandDrive.getDiskLabel() == CommandLabel then --# checking if it has been run yet or not

"CommandDrive" is the only thing you're attempting to index on that line, so that must be your nil value. That's supposed to be a disk drive wrapped as a peripheral, but off the top of my head, I don't believe disk drives can be used that way. Try replacing "CommandDrive.getDiskLabel()" with "disk.getLabel("bottom")".
Lyqyd #30
Posted 16 October 2015 - 03:31 PM
Disk drives can indeed be wrapped as peripherals. IIRC, the "disk" API just uses peripheral.call at its core.
Caleb Ragnarok #31
Posted 16 October 2015 - 09:27 PM
in line 123, I have it getting the disk label and comparing it to the label I have stored in line 14. I have that as .getLabel and not .getDiskLabel. I'm going to try .getLabel instead and see what happens

same….
Edited on 16 October 2015 - 07:38 PM
Bomb Bloke #32
Posted 16 October 2015 - 10:54 PM
… because "CommandDrive" is still nil, so it doesn't matter whether you're trying to get the "getDiskLabel" key or the "getLabel" key out of it. It's not a table, so there are no keys in there at all.

If you tweak around line 123 like so:

    elseif peripheral.getType(b) == "drive" then
      print(b)
      if b.isPresent == true then
        DiskLabel = b.getLabel()
      end

… then does it print "bottom", or does it print something else?
Edited on 16 October 2015 - 08:55 PM
Caleb Ragnarok #33
Posted 18 October 2015 - 12:30 AM
It prints 'drive_1"
Caleb Ragnarok #34
Posted 18 October 2015 - 12:42 AM
I got the line code in line 123 to get the label and compare it by using disk.getlabel( B)/> and then comparing that to the saved string. I then put the same changes in the code that was given to me by Valithor. The code now does something new. Itsa new error now. :3:Expected string
Edited on 18 October 2015 - 12:09 AM