#523 coordinator energy scale options

This commit is contained in:
Mikayla Fischler 2024-07-27 12:34:01 -04:00
parent 01f6b1e190
commit 7cc088ca95
12 changed files with 145 additions and 89 deletions

View File

@ -38,6 +38,7 @@ function coordinator.load_config()
config.SpeakerVolume = settings.get("SpeakerVolume")
config.Time24Hour = settings.get("Time24Hour")
config.TempScale = settings.get("TempScale")
config.EnergyScale = settings.get("EnergyScale")
config.DisableFlowView = settings.get("DisableFlowView")
config.MainDisplay = settings.get("MainDisplay")
@ -67,6 +68,8 @@ function coordinator.load_config()
cfv.assert_type_bool(config.Time24Hour)
cfv.assert_type_int(config.TempScale)
cfv.assert_range(config.TempScale, 1, 4)
cfv.assert_type_int(config.EnergyScale)
cfv.assert_range(config.EnergyScale, 1, 3)
cfv.assert_type_bool(config.DisableFlowView)
cfv.assert_type_table(config.UnitDisplays)
@ -702,7 +705,7 @@ function coordinator.comms(version, nic, sv_watchdog)
if conf.num_units == config.UnitCount then
-- init io controller
iocontrol.init(conf, public, config.TempScale)
iocontrol.init(conf, public, config.TempScale, config.EnergyScale)
self.sv_addr = src_addr
self.sv_linked = true

View File

