Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- Todo
- -- handle no door
- -- ensure we handle no display
- local version = 1.01
- local DoorConfig = {}
- local DoorScreen = {}
- local doorSettingsFile = "Door.Settings"
- local cabinPresent = false
- local displayHandle = nil
- --local floorMap = { }
- local KeepWaiting = true
- -- ######################################################
- -- ## Load the API ##
- -- ######################################################
- if fs.exists("/rom/apis/ECAPI") then --Check to make sure that the entered API exists
- os.loadAPI("/rom/apis/ECAPI")
- print("ECAPI loaded.")
- else
- print("That API does not exist!")
- end
- -- ######################################################
- -- ## Setup Configuration ##
- -- ######################################################
- local DefaultConfig = {}
- DefaultConfig = ECAPI.addConfigOption(DefaultConfig,"Version",version,"Please do not change this.")
- DefaultConfig = ECAPI.addConfigOption(DefaultConfig,"Network","","Elevator network name:")
- DefaultConfig = ECAPI.addConfigOption(DefaultConfig,"Modem","","Which side is the modem?",'side')
- DefaultConfig = ECAPI.addConfigOption(DefaultConfig,"Call","","Which side waits for call input?",'side')
- DefaultConfig = ECAPI.addConfigOption(DefaultConfig,"Detect","","Which side detects the Cabin?",'side')
- DefaultConfig = ECAPI.addConfigOption(DefaultConfig,"Display","","Which side is the Display monitor?",'side')
- DefaultConfig = ECAPI.addConfigOption(DefaultConfig,"Door","","Which side controls the Door?",'side')
- DefaultConfig = ECAPI.addConfigOption(DefaultConfig,"Debug","error","What level of debug output?")
- DefaultConfig = ECAPI.addConfigOption(DefaultConfig,"Floor","","Which floor is this?",'numeric')
- DefaultConfig = ECAPI.addConfigOption(DefaultConfig,"Description","","What description to display?")
- DefaultConfig = ECAPI.addConfigOption(DefaultConfig,"FloorPW","","Floor Password:",'pass')
- DefaultConfig = ECAPI.addConfigOption(DefaultConfig,"ConfigPW","","Config. Password:",'pass') -- note, this is per machine
- local function networkName()
- return ECAPI.getConfigOption(DoorConfig,"Network")
- end
- local function modemSide()
- return ECAPI.getConfigOption(DoorConfig,"Modem")
- end
- local function callSide()
- return ECAPI.getConfigOption(DoorConfig,"Call")
- end
- local function detectSide()
- return ECAPI.getConfigOption(DoorConfig,"Detect")
- end
- local function doorSide()
- return ECAPI.getConfigOption(DoorConfig,"Door")
- end
- local function displaySide()
- return ECAPI.getConfigOption(DoorConfig,"Display")
- end
- local function whichFloor()
- return ECAPI.getConfigOption(DoorConfig,"Floor")
- end
- local function floorDesc()
- return ECAPI.getConfigOption(DoorConfig,"Description")
- end
- -- ######################################################
- -- ## Terminal Functions ##
- -- ######################################################
- local function termClear()
- ECAPI.printDoorTemplate(DoorConfig)
- DoorScreen = ECAPI.setupScreen(DoorScreen)
- term.setCursorPos(3,18)
- write("Command: ")
- end
- local function justPrintInfo(DoorScreen,moduleID,sourceID,floorID,newLine)
- local t = "["..ECAPI.padLeft(moduleID,6," ").."]"
- t = t .. "["..ECAPI.padLeft(sourceID,4," ")..":"
- t = t .. ECAPI.padLeft(floorID,2," ").."]: " .. newLine
- if (ECAPI.getConfigOption(DoorConfig,"Debug") == "info") then
- DoorScreen = ECAPI.justPrintLine(DoorScreen,t)
- end
- return DoorScreen
- end
- local function justPrintLine(newLine)
- DoorScreen = ECAPI.justPrintLine(DoorScreen,newLine)
- end
- -- functions?
- local function registerFloor()
- -- Now that we're started, notify the network controller
- ECAPI.openModem(modemSide())
- --password support:
- local pass = ECAPI.getConfigOption(DoorConfig,"FloorPW")
- if (pass == nil) then pass = "" else pass = ECAPI.encrypt(pass,networkName()) end
- -- Descriptions are flagged with a * if it's password protected
- ECAPI.broadcast(networkName(),"addFloor|"..whichFloor().."|"..floorDesc().."|"..pass)
- end
- local function powerToggle(whichSide,stateStr)
- local state = false
- if string.lower(stateStr) == "true" then
- state = true
- end
- redstone.setOutput(whichSide,state)
- end
- local function displayFloor(text)
- peripheral.call(displaySide(), "setCursorPos", 1, 1)
- peripheral.call(displaySide(), "setTextScale", 2.2)
- peripheral.call(displaySide(), "write", ECAPI.padLeft(text,3," "))
- end
- local function displayUp(text)
- peripheral.call(displaySide(), "setTextScale", 2.2)
- peripheral.call(displaySide(), "setCursorPos", 3, 2)
- peripheral.call(displaySide(), "write", text)
- end
- local function displayDown(text)
- peripheral.call(displaySide(), "setTextScale", 2.2)
- peripheral.call(displaySide(), "setCursorPos", 3, 2)
- peripheral.call(displaySide(), "write", text)
- end
- local function reconfig(args)
- if (ECAPI.checkPassword(DoorScreen,DoorConfig,"ConfigPW")) then
- local what = args[1]
- if (what == nil) or (what == "") then
- DoorConfig = DefaultConfig
- createNewSettings()
- else
- what = ECAPI.caseCheck(DoorConfig,what)
- if (args[2] == nil) then
- DoorScreen, DoorConfig = ECAPI.getConfigFromUser(DoorScreen, DoorConfig,what)
- else
- DoorConfig = ECAPI.setConfigOption(DoorConfig,what,table.concat(args," ",2))
- end
- -- Make sure to SAVE changes
- ECAPI.table_save(DoorConfig,doorSettingsFile)
- -- notify the network's Motor controller
- registerFloor()
- -- Check if the cabin is present at the end of startup
- if (redstone.getInput(callSide()) == true) then
- cabinPresent = true
- end
- end
- else
- justPrintLine("Invalid password.")
- end
- end
- local function sendFloorPW(sendID)
- ECAPI.send(sendID,'floorpw|'..ECAPI.encrypt(ECAPI.getConfigOption(DoorConfig,'FloorPW'),networkName()))
- end
- -- Control functions
- local function openDoor()
- --ECAPI.printLine("open door")
- redstone.setOutput(doorSide(),false)
- end
- local function closeDoor()
- --ECAPI.printLine("close door")
- redstone.setOutput(doorSide(),true)
- end
- -- ######################################################
- -- ## Settings Functions ##
- -- ######################################################
- local function createNewSettings()
- DoorConfig = DefaultConfig
- termClear()
- --DoorScreen = ECAPI.printConfig(DoorConfig,DoorScreen)
- -- Confirm settings with the user, then save to file
- DoorScreen = ECAPI.addPrintLine(DoorScreen,"No settings file found. Setup method:")
- justPrintLine(" 1) Normal Configuration")
- justPrintLine(" 2) Import from Floor")
- local setupMethod = ECAPI.getInput("Which: ")
- if (setupMethod == nil) or (setupMethod == "") then
- setupMethod = 1
- end
- setupMethod = tonumber(setupMethod)
- if setupMethod == 1 then
- -- To ensure this code plays nice with multiple elevators, Unique network names are required (as best as can)
- DoorScreen, DoorConfig = ECAPI.getConfigFromUser(DoorScreen,DoorConfig,"Network")
- DoorScreen = ECAPI.printConfig(DoorConfig,DoorScreen,"Network")
- -- Confirm modem side
- DoorScreen, DoorConfig = ECAPI.getConfigFromUser(DoorScreen,DoorConfig,"Modem")
- DoorScreen = ECAPI.printConfig(DoorConfig,DoorScreen,"Modem")
- -- Confirm call input side
- DoorScreen, DoorConfig = ECAPI.getConfigFromUser(DoorScreen,DoorConfig,"Call")
- DoorScreen = ECAPI.printConfig(DoorConfig,DoorScreen,"Call")
- -- Confirm detect input side
- DoorScreen, DoorConfig = ECAPI.getConfigFromUser(DoorScreen,DoorConfig,"Detect")
- DoorScreen = ECAPI.printConfig(DoorConfig,DoorScreen,"Detect")
- -- Confirm display output side
- DoorScreen, DoorConfig = ECAPI.getConfigFromUser(DoorScreen,DoorConfig,"Display")
- DoorScreen = ECAPI.printConfig(DoorConfig,DoorScreen,"Display")
- -- Confirm door output side
- DoorScreen, DoorConfig = ECAPI.getConfigFromUser(DoorScreen,DoorConfig,"Door")
- DoorScreen = ECAPI.printConfig(DoorConfig,DoorScreen,"Door")
- -- Confirm floor #
- DoorScreen, DoorConfig = ECAPI.getConfigFromUser(DoorScreen,DoorConfig,"Floor")
- DoorScreen = ECAPI.printConfig(DoorConfig,DoorScreen,"Floor")
- -- Confirm floor description
- DoorScreen, DoorConfig = ECAPI.getConfigFromUser(DoorScreen,DoorConfig,"Description")
- DoorScreen = ECAPI.printConfig(DoorConfig,DoorScreen,"Description")
- -- Debug output level
- DoorScreen, DoorConfig = ECAPI.getConfigFromUser(DoorScreen,DoorConfig,"Debug")
- DoorScreen = ECAPI.printConfig(DoorConfig,DoorScreen,"Debug")
- else
- -- Still need network name, modem side, and new floor #
- -- To ensure this code plays nice with multiple elevators, Unique network names are required (as best as can)
- DoorScreen, DoorConfig = ECAPI.getConfigFromUser(DoorScreen,DoorConfig,"Network")
- DoorScreen = ECAPI.printConfig(DoorConfig,DoorScreen,"Network")
- -- Confirm modem side
- DoorScreen, DoorConfig = ECAPI.getConfigFromUser(DoorScreen,DoorConfig,"Modem")
- DoorScreen = ECAPI.printConfig(DoorConfig,DoorScreen,"Modem")
- -- Confirm floor #
- DoorScreen, DoorConfig = ECAPI.getConfigFromUser(DoorScreen,DoorConfig,"Floor")
- DoorScreen = ECAPI.printConfig(DoorConfig,DoorScreen,"Floor")
- -- Now request the info from which floor?
- local sourceFloor = ECAPI.getInput("Source floor? ")
- ECAPI.openModem(modemSide())
- justPrintLine("Broadcasting: setupcopy|"..sourceFloor)
- ECAPI.broadcast(networkName(),"setupcopy|"..sourceFloor)
- -- wait until we get the right rednet event
- local setupCopied = false
- local newSetup = { }
- repeat
- local sendID, rawmessage, distance = rednet.receive()
- local packet = ECAPI.explode("|",rawmessage)
- if packet[1] == networkName() then
- if string.lower(packet[2]) == 'setupdata' then
- newSetup = textutils.unserialize(packet[3])
- setupCopied = true
- end
- end
- until setupCopied == true
- -- copy the data
- DoorConfig = ECAPI.setConfigOption(DoorConfig,"Call",ECAPI.getConfigOption(newSetup,"Call"))
- DoorConfig = ECAPI.setConfigOption(DoorConfig,"Detect",ECAPI.getConfigOption(newSetup,"Detect"))
- DoorConfig = ECAPI.setConfigOption(DoorConfig,"Display",ECAPI.getConfigOption(newSetup,"Display"))
- DoorConfig = ECAPI.setConfigOption(DoorConfig,"Door",ECAPI.getConfigOption(newSetup,"Door"))
- DoorConfig = ECAPI.setConfigOption(DoorConfig,"Debug",ECAPI.getConfigOption(newSetup,"Debug"))
- DoorConfig = ECAPI.setConfigOption(DoorConfig,"Description",ECAPI.getConfigOption(newSetup,"Description"))
- DoorConfig = ECAPI.setConfigOption(DoorConfig,"FloorPW",ECAPI.getConfigOption(newSetup,"FloorPW"))
- DoorConfig = ECAPI.setConfigOption(DoorConfig,"ConfigPW",ECAPI.getConfigOption(newSetup,"ConfigPW"))
- end
- -- Write to file
- ECAPI.table_save(DoorConfig,doorSettingsFile)
- termClear()
- if (setupMethod == 2) then justPrintLine("Make sure to review CONFIG settings.") end
- end
- local function startupConfirmation()
- -- Check if there's a settings file
- if fs.exists(doorSettingsFile) then
- termClear()
- DoorConfig = ECAPI.table_load(doorSettingsFile)
- ECAPI.verifyConfig(DefaultConfig,DoorConfig)
- termClear()
- DoorScreen = ECAPI.justPrintLine(DoorScreen,"Settings loaded.")
- os.sleep(0.5)
- else
- createNewSettings()
- end
- -- notify the network's Motor controller
- registerFloor()
- -- Check if the cabin is present at the end of startup
- if (redstone.getInput(callSide()) == true) then
- cabinPresent = true
- end
- -- Close all doors by default
- closeDoor()
- end
- -- ######################################################
- -- ## Input Actions ##
- -- ######################################################
- -- MAX Topic summary: 36 characters
- -- |-----------------------------------|
- local helpTopics = {
- ["reboot"] = { "Restart this terminal." ,},
- ["clear"] = { "Refresh the terminal screen." ,},
- ["config"] = { "Prints the current settings. Will not print",
- "any set passwords." ,},
- ["reconfig"] = { "With no parameters, re-run the whole setup.",
- "RECONFIG [option] to change a single setting",
- "Note: Reconfig can be password protected via",
- "the ConfigPW setting. If this password is",
- "lost, you will need server admin help or be",
- "forced to recreate the terminal." ,},
- ["broadcast"] = { "Manually broadcast <message>",},
- ["send"] = { "Manually send <id> <message>",},
- ["power"] = { "Manually toggle power <side>",},
- }
- local function printHelp(topic)
- justPrintLine("Help on '"..string.upper(topic).."':")
- local t = helpTopics[topic]
- for _, text in ipairs(t) do
- justPrintLine(" "..text)
- end
- end
- local commands = {
- ["help"] = function (x)
- if (x[1] ~= nil) then
- printHelp(x[1])
- else
- justPrintLine("Please use HELP [COMMAND]. ? for Command List")
- end
- end,
- ["reboot"] = function (x) os.reboot() end,
- ["clear"] = function (x) termClear() end,
- ["broadcast"] = function (x)
- DoorScreen = justPrintInfo(DoorScreen,"REDNET",nil,nil,"Broadcast: "..table.concat(x," ",2))
- ECAPI.broadcast(networkName(),table.concat(x," "))
- end,
- ["send"] = function (x)
- DoorScreen = justPrintInfo(DoorScreen,"REDNET",nil,nil,"Send("..tonumber(x[1]).."): "..table.concat(x," ",2))
- ECAPI.send(networkName(),tonumber(x[1]),table.concat(x," ",2))
- end,
- ["config"] = function (x)
- justPrintLine("Current Configuration:")
- justPrintLine("-------------------------------")
- ECAPI.printConfig(DoorConfig,DoorScreen)
- end,
- ["reconfig"] = function (x) reconfig(x) end,
- ["power"] = function (x) powerToggle(x[1], x[2]) end,
- }
- local function printCommands()
- local col = 1
- local row = {}
- for named, _ in pairs(commands) do
- if (col < 5) then row[col] = string.upper(named) end
- col = col + 1
- if (col == 5) then
- justPrintLine(ECAPI.padLeft(row[1],12," ")..ECAPI.padLeft(row[2],12," ")..ECAPI.padLeft(row[3],12," ")..ECAPI.padLeft(row[4],11," "))
- row = {}
- col = 1
- end
- end
- if (col > 1) then
- -- handles 'remainders'
- justPrintLine(ECAPI.padLeft(row[1],12," ")..ECAPI.padLeft(row[2],12," ")..ECAPI.padLeft(row[3],12," ")..ECAPI.padLeft(row[4],11," "))
- end
- end
- local function processCommands(input)
- local arg = ECAPI.explode(" ",input)
- local command = arg[1]
- table.remove(arg,1)
- if ECAPI.tableContainsKey(commands, command) then
- commands[command](arg)
- else
- justPrintLine("Unknown command '"..command.."'. Commands are:")
- printCommands()
- end
- end
- -- ######################################################
- -- ## Handler Functions ##
- -- ######################################################
- -- User input listener
- local function userConsole()
- while KeepWaiting do
- processCommands(ECAPI.getInput("Command:"))
- end
- end
- -- Redstone listener
- local function redstoneListener()
- while KeepWaiting do
- event, param1, param2 = os.pullEvent("redstone")
- -- The players have pushed a button
- if event == "redstone" and redstone.getInput(callSide()) == true then
- --ECAPI.printLine("Call detection")
- ECAPI.broadcast(networkName(),"call")
- end
- -- if the cabin was not present, and we get a redstone on detect side, it just arrived
- if (event == "redstone") and (redstone.getInput(detectSide()) == true) then
- --ECAPI.printLine("Cabin detection")
- cabinPresent = true
- ECAPI.broadcast(networkName(),"arrival|"..whichFloor())
- displayFloor(whichFloor())
- end
- -- if the redstone on the detect side shuts off, the cabin just departed
- if (event == "redstone") and (redstone.getInput(detectSide()) == false) then
- --ECAPI.printLine("Cabin departure")
- cabinPresent = false
- ECAPI.broadcast(networkName(),"departure")
- end
- end
- end
- -- Rednet listener
- local function rednetListener()
- ECAPI.openModem(modemSide())
- while KeepWaiting do
- local sendID, rawmessage, distance = rednet.receive()
- local packet = ECAPI.explode("|",rawmessage)
- if packet[1] == networkName() then
- --ECAPI.printLine("Message received ["..sendID.."]: "..table.concat(packet,"|",2))
- if string.lower(packet[2]) == 'controlreset' then
- -- If the control computer issues a reset broadcast, re-register with it.
- os.sleep(math.random(2.0,4.0))
- --ECAPI.printLine("Re-registering")
- registerFloor()
- if (redstone.getInput(detectSide()) == true) then
- -- also call out if the cabin is at this level
- ECAPI.broadcast(networkName(),"arrival")
- end
- elseif string.lower(packet[2]) == 'opendoor' then
- --ECAPI.printLine("open door request "..ECAPI.padLeft(packet[3],5,' ').."?"..os.getComputerID())
- if packet[3] == tostring(os.getComputerID()) then
- openDoor()
- else
- closeDoor()
- end
- elseif string.lower(packet[2]) == 'closedoor' then
- closeDoor()
- elseif string.lower(packet[2]) == 'arrival' then
- displayFloor(packet[3])
- elseif string.lower(packet[2]) == 'displayup' then
- displayUp(packet[3])
- elseif string.lower(packet[2]) == 'displaydown' then
- displayDown(packet[3])
- elseif string.lower(packet[2]) == 'locate' then
- if (redstone.getInput(detectSide()) == true) then
- -- also call out if the cabin is at this level
- ECAPI.broadcast(networkName(),"arrival")
- end
- elseif string.lower(packet[2]) == 'reboot' then
- os.reboot()
- elseif string.lower(packet[2]) == 'sendpw' then
- sendFloorPW(sendID)
- elseif string.lower(packet[2]) == 'setupcopy' then
- if tonumber(packet[3]) == whichFloor() then
- ECAPI.send(networkName(),sendID,'setupdata|'..textutils.serialize(DoorConfig))
- end
- end
- end
- end
- end
- -- ######################################################
- -- ## Actual Run Program ##
- -- ######################################################
- startupConfirmation()
- parallel.waitForAll(userConsole,redstoneListener,rednetListener)
- --while KeepWaiting do
- -- ECAPI.printLine("")
- -- processCommands(ECAPI.getInput("Operation:"))
- --end
- --startupConfirmation()
- --openModem()
- --broadcast("addFloor|1")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement