diff --git a/coordinator/startup.lua b/coordinator/startup.lua index b4f3db4..1ba171b 100644 --- a/coordinator/startup.lua +++ b/coordinator/startup.lua @@ -16,7 +16,7 @@ local config = require("coordinator.config") local coordinator = require("coordinator.coordinator") local renderer = require("coordinator.renderer") -local COORDINATOR_VERSION = "alpha-v0.6.0" +local COORDINATOR_VERSION = "alpha-v0.6.1" local print = util.print local println = util.println diff --git a/coordinator/ui/components/turbine.lua b/coordinator/ui/components/turbine.lua index 119caf2..f4cbcf1 100644 --- a/coordinator/ui/components/turbine.lua +++ b/coordinator/ui/components/turbine.lua @@ -4,6 +4,7 @@ local util = require("scada-common.util") local style = require("coordinator.ui.style") local DataIndicator = require("graphics.elements.indicators.data") +local PowerIndicator = require("graphics.elements.indicators.power") local StateIndicator = require("graphics.elements.indicators.state") local Rectangle = require("graphics.elements.rectangle") local VerticalBar = require("graphics.elements.indicators.vbar") @@ -23,7 +24,7 @@ local function new_view(root, x, y, ps) local lu_col = cpair(colors.gray, colors.gray) local status = StateIndicator{parent=turbine,x=8,y=1,states=style.turbine.states,value=1,min_width=10} - local prod_rate = DataIndicator{parent=turbine,x=5,y=3,lu_colors=lu_col,label="",unit="FE",format="%10.2f",value=0,width=16,fg_bg=text_fg_bg} + local prod_rate = PowerIndicator{parent=turbine,x=5,y=3,lu_colors=lu_col,label="",format="%10.2f",value=0,width=16,fg_bg=text_fg_bg} local flow_rate = DataIndicator{parent=turbine,x=5,y=4,lu_colors=lu_col,label="",unit="mB/t",format="%10.0f",value=0,commas=true,width=16,fg_bg=text_fg_bg} ps.subscribe("computed_status", status.update) diff --git a/graphics/element.lua b/graphics/element.lua index 70b784c..178f2d7 100644 --- a/graphics/element.lua +++ b/graphics/element.lua @@ -31,6 +31,7 @@ local element = {} ---|hbar_args ---|icon_indicator_args ---|indicator_light_args +---|power_indicator_args ---|state_indicator_args ---|tristate_indicator_light_args ---|vbar_args diff --git a/graphics/elements/indicators/data.lua b/graphics/elements/indicators/data.lua index c566791..5b5a35b 100644 --- a/graphics/elements/indicators/data.lua +++ b/graphics/elements/indicators/data.lua @@ -4,29 +4,6 @@ local util = require("scada-common.util") local element = require("graphics.element") --- format a number string with commas as the thousands separator --- --- subtracts from spaces at the start if present for each comma used ----@param num string number string ----@return string -local function comma_format(num) - local formatted = num - local commas = 0 - local i = 1 - - while i > 0 do - formatted, i = formatted:gsub("^(%s-%d+)(%d%d%d)", '%1,%2') - if i > 0 then commas = commas + 1 end - end - - local _, num_spaces = formatted:gsub(" %s-", "") - local remove = math.min(num_spaces, commas) - - formatted = string.sub(formatted, remove + 1) - - return formatted -end - ---@class data_indicator_args ---@field label string indicator label ---@field unit? string indicator unit @@ -78,7 +55,7 @@ local function data(args) e.window.setCursorPos(data_start, 1) e.window.setTextColor(e.fg_bg.fgd) if args.commas then - e.window.write(comma_format(data_str)) + e.window.write(util.comma_format(data_str)) else e.window.write(data_str) end diff --git a/graphics/elements/indicators/power.lua b/graphics/elements/indicators/power.lua new file mode 100644 index 0000000..70d6479 --- /dev/null +++ b/graphics/elements/indicators/power.lua @@ -0,0 +1,74 @@ +-- Power Indicator Graphics Element + +local util = require("scada-common.util") + +local element = require("graphics.element") + +---@class power_indicator_args +---@field label string indicator label +---@field format string power format override (lua string format) +---@field lu_colors? cpair label foreground color (a), unit foreground color (b) +---@field value any default value +---@field parent graphics_element +---@field id? string element id +---@field x? integer 1 if omitted +---@field y? integer 1 if omitted +---@field width integer length +---@field fg_bg? cpair foreground/background colors + +-- new power indicator +---@param args power_indicator_args +---@return graphics_element element, element_id id +local function power(args) + assert(args.value ~= nil, "graphics.elements.indicators.power: value is a required field") + assert(util.is_int(args.width), "graphics.elements.indicators.power: width is a required field") + + -- single line + args.height = 1 + + -- create new graphics element base object + local e = element.new(args) + + -- label color + if args.lu_colors ~= nil then + e.window.setTextColor(args.lu_colors.color_a) + end + + -- write label + e.window.setCursorPos(1, 1) + e.window.write(args.label) + + local data_start = string.len(args.label) + 2 + + -- on state change + ---@param value any new value + function e.on_update(value) + e.value = value + + local data_str, unit = util.power_format(value, false, args.format) + + -- write data + e.window.setCursorPos(data_start, 1) + e.window.setTextColor(e.fg_bg.fgd) + e.window.write(util.comma_format(data_str)) + + -- write unit + if args.lu_colors ~= nil then + e.window.setTextColor(args.lu_colors.color_b) + end + -- add space so we don't end up with FEE (after having kFE for example) + if unit == "FE" then unit = "FE " end + e.window.write(" " .. unit) + end + + -- set the value + ---@param val any new value + function e.set_value(val) e.on_update(val) end + + -- initial value draw + e.on_update(args.value) + + return e.get() +end + +return power diff --git a/scada-common/util.lua b/scada-common/util.lua index 440b9e0..1153c6b 100644 --- a/scada-common/util.lua +++ b/scada-common/util.lua @@ -11,6 +11,7 @@ util.TICK_TIME_S = 0.05 util.TICK_TIME_MS = 50 -- OPERATORS -- +--#region -- trinary operator ---@param cond boolean condition @@ -21,7 +22,10 @@ function util.trinary(cond, a, b) if cond then return a else return b end end +--#endregion + -- PRINT -- +--#region -- print ---@param message any @@ -47,7 +51,10 @@ function util.println_ts(message) print(os.date("[%H:%M:%S] ") .. tostring(message)) end +--#endregion + -- STRING TOOLS -- +--#region -- get a value as a string ---@param val any @@ -160,7 +167,33 @@ function util.sprintf(format, ...) return string.format(format, table.unpack(arg)) end +-- format a number string with commas as the thousands separator +-- +-- subtracts from spaces at the start if present for each comma used +---@param num string number string +---@return string +function util.comma_format(num) + local formatted = num + local commas = 0 + local i = 1 + + while i > 0 do + formatted, i = formatted:gsub("^(%s-%d+)(%d%d%d)", '%1,%2') + if i > 0 then commas = commas + 1 end + end + + local _, num_spaces = formatted:gsub(" %s-", "") + local remove = math.min(num_spaces, commas) + + formatted = string.sub(formatted, remove + 1) + + return formatted +end + +--#endregion + -- MATH -- +--#region -- is a value an integer ---@param x any value @@ -197,7 +230,10 @@ function util.time() return util.time_ms() end +--#endregion + -- OS -- +--#region -- OS pull event raw wrapper with types ---@param target_event? string event to wait for @@ -234,7 +270,10 @@ function util.cancel_timer(timer) os.cancelTimer(timer) end +--#endregion + -- PARALLELIZATION -- +--#region -- protected sleep call so we still are in charge of catching termination ---@param t integer seconds @@ -265,7 +304,10 @@ function util.adaptive_delay(target_timing, last_update) return util.time() end +--#endregion + -- TABLE UTILITIES -- +--#region -- delete elements from a table if the passed function returns false when passed a table element -- @@ -303,7 +345,10 @@ function util.table_contains(t, element) return false end +--#endregion + -- MEKANISM POWER -- +--#region -- convert Joules to FE ---@param J number Joules @@ -322,21 +367,46 @@ local function TFE(fe) return fe / 1000000000000.0 end -- format a power value into XXX.XX UNIT format (FE, kFE, MFE, GFE, TFE) ---@param fe number forge energy value ----@return string str formatted string -function util.power_format(fe) +---@param combine_label boolean if a label should be included in the string itself +---@param format string format override +---@return string str, string? unit +function util.power_format(fe, combine_label, format) + local unit + local value + + if type(format) ~= "string" then + format = "%.2f" + end + if fe < 1000 then - return string.format("%.2f FE", fe) + unit = "FE" + value = fe elseif fe < 1000000 then - return string.format("%.2f kFE", kFE(fe)) + unit = "kFE" + value = kFE(fe) elseif fe < 1000000000 then - return string.format("%.2f MFE", MFE(fe)) + unit = "MFE" + value = MFE(fe) elseif fe < 1000000000000 then - return string.format("%.2f GFE", GFE(fe)) + unit = "GFE" + value = GFE(fe) else - return string.format("%.2f TFE", TFE(fe)) + unit = "TFE" + value = TFE(fe) + end + + if combine_label then + return util.sprintf(util.c(format, " %s"), value, unit) + else + return util.sprintf(format, value), unit end end +--#endregion + +-- UTILITY CLASSES -- +--#region + -- WATCHDOG -- -- ComputerCraft OS Timer based Watchdog @@ -403,6 +473,8 @@ function util.new_clock(period) return public end +-- FIELD VALIDATOR -- + -- create a new type validator -- -- can execute sequential checks and check valid() to see if it is still valid @@ -433,4 +505,6 @@ function util.new_validator() return public end +--#endregion + return util