@ -14,6 +14,9 @@ local pgi = require("coordinator.ui.pgi")
local ALARM_STATE = types.ALARM_STATE
local PROCESS = types.PROCESS
local ENERGY_SCALE = types.ENERGY_SCALE
local ENERGY_UNITS = types.ENERGY_SCALE_UNITS
local TEMP_SCALE = types.TEMP_SCALE
local TEMP_UNITS = types.TEMP_SCALE_UNITS
@ -50,8 +53,10 @@ end
---@param conf facility_conf configuration
---@param comms coord_comms comms reference
---@param temp_scale TEMP_SCALE temperature unit
function iocontrol.init(conf, comms, temp_scale)
io.temp_label = TEMP_UNITS[temp_scale]
---@param energy_scale ENERGY_SCALE energy unit
function iocontrol.init(conf, comms, temp_scale, energy_scale)
io.temp_label = TEMP_UNITS[temp_scale]
io.energy_label = ENERGY_UNITS[energy_scale]
-- temperature unit label and conversion function (from Kelvin)
if temp_scale == TEMP_SCALE.CELSIUS then
@ -65,6 +70,18 @@ function iocontrol.init(conf, comms, temp_scale)
io.temp_convert = function (t) return t end
end
-- energy unit label and conversion function (from Joules unless otherwise specified)
if energy_scale == ENERGY_SCALE.FE or energy_scale == ENERGY_SCALE.RF then
io.energy_convert = util.joules_to_fe_rf
io.energy_convert_from_fe = function (t) return t end
io.energy_convert_to_fe = function (t) return t end
else
io.energy_label = "J"
io.energy_convert = function (t) return t end
io.energy_convert_from_fe = util.fe_rf_to_joules
io.energy_convert_to_fe = util.joules_to_fe_rf
end
-- facility data structure
---@class ioctl_facility
io.facility = {
@ -692,7 +709,7 @@ function iocontrol.update_facility_status(status)
ps.publish("is_discharging", out_f > in_f)
if data and data.build then
local cap = util.joules_to_fe(data.build.transfer_cap)
local cap = util.joules_to_fe_rf(data.build.transfer_cap)
ps.publish("at_max_io", in_f >= cap or out_f >= cap)
end
else

View File

@ -70,8 +70,8 @@ function process.init(iocontrol, coord_comms)
self.io.facility.ps.publish("process_mode", ctl_proc.mode)
self.io.facility.ps.publish("process_burn_target", ctl_proc.burn_target)
self.io.facility.ps.publish("process_charge_target", ctl_proc.charge_target)
self.io.facility.ps.publish("process_gen_target", ctl_proc.gen_target)
self.io.facility.ps.publish("process_charge_target", self.io.energy_convert_from_fe(ctl_proc.charge_target))
self.io.facility.ps.publish("process_gen_target", self.io.energy_convert_from_fe(ctl_proc.gen_target))
self.io.facility.ps.publish("process_waste_product", ctl_proc.waste_product)
self.io.facility.ps.publish("process_pu_fallback", ctl_proc.pu_fallback)
self.io.facility.ps.publish("process_sps_low_power", ctl_proc.sps_low_power)
@ -316,8 +316,8 @@ function process.start_ack_handle(response)
self.io.facility.ps.publish("process_mode", ctl_proc.mode)
self.io.facility.ps.publish("process_burn_target", ctl_proc.burn_target)
self.io.facility.ps.publish("process_charge_target", ctl_proc.charge_target)
self.io.facility.ps.publish("process_gen_target", ctl_proc.gen_target)
self.io.facility.ps.publish("process_charge_target", self.io.energy_convert_from_fe(ctl_proc.charge_target))
self.io.facility.ps.publish("process_gen_target", self.io.energy_convert_from_fe(ctl_proc.gen_target))
self.io.facility.start_ack(ack)
end

View File

@ -1,7 +1,7 @@
local style = require("coordinator.ui.style")
local iocontrol = require("coordinator.iocontrol")
local style = require("coordinator.ui.style")
local core = require("graphics.core")
local Rectangle = require("graphics.elements.rectangle")

View File

@ -1,5 +1,7 @@
local util = require("scada-common.util")
local iocontrol = require("coordinator.iocontrol")
local style = require("coordinator.ui.style")
local core = require("graphics.core")
@ -34,6 +36,8 @@ local function new_view(root, x, y, data, ps, id)
local ind_yel = style.ind_yel
local ind_wht = style.ind_wht
local db = iocontrol.get_db()
local title = "INDUCTION MATRIX"
if type(id) == "number" then title = title .. id end
@ -48,24 +52,24 @@ local function new_view(root, x, y, data, ps, id)
local rect = Rectangle{parent=matrix,border=border(1,colors.gray,true),width=33,height=22,x=1,y=3}
local status = StateIndicator{parent=rect,x=10,y=1,states=style.imatrix.states,value=1,min_width=14}
local capacity = PowerIndicator{parent=rect,x=7,y=3,lu_colors=lu_col,label="Capacity:",format="%8.2f",value=0,width=26,fg_bg=text_fg}
local energy = PowerIndicator{parent=rect,x=7,y=4,lu_colors=lu_col,label="Energy: ",format="%8.2f",value=0,width=26,fg_bg=text_fg}
local avg_chg = PowerIndicator{parent=rect,x=7,y=5,lu_colors=lu_col,label="\xb7Average:",format="%8.2f",value=0,width=26,fg_bg=text_fg}
local input = PowerIndicator{parent=rect,x=7,y=6,lu_colors=lu_col,label="Input: ",format="%8.2f",rate=true,value=0,width=26,fg_bg=text_fg}
local avg_in = PowerIndicator{parent=rect,x=7,y=7,lu_colors=lu_col,label="\xb7Average:",format="%8.2f",rate=true,value=0,width=26,fg_bg=text_fg}
local output = PowerIndicator{parent=rect,x=7,y=8,lu_colors=lu_col,label="Output: ",format="%8.2f",rate=true,value=0,width=26,fg_bg=text_fg}
local avg_out = PowerIndicator{parent=rect,x=7,y=9,lu_colors=lu_col,label="\xb7Average:",format="%8.2f",rate=true,value=0,width=26,fg_bg=text_fg}
local trans_cap = PowerIndicator{parent=rect,x=7,y=10,lu_colors=lu_col,label="Max I/O: ",format="%8.2f",rate=true,value=0,width=26,fg_bg=text_fg}
local capacity = PowerIndicator{parent=rect,x=7,y=3,lu_colors=lu_col,label="Capacity:",unit=db.energy_label,format="%8.2f",value=0,width=26,fg_bg=text_fg}
local energy = PowerIndicator{parent=rect,x=7,y=4,lu_colors=lu_col,label="Energy: ",unit=db.energy_label,format="%8.2f",value=0,width=26,fg_bg=text_fg}
local avg_chg = PowerIndicator{parent=rect,x=7,y=5,lu_colors=lu_col,label="\xb7Average:",unit=db.energy_label,format="%8.2f",value=0,width=26,fg_bg=text_fg}
local input = PowerIndicator{parent=rect,x=7,y=6,lu_colors=lu_col,label="Input: ",unit=db.energy_label,format="%8.2f",rate=true,value=0,width=26,fg_bg=text_fg}
local avg_in = PowerIndicator{parent=rect,x=7,y=7,lu_colors=lu_col,label="\xb7Average:",unit=db.energy_label,format="%8.2f",rate=true,value=0,width=26,fg_bg=text_fg}
local output = PowerIndicator{parent=rect,x=7,y=8,lu_colors=lu_col,label="Output: ",unit=db.energy_label,format="%8.2f",rate=true,value=0,width=26,fg_bg=text_fg}
local avg_out = PowerIndicator{parent=rect,x=7,y=9,lu_colors=lu_col,label="\xb7Average:",unit=db.energy_label,format="%8.2f",rate=true,value=0,width=26,fg_bg=text_fg}
local trans_cap = PowerIndicator{parent=rect,x=7,y=10,lu_colors=lu_col,label="Max I/O: ",unit=db.energy_label,format="%8.2f",rate=true,value=0,width=26,fg_bg=text_fg}
status.register(ps, "computed_status", status.update)
capacity.register(ps, "max_energy", function (val) capacity.update(util.joules_to_fe(val)) end)
energy.register(ps, "energy", function (val) energy.update(util.joules_to_fe(val)) end)
capacity.register(ps, "max_energy", function (val) capacity.update(db.energy_convert(val)) end)
energy.register(ps, "energy", function (val) energy.update(db.energy_convert(val)) end)
avg_chg.register(ps, "avg_charge", avg_chg.update)
input.register(ps, "last_input", function (val) input.update(util.joules_to_fe(val)) end)
input.register(ps, "last_input", function (val) input.update(db.energy_convert(val)) end)
avg_in.register(ps, "avg_inflow", avg_in.update)
output.register(ps, "last_output", function (val) output.update(util.joules_to_fe(val)) end)
output.register(ps, "last_output", function (val) output.update(db.energy_convert(val)) end)
avg_out.register(ps, "avg_outflow", avg_out.update)
trans_cap.register(ps, "transfer_cap", function (val) trans_cap.update(util.joules_to_fe(val)) end)
trans_cap.register(ps, "transfer_cap", function (val) trans_cap.update(db.energy_convert(val)) end)
local fill = DataIndicator{parent=rect,x=11,y=12,lu_colors=lu_col,label="Fill: ",format="%7.2f",unit="%",value=0,width=20,fg_bg=text_fg}
local cells = DataIndicator{parent=rect,x=11,y=13,lu_colors=lu_col,label="Cells: ",format="%7d",value=0,width=18,fg_bg=text_fg}

View File

@ -56,8 +56,10 @@ local function new_view(root, x, y)
local blk_brn = cpair(colors.black, colors.brown)
local blk_pur = cpair(colors.black, colors.purple)
local facility = iocontrol.get_db().facility
local units = iocontrol.get_db().units
local db = iocontrol.get_db()
local facility = db.facility
local units = db.units
local main = Div{parent=root,width=128,height=24,x=x,y=y}
@ -141,22 +143,22 @@ local function new_view(root, x, y)
local chg_target = Div{parent=targets,x=9,y=6,width=23,height=3,fg_bg=s_hi_box}
local c_target = SpinboxNumeric{parent=chg_target,x=2,y=1,whole_num_precision=15,fractional_precision=0,min=0,arrow_fg_bg=arrow_fg_bg,arrow_disable=style.theme.disabled}
TextBox{parent=chg_target,x=18,y=2,text="MFE",fg_bg=style.theme.label_fg}
local cur_charge = DataIndicator{parent=targets,x=9,y=9,label="",format="%19d",value=0,unit="MFE",commas=true,lu_colors=black,width=23,fg_bg=blk_brn}
TextBox{parent=chg_target,x=18,y=2,text="M"..db.energy_label,fg_bg=style.theme.label_fg}
local cur_charge = DataIndicator{parent=targets,x=9,y=9,label="",format="%19d",value=0,unit="M"..db.energy_label,commas=true,lu_colors=black,width=23,fg_bg=blk_brn}
c_target.register(facility.ps, "process_charge_target", c_target.set_value)
cur_charge.register(facility.induction_ps_tbl[1], "avg_charge", function (fe) cur_charge.update(fe / 1000000) end)
cur_charge.register(facility.induction_ps_tbl[1], "avg_charge", function (fe) cur_charge.update(db.energy_convert_from_fe(fe) / 1000000) end)
local gen_tag = Div{parent=targets,x=1,y=11,width=8,height=4,fg_bg=blk_pur}
TextBox{parent=gen_tag,x=2,y=2,text="Gen. Target",width=7,height=2}
local gen_target = Div{parent=targets,x=9,y=11,width=23,height=3,fg_bg=s_hi_box}
local g_target = SpinboxNumeric{parent=gen_target,x=8,y=1,whole_num_precision=9,fractional_precision=0,min=0,arrow_fg_bg=arrow_fg_bg,arrow_disable=style.theme.disabled}
TextBox{parent=gen_target,x=18,y=2,text="kFE/t",fg_bg=style.theme.label_fg}
local cur_gen = DataIndicator{parent=targets,x=9,y=14,label="",format="%17d",value=0,unit="kFE/t",commas=true,lu_colors=black,width=23,fg_bg=blk_brn}
TextBox{parent=gen_target,x=18,y=2,text="k"..db.energy_label.."/t",fg_bg=style.theme.label_fg}
local cur_gen = DataIndicator{parent=targets,x=9,y=14,label="",format="%17d",value=0,unit="k"..db.energy_label.."/t",commas=true,lu_colors=black,width=23,fg_bg=blk_brn}
g_target.register(facility.ps, "process_gen_target", g_target.set_value)
cur_gen.register(facility.induction_ps_tbl[1], "last_input", function (j) cur_gen.update(util.round(util.joules_to_fe(j) / 1000)) end)
cur_gen.register(facility.induction_ps_tbl[1], "last_input", function (j) cur_gen.update(util.round(db.energy_convert(j) / 1000)) end)
-----------------
-- unit limits --
@ -262,7 +264,10 @@ local function new_view(root, x, y)
local limits = {}
for i = 1, #rate_limits do limits[i] = rate_limits[i].get_value() end
process.save(mode.get_value(), b_target.get_value(), c_target.get_value(), g_target.get_value(), limits)
process.save(mode.get_value(), b_target.get_value(),
db.energy_convert_to_fe(c_target.get_value()),
db.energy_convert_to_fe(g_target.get_value()),
limits)
end
-- start automatic control after saving process control settings

View File

@ -1,4 +1,4 @@
local util = require("scada-common.util")
local iocontrol = require("coordinator.iocontrol")
local style = require("coordinator.ui.style")
@ -24,14 +24,16 @@ local function new_view(root, x, y, ps)
local text_fg = style.theme.text_fg
local lu_col = style.lu_colors
local db = iocontrol.get_db()
local turbine = Rectangle{parent=root,border=border(1,colors.gray,true),width=23,height=7,x=x,y=y}
local status = StateIndicator{parent=turbine,x=7,y=1,states=style.turbine.states,value=1,min_width=12}
local prod_rate = PowerIndicator{parent=turbine,x=5,y=3,lu_colors=lu_col,label="",format="%10.2f",value=0,rate=true,width=16,fg_bg=text_fg}
local prod_rate = PowerIndicator{parent=turbine,x=5,y=3,lu_colors=lu_col,label="",unit=db.energy_label,format="%10.2f",value=0,rate=true,width=16,fg_bg=text_fg}
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}
status.register(ps, "computed_status", status.update)
prod_rate.register(ps, "prod_rate", function (val) prod_rate.update(util.joules_to_fe(val)) end)
prod_rate.register(ps, "prod_rate", function (val) prod_rate.update(db.energy_convert(val)) end)
flow_rate.register(ps, "steam_input_rate", flow_rate.update)
local steam = VerticalBar{parent=turbine,x=2,y=1,fg_bg=cpair(colors.white,colors.gray),height=4,width=1}

