From ebb1a77a64bae22ea117cb2657a18963aaddcc7e Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 14 May 2023 20:11:37 +0200 Subject: [PATCH] version 1.0.0 --- README.md | 30 ++++- config.json | 1 + images/lua_parameters.png | Bin 0 -> 12026 bytes images/mounting_scheme.png | Bin 0 -> 38176 bytes images/screen_access_deniedpng.png | Bin 0 -> 482926 bytes images/screen_access_granted.png | Bin 0 -> 232296 bytes source/unit/onStart.lua | 187 +++++++++++++++++++++++++++++ source/unit/onStop.lua | 1 + 8 files changed, 217 insertions(+), 2 deletions(-) create mode 100644 config.json create mode 100644 images/lua_parameters.png create mode 100644 images/mounting_scheme.png create mode 100644 images/screen_access_deniedpng.png create mode 100644 images/screen_access_granted.png create mode 100644 source/unit/onStart.lua create mode 100644 source/unit/onStop.lua diff --git a/README.md b/README.md index 61191ce..8a51cb7 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,28 @@ -# du simple access control - a script to control access with doors of force fields +# Du-Simple-Access-Control + +A script to control access with doors of force fields. + +- It can control several doors and force fields at the same time. +- You can manage access with user name, user id, organisation name or organisation id. + +## How to install + +1. copy the script on the board +2. link the doors you want to control to the board +3. link the force fields you want to control to the board +4. link the screens where you want to diplay the access is granted or not to the board +5. link the zone detection to the board (with a relay if you want to use several). The link must be done from the detector to the board (blue link, not green). + +## Mounting Scheme + +![Mounting Scheme]() + +## How to configure + +In the Lua Parameters of the board (right click on the board > advanced > Lua parameters), you can change the following parameters: +- AllowedUsersId: the list of the users id allowed to access, comma separated. +- AllowedUsersName: the list of the users name allowed to access, comma separated, case sensitive. +- AllowedUserOrgsId: the list of the organisations id allowed to access, comma separated. +- AllowedUserOrgsName: the list of the organisations name allowed to access, comma separated, case sensitive. + +![Lua Parameters]() \ No newline at end of file diff --git a/config.json b/config.json new file mode 100644 index 0000000..0733044 --- /dev/null +++ b/config.json @@ -0,0 +1 @@ +{"slots":{"0":{"name":"slot1","type":{"events":[],"methods":[]}},"1":{"name":"slot2","type":{"events":[],"methods":[]}},"2":{"name":"slot3","type":{"events":[],"methods":[]}},"3":{"name":"slot4","type":{"events":[],"methods":[]}},"4":{"name":"slot5","type":{"events":[],"methods":[]}},"5":{"name":"slot6","type":{"events":[],"methods":[]}},"6":{"name":"slot7","type":{"events":[],"methods":[]}},"7":{"name":"slot8","type":{"events":[],"methods":[]}},"8":{"name":"slot9","type":{"events":[],"methods":[]}},"9":{"name":"slot10","type":{"events":[],"methods":[]}},"-1":{"name":"unit","type":{"events":[],"methods":[]}},"-3":{"name":"player","type":{"events":[],"methods":[]}},"-2":{"name":"construct","type":{"events":[],"methods":[]}},"-4":{"name":"system","type":{"events":[],"methods":[]}},"-5":{"name":"library","type":{"events":[],"methods":[]}}},"handlers":[{"code":"--version 1.0.0\n\n--LUA PARAMETERS\nlocal AllowedUsersId = \"\" --export: the list of all IDs, comma separated\nlocal AllowedUsersName = \"Jericho\" --export: the list of all names, comma separated (Case sensitive)\nlocal AllowedUserOrgsId = \"18261\" --export: the list of all organisation IDs, comma separated\nlocal AllowedUserOrgsName = \"Federatis\" --export: the list of all organisation Names, comma separated (Case sensitive)\n\n--Libraries\n--split is a function to split a string in a table with a delimiter written by Jericho\nfunction split(s,d)local t={}s:gsub(\"[^\"..d..\"]+\",function(w)table.insert(t,w)end)return t end\n\n--hide unit widget\nunit.hideWidget()\n\n--auto detecting the door, force fields and the screens\nDoors = {}\nFields = {}\nScreens = {}\nfor slotName,slot in pairs(unit) do\n if\n type(slot) == \"table\"\n and type(slot.export) == \"table\"\n and slot.getClass\n then\n local ElementClass = slot.getClass():lower()\n if ElementClass:find(\"doorunit\") then\n table.insert(Doors, slot)\n elseif ElementClass:find(\"forcefieldunit\") then\n table.insert(Fields, slot)\n slot.activate()\n elseif ElementClass:find(\"screenunit\") then\n table.insert(Screens, slot)\n slot.activate()\n else\n system.print(ElementClass)\n end\n end\nend\n\nfunction getRenderScript(access)\n local color = \"red\"\n local message = \"Access Denied\"\n if access then\n color = \"green\"\n message = \"Access Granted\"\n end\n return [[\n setBackgroundColor(15/255,24/255,29/255)\n local rx,ry = getResolution()\n local cx, cy = getCursor()\n if vmode then\n ry,rx = getResolution()\n cy, cx = getCursor()\n cx = rx - cx\n if vmode_side == \"right\" then\n cy = ry - cy\n cx = rx - cx\nend\nend\n\n local smallBold=loadFont('Play-Bold',40)\n local bigBold=loadFont('Play-Bold',64)\n\n local front=createLayer()\n local back=createLayer()\n setDefaultStrokeColor( back,Shape_Line,0,0,0,0.5)\n setDefaultShadow( back,Shape_Line,6,0,0,0,0.5)\n setDefaultFillColor( front,Shape_BoxRounded,249/255,212/255,123/255,1)\n setDefaultFillColor( front,Shape_Text,0,0,0,1)\n setDefaultFillColor( front,Shape_Box,0.075,0.125,0.156,1)\n setDefaultFillColor( front,Shape_Text,0.710,0.878,0.941,1)\n\n local red = {177/255,42/255,42/255}\n local green = {34/255,177/255,76/255}\n\n function renderHeader(title)\n local h = 55\n addLine(back,0,h+12,rx,h+12)\n addBox(front,0,12,rx,h)\n addText(front,smallBold,title,44,h-12)\nend\n\n setNextFillColor(front, ]] .. color .. [[[1], ]] .. color .. [[[2], ]] .. color .. [[[3], 1)\n setNextTextAlign(front,AlignH_Center,AlignV_Middle)\n addText(front,smallBold,\"]] .. message .. [[\", rx/2, ry/4)\n\n\n setNextFillColor(front, ]] .. color .. [[[1], ]] .. color .. [[[2], ]] .. color .. [[[3], 1)\n setNextTextAlign(front,AlignH_Center,AlignV_Middle)\n addText(front,bigBold,\"]] .. player.getName() .. [[\", rx/2, ry/2)\n\n renderHeader(\"Access Control System\")\n requestAnimationFrame(10)\n ]]\nend\n\nlocal AccessPermitted = false\n\nfunction setRenderScriptOnScreens(access)\n for _,screen in pairs(Screens) do\n screen.setRenderScript(getRenderScript(access))\n end\nend\n\nfunction grantAccess()\n AccessPermitted = true\n for _,Door in pairs(Doors) do\n Door.open() --open the door\n end\n for _,Field in pairs(Fields) do\n Field.deactivate() --open the field\n end\n setRenderScriptOnScreens(true)\nend\n\nfunction closeAll()\n AccessPermitted = false\n for _,Door in pairs(Doors) do\n Door.close() --close the door\n end\n for _,Field in pairs(Fields) do\n Field.activate() --close the field\n end\nend\n\nfunction rejectAccess()\n closeAll()\n setRenderScriptOnScreens(false)\n unit.exit()\nend\n\n--converting to tables\nlocal tPermittedUsersId = split(AllowedUsersId,',') or {}\nlocal tPermittedUsersName = split(AllowedUsersName,',') or {}\nlocal tPermittedOrgsId = split(AllowedUserOrgsId,',') or {}\nlocal tPermittedOrgsName = split(AllowedUserOrgsName,',') or {}\n\nlocal player_id = player.getId()\n\nfor _,id in pairs(tPermittedUsersId) do\n if id == player_id then\n grantAccess()\n AccessPermitted = true\n break\n end\nend\n\nif not AccessPermitted then\n local player_name = player.getName()\n for _,name in pairs(tPermittedUsersName) do\n if name == player_name then\n grantAccess()\n break\n end\n end\nend\n\nif not AccessPermitted then\n local player_orgs_id = player.getOrgIds()\n for _,oid in pairs(player_orgs_id) do\n for _,id in pairs(tPermittedOrgsId) do\n if tonumber(id) == oid then\n grantAccess()\n break\n end\n end\n --if access is granted, end the loop\n if AccessPermitted then break end\n --if not a valid ID, veifying the org name\n local o = system.getOrganization(oid)\n if o.name then\n for _,name in pairs(tPermittedOrgsName) do\n if name == o.name then\n grantAccess()\n break\n end\n end\n end\n --if access is granted, end the loop\n if AccessPermitted then break end\n end\nend\n\nif not AccessPermitted then\n rejectAccess()\nend","filter":{"args":[],"signature":"onStart()","slotKey":"-1"},"key":"0"},{"code":"closeAll()\n","filter":{"args":[],"signature":"onStop()","slotKey":"-1"},"key":"1"}],"methods":[],"events":[]} \ No newline at end of file diff --git a/images/lua_parameters.png b/images/lua_parameters.png new file mode 100644 index 0000000000000000000000000000000000000000..60b4d7c149b3b3afc442999d847cd3c988dd97e5 GIT binary patch literal 12026 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 literal 0 HcmV?d00001 diff --git a/images/mounting_scheme.png b/images/mounting_scheme.png new file mode 100644 index 0000000000000000000000000000000000000000..f9bce2ed03db4042a9622107b177aaa27f8165ff GIT binary patch literal 38176 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