diff --git a/ccmsi.lua b/ccmsi.lua
index f3f74d1..1ce1e88 100644
--- a/ccmsi.lua
+++ b/ccmsi.lua
@@ -20,7 +20,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
local function println(message) print(tostring(message)) end
local function print(message) term.write(tostring(message)) end
-local CCMSI_VERSION = "v1.4f"
+local CCMSI_VERSION = "v1.5"
local install_dir = "/.install-cache"
local manifest_path = "https://mikaylafischler.github.io/cc-mek-scada/manifests/"
@@ -29,22 +29,88 @@ local repo_path = "http://raw.githubusercontent.com/MikaylaFischler/cc-mek-scada
local opts = { ... }
local mode = nil
local app = nil
-local target
+local target = nil
+local install_manifest = manifest_path .. "main/install_manifest.json"
+
+local function red() term.setTextColor(colors.red) end
+local function orange() term.setTextColor(colors.orange) end
+local function yellow() term.setTextColor(colors.yellow) end
+local function green() term.setTextColor(colors.green) end
+local function blue() term.setTextColor(colors.blue) end
+local function white() term.setTextColor(colors.white) end
+local function lgray() term.setTextColor(colors.lightGray) end
+
+-- get command line option in list
+local function get_opt(opt, options)
+ for _, v in pairs(options) do if opt == v then return v end end
+ return nil
+end
+
+-- ask the user yes or no
+local function ask_y_n(question, default)
+ print(question)
+ if default == true then print(" (Y/n)? ") else print(" (y/N)? ") end
+ local response = read()
+ if response == "" then return default
+ elseif response == "Y" or response == "y" then return true
+ elseif response == "N" or response == "n" then return false
+ else return nil end
+end
+
+-- print out a white + blue text message
+local function pkg_message(message, package) white(); print(message .. " "); blue(); println(package); white() end
+
+-- indicate actions to be taken based on package differences for installs/updates
+local function show_pkg_change(name, v_local, v_remote)
+ if v_local ~= nil then
+ if v_local ~= v_remote then
+ print("[" .. name .. "] updating "); blue(); print(v_local); white(); print(" \xbb "); blue(); println(v_local); white()
+ elseif mode == "install" then
+ pkg_message("[" .. name .. "] reinstalling", v_local)
+ end
+ else
+ pkg_message("[" .. name .. "] new install of", v_remote)
+ end
+end
+
+-- read the local manifest file
+local function read_local_manifest()
+ local local_ok = false
+ local local_manifest = {}
+ local imfile = fs.open("install_manifest.json", "r")
+ if imfile ~= nil then
+ local_ok, local_manifest = pcall(function () return textutils.unserializeJSON(imfile.readAll()) end)
+ imfile.close()
+ end
+ return local_ok, local_manifest
+end
+
+local function get_remote_manifest()
+ local response, error = http.get(install_manifest)
+ if response == nil then
+ orange(); println("failed to get installation manifest from GitHub, cannot update or install")
+ red(); println("HTTP error: " .. error); white()
+ return false, {}
+ end
+
+ local ok, manifest = pcall(function () return textutils.unserializeJSON(response.readAll()) end)
+ if not ok then
+ red(); println("error parsing remote installation manifest"); white()
+ end
+
+ return ok, manifest
+end
-- record the local installation manifest
----@param manifest table
----@param dependencies table
local function write_install_manifest(manifest, dependencies)
local versions = {}
for key, value in pairs(manifest.versions) do
local is_dependency = false
for _, dependency in pairs(dependencies) do
if (key == "bootloader" and dependency == "system") or key == dependency then
- is_dependency = true
- break
+ is_dependency = true; break
end
end
-
if key == app or key == "comms" or is_dependency then versions[key] = value end
end
@@ -55,184 +121,66 @@ local function write_install_manifest(manifest, dependencies)
imfile.close()
end
--- ask the user yes or no
----@nodiscard
----@param question string
----@param default boolean
----@return boolean|nil
-local function ask_y_n(question, default)
- print(question)
-
- if default == true then
- print(" (Y/n)? ")
- else
- print(" (y/N)? ")
- end
-
- local response = read(nil, nil)
-
- if response == "" then
- return default
- elseif response == "Y" or response == "y" then
- return true
- elseif response == "N" or response == "n" then
- return false
- else
- return nil
- end
-end
-
--- print out a white + blue text message
--- automatically adds a space
----@param message string message
----@param package string dependency/package/version
-local function pkg_message(message, package)
- term.setTextColor(colors.white)
- print(message .. " ")
- term.setTextColor(colors.blue)
- println(package)
- term.setTextColor(colors.white)
-end
-
--- indicate actions to be taken based on package differences for installs/updates
----@param name string package name
----@param v_local string|nil local version
----@param v_remote string remote version
-local function show_pkg_change(name, v_local, v_remote)
- if v_local ~= nil then
- if v_local ~= v_remote then
- print("[" .. name .. "] updating ")
- term.setTextColor(colors.blue)
- print(v_local)
- term.setTextColor(colors.white)
- print(" \xbb ")
- term.setTextColor(colors.blue)
- println(v_local)
- term.setTextColor(colors.white)
- elseif mode == "install" then
- pkg_message("[" .. name .. "] reinstalling", v_local)
- end
- else
- pkg_message("[" .. name .. "] new install of", v_remote)
- end
-end
-
---
-- get and validate command line options
---
println("-- CC Mekanism SCADA Installer " .. CCMSI_VERSION .. " --")
if #opts == 0 or opts[1] == "help" then
println("usage: ccmsi ")
println("")
- term.setTextColor(colors.lightGray)
+ lgray()
println(" check - check latest versions avilable")
- term.setTextColor(colors.yellow)
+ yellow()
println(" ccmsi check for target")
- term.setTextColor(colors.lightGray)
+ lgray()
println(" install - fresh install, overwrites config")
println(" update - update files EXCEPT for config/logs")
println(" remove - delete files EXCEPT for config/logs")
println(" purge - delete files INCLUDING config/logs")
- term.setTextColor(colors.white)
- println("")
- term.setTextColor(colors.lightGray)
+ white(); println(""); lgray()
println(" reactor-plc - reactor PLC firmware")
println(" rtu - RTU firmware")
println(" supervisor - supervisor server application")
println(" coordinator - coordinator application")
println(" pocket - pocket application")
- term.setTextColor(colors.white)
- println("")
- term.setTextColor(colors.yellow)
+ white(); println(""); yellow()
println(" second parameter when used with check")
- term.setTextColor(colors.lightGray)
- println(" main (default) | latest | devel")
+ lgray(); println(" main (default) | latest | devel"); white()
return
else
- for _, v in pairs({ "check", "install", "update", "remove", "purge" }) do
- if opts[1] == v then
- mode = v
- break
- end
- end
-
+ mode = get_opt(opts[1], { "check", "install", "update", "remove", "purge" })
if mode == nil then
- println("unrecognized mode")
+ red(); println("Unrecognized mode."); white()
return
end
- for _, v in pairs({ "reactor-plc", "rtu", "supervisor", "coordinator", "pocket" }) do
- if opts[2] == v then
- app = v
- break
- end
- end
-
+ app = get_opt(opts[2], { "reactor-plc", "rtu", "supervisor", "coordinator", "pocket" })
if app == nil and mode ~= "check" then
- println("unrecognized application")
+ red(); println("Unrecognized application."); white()
return
end
-- determine target
if mode == "check" then target = opts[2] else target = opts[3] end
if (target ~= "main") and (target ~= "latest") and (target ~= "devel") then
+ if target ~= "" then yellow(); println("Unknown target, defaulting to 'main'"); white() end
target = "main"
- println("unknown target, defaulting to 'main'")
end
+
+ -- set paths
+ install_manifest = manifest_path .. target .. "/install_manifest.json"
+ repo_path = repo_path .. target .. "/"
end
---
-- run selected mode
---
if mode == "check" then
- -------------------------
- -- GET REMOTE MANIFEST --
- -------------------------
-
- manifest_path = manifest_path .. target .. "/"
- local install_manifest = manifest_path .. "install_manifest.json"
-
- local response, error = http.get(install_manifest)
-
- if response == nil then
- term.setTextColor(colors.orange)
- println("failed to get installation manifest from GitHub, cannot update or install")
- term.setTextColor(colors.red)
- println("HTTP error: " .. error)
- term.setTextColor(colors.white)
- return
- end
-
- local ok, manifest = pcall(function () return textutils.unserializeJSON(response.readAll()) end)
-
- if not ok then
- term.setTextColor(colors.red)
- println("error parsing remote installation manifest")
- term.setTextColor(colors.white)
- return
- end
-
- ------------------------
- -- GET LOCAL MANIFEST --
- ------------------------
-
- local imfile = fs.open("install_manifest.json", "r")
- local local_ok = false
- local local_manifest = {}
-
- if imfile ~= nil then
- local_ok, local_manifest = pcall(function () return textutils.unserializeJSON(imfile.readAll()) end)
- imfile.close()
- end
+ local ok, manifest = get_remote_manifest()
+ if not ok then return end
+ local local_ok, local_manifest = read_local_manifest()
if not local_ok then
- term.setTextColor(colors.yellow)
- println("failed to load local installation information")
- term.setTextColor(colors.white)
-
+ yellow(); println("failed to load local installation information"); white()
local_manifest = { versions = { installer = CCMSI_VERSION } }
else
local_manifest.versions.installer = CCMSI_VERSION
@@ -243,84 +191,35 @@ if mode == "check" then
term.setTextColor(colors.purple)
print(string.format("%-14s", "[" .. key .. "]"))
if key == "installer" or (local_ok and (local_manifest.versions[key] ~= nil)) then
- term.setTextColor(colors.blue)
- print(local_manifest.versions[key])
+ blue(); print(local_manifest.versions[key])
if value ~= local_manifest.versions[key] then
- term.setTextColor(colors.white)
- print(" (")
+ white(); print(" (")
term.setTextColor(colors.cyan)
- print(value)
- term.setTextColor(colors.white)
- println(" available)")
- else
- term.setTextColor(colors.green)
- println(" (up to date)")
- end
+ print(value); white(); println(" available)")
+ else green(); println(" (up to date)") end
else
- term.setTextColor(colors.lightGray)
- print("not installed")
- term.setTextColor(colors.white)
- print(" (latest ")
+ lgray(); print("not installed"); white(); print(" (latest ")
term.setTextColor(colors.cyan)
- print(value)
- term.setTextColor(colors.white)
- println(")")
+ print(value); white(); println(")")
end
end
elseif mode == "install" or mode == "update" then
- -------------------------
- -- GET REMOTE MANIFEST --
- -------------------------
-
- repo_path = repo_path .. target .. "/"
- manifest_path = manifest_path .. target .. "/"
- local install_manifest = manifest_path .. "install_manifest.json"
-
- local response, error = http.get(install_manifest)
-
- if response == nil then
- term.setTextColor(colors.orange)
- println("failed to get installation manifest from GitHub, cannot update or install")
- term.setTextColor(colors.red)
- println("HTTP error: " .. error)
- term.setTextColor(colors.white)
- return
- end
-
- local ok, manifest = pcall(function () return textutils.unserializeJSON(response.readAll()) end)
-
- if not ok then
- term.setTextColor(colors.red)
- println("error parsing remote installation manifest")
- term.setTextColor(colors.white)
- end
-
- ------------------------
- -- GET LOCAL MANIFEST --
- ------------------------
+ local ok, manifest = get_remote_manifest()
+ if not ok then return end
local ver = {
app = { v_local = nil, v_remote = nil, changed = false },
boot = { v_local = nil, v_remote = nil, changed = false },
comms = { v_local = nil, v_remote = nil, changed = false },
- graphics = { v_local = nil, v_remote = nil, changed = false }
+ graphics = { v_local = nil, v_remote = nil, changed = false },
+ lockbox = { v_local = nil, v_remote = nil, changed = false }
}
- local imfile = fs.open("install_manifest.json", "r")
- local local_ok = false
- local local_manifest = {}
-
- if imfile ~= nil then
- local_ok, local_manifest = pcall(function () return textutils.unserializeJSON(imfile.readAll()) end)
- imfile.close()
- end
-
-- try to find local versions
+ local local_ok, local_manifest = read_local_manifest()
if not local_ok then
if mode == "update" then
- term.setTextColor(colors.red)
- println("failed to load local installation information, cannot update")
- term.setTextColor(colors.white)
+ red(); println("failed to load local installation information, cannot update"); white()
return
end
else
@@ -328,19 +227,16 @@ elseif mode == "install" or mode == "update" then
ver.app.v_local = local_manifest.versions[app]
ver.comms.v_local = local_manifest.versions.comms
ver.graphics.v_local = local_manifest.versions.graphics
+ ver.lockbox.v_local = local_manifest.versions.lockbox
if local_manifest.versions[app] == nil then
- term.setTextColor(colors.red)
- println("another application is already installed, please purge it before installing a new application")
- term.setTextColor(colors.white)
+ red(); println("another application is already installed, please purge it before installing a new application"); white()
return
end
local_manifest.versions.installer = CCMSI_VERSION
if manifest.versions.installer ~= CCMSI_VERSION then
- term.setTextColor(colors.yellow)
- println("a newer version of the installer is available, consider downloading it")
- term.setTextColor(colors.white)
+ yellow(); println("a newer version of the installer is available, it is recommended to download it"); white()
end
end
@@ -348,14 +244,15 @@ elseif mode == "install" or mode == "update" then
ver.app.v_remote = manifest.versions[app]
ver.comms.v_remote = manifest.versions.comms
ver.graphics.v_remote = manifest.versions.graphics
+ ver.lockbox.v_remote = manifest.versions.lockbox
- term.setTextColor(colors.green)
+ green()
if mode == "install" then
println("Installing " .. app .. " files...")
elseif mode == "update" then
println("Updating " .. app .. " files... (keeping old config.lua)")
end
- term.setTextColor(colors.white)
+ white()
-- display bootloader version change information
show_pkg_change("bootldr", ver.boot.v_local, ver.boot.v_remote)
@@ -369,16 +266,17 @@ elseif mode == "install" or mode == "update" then
show_pkg_change("comms", ver.comms.v_local, ver.comms.v_remote)
ver.comms.changed = ver.comms.v_local ~= ver.comms.v_remote
if ver.comms.changed and ver.comms.v_local ~= nil then
- print("[comms] ")
- term.setTextColor(colors.yellow)
- println("other devices on the network will require an update")
- term.setTextColor(colors.white)
+ print("[comms] "); yellow(); println("other devices on the network will require an update"); white()
end
-- display graphics version change information
show_pkg_change("graphics", ver.graphics.v_local, ver.graphics.v_remote)
ver.graphics.changed = ver.graphics.v_local ~= ver.graphics.v_remote
+ -- display lockbox version change information
+ show_pkg_change("lockbox", ver.lockbox.v_local, ver.lockbox.v_remote)
+ ver.lockbox.changed = ver.lockbox.v_local ~= ver.lockbox.v_remote
+
-- ask for confirmation
if not ask_y_n("Continue?", false) then return end
@@ -405,11 +303,9 @@ elseif mode == "install" or mode == "update" then
-- check space constraints
if space_available < space_required then
single_file_mode = true
- term.setTextColor(colors.yellow)
- println("WARNING: Insufficient space available for a full download!")
- term.setTextColor(colors.white)
+ yellow(); println("WARNING: Insufficient space available for a full download!"); white()
println("Files can be downloaded one by one, so if you are replacing a current install this will not be a problem unless installation fails.")
- if mode == "update" then println("If installation still fails, delete this device's log file and try again.") end
+ if mode == "update" then println("If installation still fails, delete this device's log file or uninstall the app (not purge) and try again.") end
if not ask_y_n("Do you wish to continue?", false) then
println("Operation cancelled.")
return
@@ -419,12 +315,11 @@ elseif mode == "install" or mode == "update" then
local success = true
-- helper function to check if a dependency is unchanged
- ---@nodiscard
- ---@param dependency string
- ---@return boolean
local function unchanged(dependency)
if dependency == "system" then return not ver.boot.changed
elseif dependency == "graphics" then return not ver.graphics.changed
+ elseif dependency == "lockbox" then return not ver.lockbox.changed
+ elseif dependency == "common" then return not (ver.app.changed or ver.comms.changed)
elseif dependency == app then return not ver.app.changed
else return true end
end
@@ -441,7 +336,7 @@ elseif mode == "install" or mode == "update" then
pkg_message("skipping download of unchanged package", dependency)
else
pkg_message("downloading package", dependency)
- term.setTextColor(colors.lightGray)
+ lgray()
local files = file_list[dependency]
for _, file in pairs(files) do
@@ -449,8 +344,7 @@ elseif mode == "install" or mode == "update" then
local dl, err = http.get(repo_path .. file)
if dl == nil then
- term.setTextColor(colors.red)
- println("GET HTTP Error " .. err)
+ red(); println("GET HTTP Error " .. err)
success = false
break
else
@@ -469,7 +363,7 @@ elseif mode == "install" or mode == "update" then
pkg_message("skipping install of unchanged package", dependency)
else
pkg_message("installing package", dependency)
- term.setTextColor(colors.lightGray)
+ lgray()
local files = file_list[dependency]
for _, file in pairs(files) do
@@ -486,23 +380,15 @@ elseif mode == "install" or mode == "update" then
fs.delete(install_dir)
if success then
- -- if we made it here, then none of the file system functions threw exceptions
- -- that means everything is OK
write_install_manifest(manifest, dependencies)
- term.setTextColor(colors.green)
+ green()
if mode == "install" then
println("Installation completed successfully.")
- else
- println("Update completed successfully.")
- end
+ else println("Update completed successfully.") end
else
if mode == "install" then
- term.setTextColor(colors.red)
- println("Installation failed.")
- else
- term.setTextColor(colors.orange)
- println("Update failed, existing files unmodified.")
- end
+ red(); println("Installation failed.")
+ else orange(); println("Update failed, existing files unmodified.") end
end
else
-- go through all files and replace one by one
@@ -511,7 +397,7 @@ elseif mode == "install" or mode == "update" then
pkg_message("skipping install of unchanged package", dependency)
else
pkg_message("installing package", dependency)
- term.setTextColor(colors.lightGray)
+ lgray()
local files = file_list[dependency]
for _, file in pairs(files) do
@@ -520,7 +406,7 @@ elseif mode == "install" or mode == "update" then
local dl, err = http.get(repo_path .. file)
if dl == nil then
- println("GET HTTP Error " .. err)
+ red(); println("GET HTTP Error " .. err)
success = false
break
else
@@ -534,51 +420,33 @@ elseif mode == "install" or mode == "update" then
end
if success then
- -- if we made it here, then none of the file system functions threw exceptions
- -- that means everything is OK
write_install_manifest(manifest, dependencies)
- term.setTextColor(colors.green)
+ green()
if mode == "install" then
println("Installation completed successfully.")
- else
- println("Update completed successfully.")
- end
+ else println("Update completed successfully.") end
else
- term.setTextColor(colors.red)
+ red()
if mode == "install" then
println("Installation failed, files may have been skipped.")
- else
- println("Update failed, files may have been skipped.")
- end
+ else println("Update failed, files may have been skipped.") end
end
end
elseif mode == "remove" or mode == "purge" then
- local imfile = fs.open("install_manifest.json", "r")
- local ok = false
- local manifest = {}
-
- if imfile ~= nil then
- ok, manifest = pcall(function () return textutils.unserializeJSON(imfile.readAll()) end)
- imfile.close()
- end
-
+ local ok, manifest = read_local_manifest()
if not ok then
- term.setTextColor(colors.red)
- println("error parsing local installation manifest")
- term.setTextColor(colors.white)
+ red(); println("Error parsing local installation manifest."); white()
return
elseif mode == "remove" and manifest.versions[app] == nil then
- term.setTextColor(colors.red)
- println(app .. " is not installed")
- term.setTextColor(colors.white)
+ red(); println(app .. " is not installed, cannot remove."); white()
return
end
- term.setTextColor(colors.orange)
+ orange()
if mode == "remove" then
- println("removing all " .. app .. " files except for config.lua and log.txt...")
+ println("Removing all " .. app .. " files except for config and log...")
elseif mode == "purge" then
- println("purging all " .. app .. " files...")
+ println("Purging all " .. app .. " files including config and log...")
end
-- ask for confirmation
@@ -590,9 +458,8 @@ elseif mode == "remove" or mode == "purge" then
table.insert(dependencies, app)
- term.setTextColor(colors.lightGray)
-
-- delete log file if purging
+ lgray()
if mode == "purge" and fs.exists(config_file) then
local log_deleted = pcall(function ()
local config = require(app .. ".config")
@@ -603,11 +470,9 @@ elseif mode == "remove" or mode == "purge" then
end)
if not log_deleted then
- term.setTextColor(colors.red)
- println("failed to delete log file")
- term.setTextColor(colors.lightGray)
----@diagnostic disable-next-line: undefined-field
- os.sleep(1)
+ red(); println("failed to delete log file")
+ white(); println("press enter to continue...")
+ read(); lgray()
end
end
@@ -628,11 +493,7 @@ elseif mode == "remove" or mode == "purge" then
local folder = files[1]
while true do
local dir = fs.getDir(folder)
- if dir == "" or dir == ".." then
- break
- else
- folder = dir
- end
+ if dir == "" or dir == ".." then break else folder = dir end
end
if fs.isDir(folder) then
@@ -640,14 +501,11 @@ elseif mode == "remove" or mode == "purge" then
println("deleted directory " .. folder)
end
elseif dependency == app then
+ -- delete individual subdirectories so we can leave the config
for _, folder in pairs(files) do
while true do
local dir = fs.getDir(folder)
- if dir == "" or dir == ".." or dir == app then
- break
- else
- folder = dir
- end
+ if dir == "" or dir == ".." or dir == app then break else folder = dir end
end
if folder ~= app and fs.isDir(folder) then
@@ -665,13 +523,12 @@ elseif mode == "remove" or mode == "purge" then
else
-- remove all data from versions list to show nothing is installed
manifest.versions = {}
- imfile = fs.open("install_manifest.json", "w")
+ local imfile = fs.open("install_manifest.json", "w")
imfile.write(textutils.serializeJSON(manifest))
imfile.close()
end
- term.setTextColor(colors.green)
- println("Done!")
+ green(); println("Done!")
end
-term.setTextColor(colors.white)
+white()
diff --git a/imgen.py b/imgen.py
index 63f28cf..046fc36 100644
--- a/imgen.py
+++ b/imgen.py
@@ -50,6 +50,7 @@ def make_manifest(size):
"bootloader" : get_version("./startup.lua"),
"comms" : get_version("./scada-common/comms.lua", True),
"graphics" : get_version("./graphics/core.lua", True),
+ "lockbox" : get_version("./lockbox/init.lua", True),
"reactor-plc" : get_version("./reactor-plc/startup.lua"),
"rtu" : get_version("./rtu/startup.lua"),
"supervisor" : get_version("./supervisor/startup.lua"),
@@ -70,11 +71,11 @@ def make_manifest(size):
"pocket" : list_files("./pocket"),
},
"depends" : {
- "reactor-plc" : [ "system", "common", "graphics" ],
- "rtu" : [ "system", "common", "graphics" ],
- "supervisor" : [ "system", "common", "graphics" ],
- "coordinator" : [ "system", "common", "graphics" ],
- "pocket" : [ "system", "common", "graphics" ]
+ "reactor-plc" : [ "system", "common", "graphics", "lockbox" ],
+ "rtu" : [ "system", "common", "graphics", "lockbox" ],
+ "supervisor" : [ "system", "common", "graphics", "lockbox" ],
+ "coordinator" : [ "system", "common", "graphics", "lockbox" ],
+ "pocket" : [ "system", "common", "graphics", "lockbox" ]
},
"sizes" : {
# manifest file estimate
diff --git a/install_manifest.json b/install_manifest.json
index 7a6c673..88da63c 100644
--- a/install_manifest.json
+++ b/install_manifest.json
@@ -1 +1 @@
-{"versions": {"installer": "v1.4f", "bootloader": "0.2", "comms": "2.1.0", "graphics": "1.0.0", "reactor-plc": "v1.4.7", "rtu": "v1.3.7", "supervisor": "v0.17.10", "coordinator": "v0.17.1", "pocket": "alpha-v0.5.1"}, "files": {"system": ["initenv.lua", "startup.lua"], "common": ["scada-common/ppm.lua", "scada-common/comms.lua", "scada-common/psil.lua", "scada-common/rsio.lua", "scada-common/constants.lua", "scada-common/mqueue.lua", "scada-common/tcd.lua", "scada-common/crash.lua", "scada-common/log.lua", "scada-common/types.lua", "scada-common/util.lua", "scada-common/network.lua"], "graphics": ["graphics/element.lua", "graphics/events.lua", "graphics/flasher.lua", "graphics/core.lua", "graphics/elements/listbox.lua", "graphics/elements/textbox.lua", "graphics/elements/displaybox.lua", "graphics/elements/pipenet.lua", "graphics/elements/rectangle.lua", "graphics/elements/div.lua", "graphics/elements/multipane.lua", "graphics/elements/tiling.lua", "graphics/elements/colormap.lua", "graphics/elements/indicators/alight.lua", "graphics/elements/indicators/icon.lua", "graphics/elements/indicators/power.lua", "graphics/elements/indicators/rad.lua", "graphics/elements/indicators/state.lua", "graphics/elements/indicators/light.lua", "graphics/elements/indicators/vbar.lua", "graphics/elements/indicators/led.lua", "graphics/elements/indicators/coremap.lua", "graphics/elements/indicators/data.lua", "graphics/elements/indicators/ledpair.lua", "graphics/elements/indicators/hbar.lua", "graphics/elements/indicators/trilight.lua", "graphics/elements/indicators/ledrgb.lua", "graphics/elements/controls/switch_button.lua", "graphics/elements/controls/spinbox_numeric.lua", "graphics/elements/controls/hazard_button.lua", "graphics/elements/controls/push_button.lua", "graphics/elements/controls/radio_button.lua", "graphics/elements/controls/multi_button.lua", "graphics/elements/controls/tabbar.lua", "graphics/elements/controls/sidebar.lua", "graphics/elements/animations/waiting.lua"], "lockbox": ["lockbox/init.lua", "lockbox/LICENSE", "lockbox/kdf/pbkdf2.lua", "lockbox/util/bit.lua", "lockbox/util/array.lua", "lockbox/util/stream.lua", "lockbox/util/queue.lua", "lockbox/digest/sha2_224.lua", "lockbox/digest/sha1.lua", "lockbox/digest/sha2_256.lua", "lockbox/digest/md5.lua", "lockbox/mac/hmac.lua"], "reactor-plc": ["reactor-plc/renderer.lua", "reactor-plc/threads.lua", "reactor-plc/databus.lua", "reactor-plc/plc.lua", "reactor-plc/config.lua", "reactor-plc/startup.lua", "reactor-plc/panel/front_panel.lua", "reactor-plc/panel/style.lua"], "rtu": ["rtu/renderer.lua", "rtu/threads.lua", "rtu/rtu.lua", "rtu/databus.lua", "rtu/modbus.lua", "rtu/config.lua", "rtu/startup.lua", "rtu/panel/front_panel.lua", "rtu/panel/style.lua", "rtu/dev/sps_rtu.lua", "rtu/dev/envd_rtu.lua", "rtu/dev/boilerv_rtu.lua", "rtu/dev/redstone_rtu.lua", "rtu/dev/sna_rtu.lua", "rtu/dev/imatrix_rtu.lua", "rtu/dev/turbinev_rtu.lua"], "supervisor": ["supervisor/renderer.lua", "supervisor/databus.lua", "supervisor/supervisor.lua", "supervisor/unit.lua", "supervisor/config.lua", "supervisor/startup.lua", "supervisor/unitlogic.lua", "supervisor/facility.lua", "supervisor/panel/pgi.lua", "supervisor/panel/front_panel.lua", "supervisor/panel/style.lua", "supervisor/panel/components/rtu_entry.lua", "supervisor/panel/components/pdg_entry.lua", "supervisor/session/coordinator.lua", "supervisor/session/svqtypes.lua", "supervisor/session/pocket.lua", "supervisor/session/svsessions.lua", "supervisor/session/rtu.lua", "supervisor/session/plc.lua", "supervisor/session/rsctl.lua", "supervisor/session/rtu/boilerv.lua", "supervisor/session/rtu/txnctrl.lua", "supervisor/session/rtu/unit_session.lua", "supervisor/session/rtu/turbinev.lua", "supervisor/session/rtu/envd.lua", "supervisor/session/rtu/imatrix.lua", "supervisor/session/rtu/sps.lua", "supervisor/session/rtu/qtypes.lua", "supervisor/session/rtu/sna.lua", "supervisor/session/rtu/redstone.lua"], "coordinator": ["coordinator/coordinator.lua", "coordinator/renderer.lua", "coordinator/iocontrol.lua", "coordinator/sounder.lua", "coordinator/config.lua", "coordinator/startup.lua", "coordinator/process.lua", "coordinator/ui/dialog.lua", "coordinator/ui/style.lua", "coordinator/ui/layout/main_view.lua", "coordinator/ui/layout/unit_view.lua", "coordinator/ui/components/reactor.lua", "coordinator/ui/components/processctl.lua", "coordinator/ui/components/unit_overview.lua", "coordinator/ui/components/boiler.lua", "coordinator/ui/components/unit_detail.lua", "coordinator/ui/components/imatrix.lua", "coordinator/ui/components/turbine.lua", "coordinator/session/pocket.lua", "coordinator/session/apisessions.lua"], "pocket": ["pocket/pocket.lua", "pocket/renderer.lua", "pocket/config.lua", "pocket/coreio.lua", "pocket/startup.lua", "pocket/ui/main.lua", "pocket/ui/style.lua", "pocket/ui/components/conn_waiting.lua", "pocket/ui/pages/turbine_page.lua", "pocket/ui/pages/reactor_page.lua", "pocket/ui/pages/home_page.lua", "pocket/ui/pages/unit_page.lua", "pocket/ui/pages/boiler_page.lua"]}, "depends": {"reactor-plc": ["system", "common", "graphics"], "rtu": ["system", "common", "graphics"], "supervisor": ["system", "common", "graphics"], "coordinator": ["system", "common", "graphics"], "pocket": ["system", "common", "graphics"]}, "sizes": {"manifest": 5496, "system": 1991, "common": 93516, "graphics": 144556, "lockbox": 34900, "reactor-plc": 97317, "rtu": 102353, "supervisor": 315477, "coordinator": 197703, "pocket": 37373}}
\ No newline at end of file
+{"versions": {"installer": "v1.5", "bootloader": "0.2", "comms": "2.1.0", "graphics": "1.0.0", "lockbox": "1.0", "reactor-plc": "v1.5.0", "rtu": "v1.4.0", "supervisor": "v0.18.0", "coordinator": "v0.17.1", "pocket": "alpha-v0.5.1"}, "files": {"system": ["initenv.lua", "startup.lua"], "common": ["scada-common/ppm.lua", "scada-common/comms.lua", "scada-common/psil.lua", "scada-common/rsio.lua", "scada-common/constants.lua", "scada-common/mqueue.lua", "scada-common/tcd.lua", "scada-common/crash.lua", "scada-common/log.lua", "scada-common/types.lua", "scada-common/util.lua", "scada-common/network.lua"], "graphics": ["graphics/element.lua", "graphics/events.lua", "graphics/flasher.lua", "graphics/core.lua", "graphics/elements/listbox.lua", "graphics/elements/textbox.lua", "graphics/elements/displaybox.lua", "graphics/elements/pipenet.lua", "graphics/elements/rectangle.lua", "graphics/elements/div.lua", "graphics/elements/multipane.lua", "graphics/elements/tiling.lua", "graphics/elements/colormap.lua", "graphics/elements/indicators/alight.lua", "graphics/elements/indicators/icon.lua", "graphics/elements/indicators/power.lua", "graphics/elements/indicators/rad.lua", "graphics/elements/indicators/state.lua", "graphics/elements/indicators/light.lua", "graphics/elements/indicators/vbar.lua", "graphics/elements/indicators/led.lua", "graphics/elements/indicators/coremap.lua", "graphics/elements/indicators/data.lua", "graphics/elements/indicators/ledpair.lua", "graphics/elements/indicators/hbar.lua", "graphics/elements/indicators/trilight.lua", "graphics/elements/indicators/ledrgb.lua", "graphics/elements/controls/switch_button.lua", "graphics/elements/controls/spinbox_numeric.lua", "graphics/elements/controls/hazard_button.lua", "graphics/elements/controls/push_button.lua", "graphics/elements/controls/radio_button.lua", "graphics/elements/controls/multi_button.lua", "graphics/elements/controls/tabbar.lua", "graphics/elements/controls/sidebar.lua", "graphics/elements/animations/waiting.lua"], "lockbox": ["lockbox/init.lua", "lockbox/LICENSE", "lockbox/kdf/pbkdf2.lua", "lockbox/util/bit.lua", "lockbox/util/array.lua", "lockbox/util/stream.lua", "lockbox/util/queue.lua", "lockbox/digest/sha2_224.lua", "lockbox/digest/sha1.lua", "lockbox/digest/sha2_256.lua", "lockbox/digest/md5.lua", "lockbox/mac/hmac.lua"], "reactor-plc": ["reactor-plc/renderer.lua", "reactor-plc/threads.lua", "reactor-plc/databus.lua", "reactor-plc/plc.lua", "reactor-plc/config.lua", "reactor-plc/startup.lua", "reactor-plc/panel/front_panel.lua", "reactor-plc/panel/style.lua"], "rtu": ["rtu/renderer.lua", "rtu/threads.lua", "rtu/rtu.lua", "rtu/databus.lua", "rtu/modbus.lua", "rtu/config.lua", "rtu/startup.lua", "rtu/panel/front_panel.lua", "rtu/panel/style.lua", "rtu/dev/sps_rtu.lua", "rtu/dev/envd_rtu.lua", "rtu/dev/boilerv_rtu.lua", "rtu/dev/redstone_rtu.lua", "rtu/dev/sna_rtu.lua", "rtu/dev/imatrix_rtu.lua", "rtu/dev/turbinev_rtu.lua"], "supervisor": ["supervisor/renderer.lua", "supervisor/databus.lua", "supervisor/supervisor.lua", "supervisor/unit.lua", "supervisor/config.lua", "supervisor/startup.lua", "supervisor/unitlogic.lua", "supervisor/facility.lua", "supervisor/panel/pgi.lua", "supervisor/panel/front_panel.lua", "supervisor/panel/style.lua", "supervisor/panel/components/rtu_entry.lua", "supervisor/panel/components/pdg_entry.lua", "supervisor/session/coordinator.lua", "supervisor/session/svqtypes.lua", "supervisor/session/pocket.lua", "supervisor/session/svsessions.lua", "supervisor/session/rtu.lua", "supervisor/session/plc.lua", "supervisor/session/rsctl.lua", "supervisor/session/rtu/boilerv.lua", "supervisor/session/rtu/txnctrl.lua", "supervisor/session/rtu/unit_session.lua", "supervisor/session/rtu/turbinev.lua", "supervisor/session/rtu/envd.lua", "supervisor/session/rtu/imatrix.lua", "supervisor/session/rtu/sps.lua", "supervisor/session/rtu/qtypes.lua", "supervisor/session/rtu/sna.lua", "supervisor/session/rtu/redstone.lua"], "coordinator": ["coordinator/coordinator.lua", "coordinator/renderer.lua", "coordinator/iocontrol.lua", "coordinator/sounder.lua", "coordinator/config.lua", "coordinator/startup.lua", "coordinator/process.lua", "coordinator/ui/dialog.lua", "coordinator/ui/style.lua", "coordinator/ui/layout/main_view.lua", "coordinator/ui/layout/unit_view.lua", "coordinator/ui/components/reactor.lua", "coordinator/ui/components/processctl.lua", "coordinator/ui/components/unit_overview.lua", "coordinator/ui/components/boiler.lua", "coordinator/ui/components/unit_detail.lua", "coordinator/ui/components/imatrix.lua", "coordinator/ui/components/turbine.lua", "coordinator/session/pocket.lua", "coordinator/session/apisessions.lua"], "pocket": ["pocket/pocket.lua", "pocket/renderer.lua", "pocket/config.lua", "pocket/coreio.lua", "pocket/startup.lua", "pocket/ui/main.lua", "pocket/ui/style.lua", "pocket/ui/components/conn_waiting.lua", "pocket/ui/pages/turbine_page.lua", "pocket/ui/pages/reactor_page.lua", "pocket/ui/pages/home_page.lua", "pocket/ui/pages/unit_page.lua", "pocket/ui/pages/boiler_page.lua"]}, "depends": {"reactor-plc": ["system", "common", "graphics", "lockbox"], "rtu": ["system", "common", "graphics", "lockbox"], "supervisor": ["system", "common", "graphics", "lockbox"], "coordinator": ["system", "common", "graphics", "lockbox"], "pocket": ["system", "common", "graphics", "lockbox"]}, "sizes": {"manifest": 5567, "system": 1991, "common": 93645, "graphics": 144556, "lockbox": 34900, "reactor-plc": 97702, "rtu": 102350, "supervisor": 315619, "coordinator": 198291, "pocket": 37736}}
\ No newline at end of file
diff --git a/lockbox/init.lua b/lockbox/init.lua
index 9323451..caee6c0 100644
--- a/lockbox/init.lua
+++ b/lockbox/init.lua
@@ -1,7 +1,7 @@
local Lockbox = {};
-- cc-mek-scada lockbox version
-Lockbox.VERSION = "1.0"
+Lockbox.version = "1.0"
--[[
package.path = "./?.lua;"