View File

@ -6,6 +6,7 @@ local element = require("graphics.element")
---@class power_indicator_args
---@field label string indicator label
---@field unit string energy unit
---@field format string power format override (lua string format)
---@field rate boolean? whether to append /t to the end (power per tick)
---@field lu_colors? cpair label foreground color (a), unit foreground color (b)
@ -24,6 +25,7 @@ local element = require("graphics.element")
---@return graphics_element element, element_id id
local function power(args)
element.assert(type(args.value) == "number", "value is a required field")
element.assert(type(args.unit) == "string", "unit is a required field")
element.assert(util.is_int(args.width), "width is a required field")
args.height = 1
@ -40,7 +42,7 @@ local function power(args)
function e.on_update(value)
e.value = value
local data_str, unit = util.power_format(value, false, args.format)
local data_str, unit = util.power_format(value, args.unit, false, args.format)
-- write data
e.w_set_cur(data_start, 1)
@ -53,14 +55,13 @@ local function power(args)
end
-- append per tick if rate is set
-- add space to FE so we don't end up with FEE (after having kFE for example)
if args.rate == true then
unit = unit .. "/t"
if unit == "FE/t" then unit = "FE/t " end
else
if unit == "FE" then unit = "FE " end
end
-- add space to unit so we don't end up with something like FEE after having kFE
unit = util.strminw(unit, 5)
e.w_write(" " .. unit)
end

