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

Universal Touchpad Door Lock

Started by Calimore, 12 May 2013 - 10:51 AM
Calimore #1
Posted 12 May 2013 - 12:51 PM
I came back to Minecraft just the other day because I found out about ComputerCraft and was playing around a little bit with it and instantly a lot of ideas were flying through my head what one could do with this great addon.

I know there are a ton of door lock programs here and I have also seen a couple of programs using the advanced monitors with a touchpad. Still I determined a touchpad door lock should be my first program using ComputerCraft and LUA. I have tried to keep everything as generic as possible.

The beginning of the code defines a couple of variables which should make it easy to customize the code to different setups without having to go through the whole thing. Here's what I tried to keep in mind when writing this:
- password length should be dynamic (have a longer password if you like without having to change the code)
- the output of the redstone signal and the location of the monitor relative to the computer should be easily customizable without having to touch the code itself

The output to the monitor is coded for a single monitor setup. One thing I'd like to add later is to dynamically change the output (e.g. center it on screen) depending on the monitor size attached to the computer.

So maybe some newbies like me might have a use for these lines of code and maybe the Pros have some suggestions on how to make this thing more efficient/elegant.

Here we go:



-- Variables -----------------------------------------------
local password = "123"
local keypadtable = {{3,2,"1"}, {4,2,"2"}, {5,2,"3"}, {3,3,"4"}, {4,3,"5"}, {5,3,"6"}, {3,4,"7"}, {4,4,"8"}, {5,4,"9"}}
local dooropendelay = 4
local errordelay = 3
local monitorlocation = 'back'
local redstonesignalside = 'left'

------------------------------------------------------------

local monitor = peripheral.wrap(monitorlocation)
local maxx, maxy = monitor.getSize()

local function idleScreen ()
  monitor.clear()
  monitor.setCursorPos(2,2)
  monitor.write("Enter")
  monitor.setCursorPos(3,3)
  monitor.write("PIN")
end

local function loginOK ()
  monitor.clear()
  monitor.setCursorPos(1,3)
  monitor.write("Welcome")
end

local function loginFail ()
  monitor.clear()
  monitor.setCursorPos(2,3)
  monitor.write("Error")
end

local function printKeyPad ()
  monitor.clear()
  for i=1,#keypadtable do
	monitor.setCursorPos(keypadtable[i][1],keypadtable[i][2])
	monitor.write(keypadtable[i][3])
  end
end

local function getKeyFromPad (xclick, yclick)
  for i=1,#keypadtable do
	if ((keypadtable[i][1] == xclick) and (keypadtable[i][2] == yclick)) then
	  return (keypadtable[i][3])
	end
  end
  return ('')
end

local function openDoor ()
  redstone.setOutput (redstonesignalside, true)
end

local function closeDoor ()
  redstone.setOutput (redstonesignalside, false)
end

-- MAIN ------------------------------------------------------------

while true do
  idleScreen()
  local pwentered = ''

  -- Get first keypress and show pinpad
  local event, monside, xpos, ypos = os.pullEvent()
  if event == 'monitor_touch' then
	print ('* Starting keypad entry')
	printKeyPad()
  end

  while (tonumber(string.len(pwentered)) < tonumber(string.len(password))) do
	local pressed = ''
	local event, monside, xpos, ypos = os.pullEvent()

	if event == 'monitor_touch' then
	 local pressed = tostring(getKeyFromPad (xpos, ypos))
	 if pressed ~= "" then
	  pwentered = pwentered .. pressed
	  print ("* Pressed: " .. pressed)
	 end
	end
  end

  if (pwentered == password) then
	print ('* Login SUCCESS')
	loginOK ()
	openDoor ()
	sleep (dooropendelay)
	closeDoor ()
  else
	print ('* Login FAIL')
	loginFail ()
	sleep (errordelay)
  end
end

What do you think?
Lyqyd #2
Posted 12 May 2013 - 05:02 PM
Split into new topic.
Bubba #3
Posted 12 May 2013 - 10:26 PM
You should report the post and request to have it moved to the Programs section instead as it doesn't really belong in AaP.

But anywho, this is a pretty good job for a first program (Educated guess: you've programmed before). Keeping things dynamic is great, and I like your use of tables for the keypad rather than having a large if/elseif block.

To implement the variable monitor size, here's a few hints (only open the spoiler if you don't mind getting answers the easy way):
Spoiler
  1. Have your program get the x/y of each keypad number by adding the number in each one by monWidth/2. For example:

local monX, monY = monitor.getSize()
local hX = math.ceil(monX/2)
local hY = math.ceil(monY/2)