View File

@ -96,6 +96,25 @@ types.TEMP_SCALE_UNITS = {
"\xb0R"
}
---@enum ENERGY_SCALE
types.ENERGY_SCALE = {
JOULES = 1,
FE = 2,
RF = 3
}
types.ENERGY_SCALE_NAMES = {
"Joules (J)",
"Forge Energy (FE)",
"Redstone Flux (RF)"
}
types.ENERGY_SCALE_UNITS = {
"J",
"FE",
"RF"
}
---@enum PANEL_LINK_STATE
types.PANEL_LINK_STATE = {
LINKED = 1,

View File

@ -24,7 +24,7 @@ local t_pack = table.pack
local util = {}
-- scada-common version
util.version = "1.4.1"
util.version = "1.4.2"
util.TICK_TIME_S = 0.05
util.TICK_TIME_MS = 50
@ -120,6 +120,13 @@ function util.strwrap(str, limit)
return cc_strings.wrap(str, limit)
end
-- make sure a string is at least 'width' long
---@nodiscard
---@param str string
---@param width integer minimum width
---@return string string
function util.strminw(str, width) return cc_strings.ensure_width(str, width) end
-- concatenation with built-in to string
---@nodiscard
---@vararg any
@ -375,65 +382,63 @@ end
--#region MEKANISM MATH
-- convert Joules to FE
-- convert Joules to FE (or RF)
---@nodiscard
---@param J number Joules
---@return number FE Forge Energy
function util.joules_to_fe(J) return (J * 0.4) end
---@return number FE Forge Energy or Redstone Flux
function util.joules_to_fe_rf(J) return (J * 0.4) end
-- convert FE to Joules
-- convert FE (or RF) to Joules
---@nodiscard
---@param FE number Forge Energy
---@param FE number Forge Energy or Redstone Flux
---@return number J Joules
function util.fe_to_joules(FE) return (FE * 2.5) end
function util.fe_rf_to_joules(FE) return (FE * 2.5) end
local function kFE(fe) return fe / 1000.0 end
local function MFE(fe) return fe / 1000000.0 end
local function GFE(fe) return fe / 1000000000.0 end
local function TFE(fe) return fe / 1000000000000.0 end
local function PFE(fe) return fe / 1000000000000000.0 end
local function EFE(fe) return fe / 1000000000000000000.0 end -- if you accomplish this please touch grass
local function ZFE(fe) return fe / 1000000000000000000000.0 end -- how & why did you do this?
-- format a power value into XXX.XX UNIT format (FE, kFE, MFE, GFE, TFE, PFE, EFE, ZFE)
-- format a power value into XXX.XX UNIT format<br>
-- example for FE: FE, kFE, MFE, GFE, TFE, PFE, EFE, ZFE
---@nodiscard
---@param fe number forge energy value
---@param e number energy value
---@param label string energy scale label
---@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)
---@return string str, string unit
function util.power_format(e, label, combine_label, format)
local unit, value
if type(format) ~= "string" then format = "%.2f" end
if fe < 1000.0 then
unit = "FE"
value = fe
elseif fe < 1000000.0 then
unit = "kFE"
value = kFE(fe)
elseif fe < 1000000000.0 then
unit = "MFE"
value = MFE(fe)
elseif fe < 1000000000000.0 then
unit = "GFE"
value = GFE(fe)
elseif fe < 1000000000000000.0 then
unit = "TFE"
value = TFE(fe)
elseif fe < 1000000000000000000.0 then
unit = "PFE"
value = PFE(fe)
elseif fe < 1000000000000000000000.0 then
unit = "EFE"
value = EFE(fe)
if e < 1000.0 then
unit = ""
value = e
elseif e < 1000000.0 then
unit = "k"
value = e / 1000.0
elseif e < 1000000000.0 then
unit = "M"
value = e / 1000000.0
elseif e < 1000000000000.0 then
unit = "G"
value = e / 1000000000.0
elseif e < 1000000000000000.0 then
unit = "T"
value = e / 1000000000000.0
elseif e < 1000000000000000000.0 then
unit = "P"
value = e / 1000000000000000.0
elseif e < 1000000000000000000000.0 then
-- if you accomplish this please touch grass
unit = "E"
value = e / 1000000000000000000.0
else
unit = "ZFE"
value = ZFE(fe)
-- how & why did you do this?
unit = "Z"
value = e / 1000000000000000000000.0
end
unit = unit .. label
if combine_label then
return util.sprintf(util.c(format, " %s"), value, unit)
return util.sprintf(util.c(format, " %s"), value, unit), unit
else
return util.sprintf(format, value), unit
end