local keypadtable = {
  {{hX-1, hY-1, "1"}, {hX, hY-1, "2"}, {hX+1, hY-1,"3"},
  {{hX-1, hY, "4"}, --And I think you get my drift
}


Better yet, why not have a function which generates the keypad table for you?


local function generateTable(hX, hY)
  local _temp = {}
  local yPos = hY-1
  local xPos = hX-1
  for i=1,9 do
    _temp[#_temp+1] = {
      xPos, yPos, tostring(i)
    }
    xPos = i%3==0 and hX-1 or xPos + 1 --This sort of and/or format is called a ternary operator
    yPos = i%3==0 and yPos + 1 or yPos
  end
  return _temp
end

local keypadtable = generateTable(math.ceil(monX/2), math.ceil(monY/2))

Check out the ternary operator bit here: http://lua-users.org/wiki/TernaryOperator

Like the program, and keep up the good work!
Calimore #4
Posted 13 May 2013 - 06:07 AM
Thanks for your feedback! I have programmed before that's true but this was some time ago. When writing this little Touch Pinpad thingy I had about 25 tabs open in my browser because my skills are quite rusty and I have to get a grip of LUA syntax, operators and so on…

Thank you also for your great code example… I think I won't copy it but instead do a rewrite of what you showed. This way (I hope) I will remember what I did at some later point. :P/>
Jian #5
Posted 14 May 2013 - 11:55 PM
Hey man this looks pretty good. Check out my version from a while ago. I have been thinking about adding a compact version/option
http://www.computercraft.info/forums2/index.php?/topic/11959-touchscreen-monitor-pin-keypad/
Calimore #6
Posted 19 May 2013 - 07:58 PM
Hey man this looks pretty good. Check out my version from a while ago. I have been thinking about adding a compact version/option
http://www.computerc...tor-pin-keypad/

Wow… Incredible…! :o/>
Actually I came here to "show off" (if you can call it that) what I wrote today but I won't be able to top that… :lol:/>

Anyway here's what I did today:

I have built a hidden stair in the floor with a redstone mechanism. As I am not using redpower (with those awesome multicables - are there any replacements for that?) and redstone mechanisms tend to get quite large I decided to control opening and closing of my stairs with 3 different redstone signals (left and right cover of the stairs + rise of 1 half slab for the first step) which are sent out by 3 computers.

Pic 1 (Slave): http://bayimg.com/mamoMaAEM
Pic 2 (Slave): http://bayimg.com/mamOOaaeM

These 3 computers should just act as a slave and send out a redstone signal whenever told to. The master should again be a computer with a touch screen but without being limited to a keypad of (0/1 to 9).

Pic 3 (Master + hidden stairs): http://bayimg.com/nAMOmAAem
Pic 4 (Master + opened stairs): http://bayimg.com/namOOaAem

When the correct password was entered into the monitor of the master it should send out a WLAN message to all three slaves which then simply trigger a redstone signal.

The code is far from complete and there are mutliple to-dos on my list, but here's what I've been playing around with… So maybe again some newbies might want to check parts of it out… Most of the pros will yawn though… :rolleyes:/>

- calicommAPI: I wanted to experiment with "libraries"/"APIs" so there's a small library which takes care of initializing attached modems, returning handles to them, as well as opening &amp; closing of listening ports and some error handling (although it is not completely reliable in the way it returns errors and so on)

http://pastebin.com/VKxFFjB0


- rsslave: Slaves should all share the same code (without ANY modification). As the redstone signals come out of different sides I didn't want to use a global for that in my code. So I decided to read the side the redstone signal should be output to from a config file. There are still a lot of globals in slave code that should probably also go to the config file. As I didn't want wo waste too many of those 65533 channels I implemented a very very simple protocol which uses adressing in the form of a computer id and "authentication" with a shared secret. I know this is not safe at all but hey, that's what I did… :P/> That way I am able to have all slaves listening on the same port/channel.

I'd also like to add an acknowledgement of receiving and executing a command on the slave back to the master some time later… Most of the code in here could also go to the libarary above.

http://pastebin.com/dkJDbd31


- stairctrl: The staircontrol is again a computer with a touchpad. This time it allows to display any kind of multiline text, automatically centers it on screen and returns the pressed characters as a password. Any character displayed acts as a input key.

http://pastebin.com/SKFA0Rsy


Well there you have it… Not the cleanest/best code but it works and fills all the requirements I have put on myself… Learning by doing. B)/>
CreeperGoBoom #7
Posted 27 November 2018 - 04:50 AM
I came back to Minecraft just the other day because I found out about ComputerCraft and was playing around a little bit with it and instantly a lot of ideas were flying through my head what one could do with this great addon.

I know there are a ton of door lock programs here and I have also seen a couple of programs using the advanced monitors with a touchpad. Still I determined a touchpad door lock should be my first program using ComputerCraft and LUA. I have tried to keep everything as generic as possible.

The beginning of the code defines a couple of variables which should make it easy to customize the code to different setups without having to go through the whole thing. Here's what I tried to keep in mind when writing this:
- password length should be dynamic (have a longer password if you like without having to change the code)
- the output of the redstone signal and the location of the monitor relative to the computer should be easily customizable without having to touch the code itself

The output to the monitor is coded for a single monitor setup. One thing I'd like to add later is to dynamically change the output (e.g. center it on screen) depending on the monitor size attached to the computer.

So maybe some newbies like me might have a use for these lines of code and maybe the Pros have some suggestions on how to make this thing more efficient/elegant.

Here we go:



-- Variables -----------------------------------------------
local password = "123"
local keypadtable = {{3,2,"1"}, {4,2,"2"}, {5,2,"3"}, {3,3,"4"}, {4,3,"5"}, {5,3,"6"}, {3,4,"7"}, {4,4,"8"}, {5,4,"9"}}
local dooropendelay = 4
local errordelay = 3
local monitorlocation = 'back'
local redstonesignalside = 'left'

------------------------------------------------------------

local monitor = peripheral.wrap(monitorlocation)
local maxx, maxy = monitor.getSize()

local function idleScreen ()
  monitor.clear()
  monitor.setCursorPos(2,2)
  monitor.write("Enter")
  monitor.setCursorPos(3,3)
  monitor.write("PIN")
end

local function loginOK ()
  monitor.clear()
  monitor.setCursorPos(1,3)
  monitor.write("Welcome")
end

local function loginFail ()
  monitor.clear()
  monitor.setCursorPos(2,3)
  monitor.write("Error")
end

local function printKeyPad ()
  monitor.clear()
  for i=1,#keypadtable do
	monitor.setCursorPos(keypadtable[i][1],keypadtable[i][2])
	monitor.write(keypadtable[i][3])
  end
end

local function getKeyFromPad (xclick, yclick)
  for i=1,#keypadtable do
	if ((keypadtable[i][1] == xclick) and (keypadtable[i][2] == yclick)) then
	  return (keypadtable[i][3])
	end
  end
  return ('')
end

local function openDoor ()
  redstone.setOutput (redstonesignalside, true)
end

local function closeDoor ()
  redstone.setOutput (redstonesignalside, false)
end

-- MAIN ------------------------------------------------------------

while true do
  idleScreen()
  local pwentered = ''

  -- Get first keypress and show pinpad
  local event, monside, xpos, ypos = os.pullEvent()
  if event == 'monitor_touch' then
	print ('* Starting keypad entry')
	printKeyPad()
  end

  while (tonumber(string.len(pwentered)) < tonumber(string.len(password))) do
	local pressed = ''
	local event, monside, xpos, ypos = os.pullEvent()

	if event == 'monitor_touch' then
	 local pressed = tostring(getKeyFromPad (xpos, ypos))
	 if pressed ~= "" then
	  pwentered = pwentered .. pressed
	  print ("* Pressed: " .. pressed)
	 end
	end
  end

  if (pwentered == password) then
	print ('* Login SUCCESS')
	loginOK ()
	openDoor ()
	sleep (dooropendelay)
	closeDoor ()
  else
	print ('* Login FAIL')
	loginFail ()
	sleep (errordelay)
  end
end

What do you think?

Hi,

Great and very useful script, I have a few tips for you on this code however.

This block of code causes instability: line 78-84

if (event == 'monitor_touch') and interact then
		 local pressed = tostring(getKeyFromPad (xpos, ypos))
		 if pressed ~= "" then
		  pwentered = pwentered .. pressed
		  print ("* Pressed: " .. pressed)
		 end
		end
I was using this script today and found that the above code block caused the keypad to randomly do one of the following causing LoginFail to trgger:
-Not showing the keypad at all
-Keypad shows after Enter Pin, however the interaction with the screen also triggers a keypad entry BEFORE the keypad appears
-Keypad shows as intended however the next interaction doesn't register.

My tip for you here is, don't use os.pullevent unless you need it, avoid using it multiple times within the same while statement. In this instance if you still intended the user to interact in order to bring up the keypad. Your code should look like this: (I added a interact toggle for stability, so far it works perfect, LoginFail does fire once at startup but it doesnt seem to affect the functionality)
https://pastebin.com/wkgUj5w3

I other words, to avoid the extra os.pullevent from triggering unwantedly, you need to place it under a interact toggle or something else that wont immediately get triggered until the event you want actually has triggered as I have above

However for functionality purposes it makes more sense if the keypad is already showing instead of "Enter PIN":
https://pastebin.com/1g36zb9p

Here is a breakdown of what I did for the second link from your original code
-Remove line 65-70 as its not needed for keypad position detection
-Replace line 62 Idlescreen() with PrintKeypad()

Hope this helps :D/>

Keep up the good work ;)/>

Edit: big time oops, i didn't realize just how old this thread was, maybe my reply will help someone in future…? hmm
Edited on 27 November 2018 - 08:16 AM