View File

@ -29,7 +29,7 @@ local DTV_RTU_S_DATA = qtypes.DTV_RTU_S_DATA
-- 7.14 kJ per blade for 1 mB of fissile fuel<br>
-- 2856 FE per blade per 1 mB, 285.6 FE per blade per 0.1 mB (minimum)
local POWER_PER_BLADE = util.joules_to_fe(7140)
local POWER_PER_BLADE = util.joules_to_fe_rf(7140)
local FLOW_STABILITY_DELAY_S = const.FLOW_STABILITY_DELAY_MS / 1000
@ -332,9 +332,9 @@ function facility.new(config, cooling_conf)
end
if has_data then
local energy = util.joules_to_fe(db.tanks.energy)
local input = util.joules_to_fe(db.state.last_input)
local output = util.joules_to_fe(db.state.last_output)
local energy = util.joules_to_fe_rf(db.tanks.energy)
local input = util.joules_to_fe_rf(db.state.last_input)
local output = util.joules_to_fe_rf(db.state.last_output)
if self.im_stat_init then
self.avg_charge.record(energy, charge_update)
@ -1283,7 +1283,7 @@ function facility.new(config, cooling_conf)
status.induction[i] = { matrix.is_faulted(), db.formed, db.state, db.tanks }
local fe_per_ms = self.avg_net.compute()
local remaining = util.joules_to_fe(util.trinary(fe_per_ms >= 0, db.tanks.energy_need, db.tanks.energy))
local remaining = util.joules_to_fe_rf(util.trinary(fe_per_ms >= 0, db.tanks.energy_need, db.tanks.energy))
status.power[4] = remaining / fe_per_ms
end

View File

@ -21,7 +21,7 @@ local supervisor = require("supervisor.supervisor")
local svsessions = require("supervisor.session.svsessions")
local SUPERVISOR_VERSION = "v1.4.1"
local SUPERVISOR_VERSION = "v1.4.2"
local println = util.println
local println_ts = util.println_ts