mirror of
https://github.com/MikaylaFischler/cc-mek-scada.git
synced 2024-08-30 18:22:34 +00:00
#469 induction matrix charge ETAs and misc cleanup/updates
This commit is contained in:
parent
7b8cea4a5c
commit
35bf56663f
@ -663,10 +663,26 @@ function iocontrol.update_facility_status(status)
|
||||
fac.rtu_count = rtu_statuses.count
|
||||
|
||||
-- power statistics
|
||||
if type(rtu_statuses.power) == "table" then
|
||||
fac.induction_ps_tbl[1].publish("avg_charge", rtu_statuses.power[1])
|
||||
fac.induction_ps_tbl[1].publish("avg_inflow", rtu_statuses.power[2])
|
||||
fac.induction_ps_tbl[1].publish("avg_outflow", rtu_statuses.power[3])
|
||||
if type(rtu_statuses.power) == "table" and #rtu_statuses.power == 4 then
|
||||
local data = fac.induction_data_tbl[1] ---@type imatrix_session_db
|
||||
local ps = fac.induction_ps_tbl[1] ---@type psil
|
||||
|
||||
local chg = tonumber(rtu_statuses.power[1])
|
||||
local in_f = tonumber(rtu_statuses.power[2])
|
||||
local out_f = tonumber(rtu_statuses.power[3])
|
||||
local eta = tonumber(rtu_statuses.power[4])
|
||||
|
||||
ps.publish("avg_charge", chg)
|
||||
ps.publish("avg_inflow", in_f)
|
||||
ps.publish("avg_outflow", out_f)
|
||||
ps.publish("eta_ms", eta)
|
||||
|
||||
ps.publish("is_charging", in_f > out_f)
|
||||
ps.publish("is_discharging", out_f > in_f)
|
||||
|
||||
if data and data.build then
|
||||
ps.publish("at_max_io", in_f >= data.build.transfer_cap or out_f >= data.build.transfer_cap)
|
||||
end
|
||||
else
|
||||
log.debug(log_header .. "power statistics list not a table")
|
||||
valid = false
|
||||
|
@ -19,7 +19,7 @@ local renderer = require("coordinator.renderer")
|
||||
local sounder = require("coordinator.sounder")
|
||||
local threads = require("coordinator.threads")
|
||||
|
||||
local COORDINATOR_VERSION = "v1.4.3"
|
||||
local COORDINATOR_VERSION = "v1.4.4"
|
||||
|
||||
local CHUNK_LOAD_DELAY_S = 30.0
|
||||
|
||||
|
@ -9,6 +9,7 @@ local Rectangle = require("graphics.elements.rectangle")
|
||||
local TextBox = require("graphics.elements.textbox")
|
||||
|
||||
local DataIndicator = require("graphics.elements.indicators.data")
|
||||
local IndicatorLight = require("graphics.elements.indicators.light")
|
||||
local PowerIndicator = require("graphics.elements.indicators.power")
|
||||
local StateIndicator = require("graphics.elements.indicators.state")
|
||||
local VerticalBar = require("graphics.elements.indicators.vbar")
|
||||
@ -26,9 +27,13 @@ local ALIGN = core.ALIGN
|
||||
---@param ps psil ps interface
|
||||
---@param id number? matrix ID
|
||||
local function new_view(root, x, y, data, ps, id)
|
||||
local label_fg = style.theme.label_fg
|
||||
local text_fg = style.theme.text_fg
|
||||
local lu_col = style.lu_colors
|
||||
|
||||
local ind_yel = style.ind_yel
|
||||
local ind_wht = style.ind_wht
|
||||
|
||||
local title = "INDUCTION MATRIX"
|
||||
if type(id) == "number" then title = title .. id end
|
||||
|
||||
@ -43,44 +48,46 @@ 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 energy = PowerIndicator{parent=rect,x=7,y=3,lu_colors=lu_col,label="Energy: ",format="%8.2f",value=0,width=26,fg_bg=text_fg}
|
||||
local capacity = PowerIndicator{parent=rect,x=7,y=4,lu_colors=lu_col,label="Capacity:",format="%8.2f",value=0,width=26,fg_bg=text_fg}
|
||||
local input = PowerIndicator{parent=rect,x=7,y=5,lu_colors=lu_col,label="Input: ",format="%8.2f",rate=true,value=0,width=26,fg_bg=text_fg}
|
||||
local output = PowerIndicator{parent=rect,x=7,y=6,lu_colors=lu_col,label="Output: ",format="%8.2f",rate=true,value=0,width=26,fg_bg=text_fg}
|
||||
|
||||
local avg_chg = PowerIndicator{parent=rect,x=7,y=8,lu_colors=lu_col,label="Avg. Chg:",format="%8.2f",value=0,width=26,fg_bg=text_fg}
|
||||
local avg_in = PowerIndicator{parent=rect,x=7,y=9,lu_colors=lu_col,label="Avg. In: ",format="%8.2f",rate=true,value=0,width=26,fg_bg=text_fg}
|
||||
local avg_out = PowerIndicator{parent=rect,x=7,y=10,lu_colors=lu_col,label="Avg. Out:",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:",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}
|
||||
|
||||
status.register(ps, "computed_status", status.update)
|
||||
energy.register(ps, "energy", function (val) energy.update(util.joules_to_fe(val)) end)
|
||||
capacity.register(ps, "max_energy", function (val) capacity.update(util.joules_to_fe(val)) end)
|
||||
input.register(ps, "last_input", function (val) input.update(util.joules_to_fe(val)) end)
|
||||
output.register(ps, "last_output", function (val) output.update(util.joules_to_fe(val)) end)
|
||||
|
||||
energy.register(ps, "energy", function (val) energy.update(util.joules_to_fe(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)
|
||||
avg_in.register(ps, "avg_inflow", avg_in.update)
|
||||
output.register(ps, "last_output", function (val) output.update(util.joules_to_fe(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)
|
||||
|
||||
local fill = DataIndicator{parent=rect,x=11,y=12,lu_colors=lu_col,label="Fill:",unit="%",format="%8.2f",value=0,width=18,fg_bg=text_fg}
|
||||
|
||||
local cells = DataIndicator{parent=rect,x=11,y=14,lu_colors=lu_col,label="Cells: ",format="%7d",value=0,width=18,fg_bg=text_fg}
|
||||
local providers = DataIndicator{parent=rect,x=11,y=15,lu_colors=lu_col,label="Providers:",format="%7d",value=0,width=18,fg_bg=text_fg}
|
||||
|
||||
TextBox{parent=rect,text="Transfer Capacity",x=11,y=17,height=1,width=17,fg_bg=style.theme.label_fg}
|
||||
local trans_cap = PowerIndicator{parent=rect,x=19,y=18,lu_colors=lu_col,label="",format="%5.2f",rate=true,value=0,width=12,fg_bg=text_fg}
|
||||
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}
|
||||
local providers = DataIndicator{parent=rect,x=11,y=14,lu_colors=lu_col,label="Providers:",format="%7d",value=0,width=18,fg_bg=text_fg}
|
||||
|
||||
fill.register(ps, "energy_fill", function (val) fill.update(val * 100) end)
|
||||
cells.register(ps, "cells", cells.update)
|
||||
providers.register(ps, "providers", providers.update)
|
||||
fill.register(ps, "energy_fill", function (val) fill.update(val * 100) end)
|
||||
trans_cap.register(ps, "transfer_cap", function (val) trans_cap.update(util.joules_to_fe(val)) end)
|
||||
|
||||
local chging = IndicatorLight{parent=rect,x=11,y=16,label="Charging",colors=ind_wht}
|
||||
local dischg = IndicatorLight{parent=rect,x=11,y=17,label="Discharging",colors=ind_wht}
|
||||
local max_io = IndicatorLight{parent=rect,x=11,y=18,label="Max I/O Rate",colors=ind_yel}
|
||||
|
||||
chging.register(ps, "is_charging", chging.update)
|
||||
dischg.register(ps, "is_discharging", dischg.update)
|
||||
max_io.register(ps, "at_max_io", max_io.update)
|
||||
|
||||
local charge = VerticalBar{parent=rect,x=2,y=2,fg_bg=cpair(colors.green,colors.gray),height=17,width=4}
|
||||
local in_cap = VerticalBar{parent=rect,x=7,y=12,fg_bg=cpair(colors.red,colors.gray),height=7,width=1}
|
||||
local out_cap = VerticalBar{parent=rect,x=9,y=12,fg_bg=cpair(colors.blue,colors.gray),height=7,width=1}
|
||||
|
||||
TextBox{parent=rect,text="FILL",x=2,y=20,height=1,width=4,fg_bg=text_fg}
|
||||
TextBox{parent=rect,text="I/O",x=7,y=20,height=1,width=3,fg_bg=text_fg}
|
||||
TextBox{parent=rect,text="FILL I/O",x=2,y=20,height=1,width=8,fg_bg=label_fg}
|
||||
|
||||
local function calc_saturation(val)
|
||||
if (type(data.build) == "table") and (type(data.build.transfer_cap) == "number") and (data.build.transfer_cap > 0) then
|
||||
@ -91,6 +98,49 @@ local function new_view(root, x, y, data, ps, id)
|
||||
charge.register(ps, "energy_fill", charge.update)
|
||||
in_cap.register(ps, "last_input", function (val) in_cap.update(calc_saturation(val)) end)
|
||||
out_cap.register(ps, "last_output", function (val) out_cap.update(calc_saturation(val)) end)
|
||||
|
||||
local eta = TextBox{parent=rect,x=11,y=20,width=20,height=1,text="ETA Unknown",alignment=ALIGN.CENTER,fg_bg=style.theme.field_box}
|
||||
|
||||
eta.register(ps, "eta_mss", function (eta_ms)
|
||||
local str, pre = "", util.trinary(eta_ms >= 0, "Full in ", "Empty in ")
|
||||
|
||||
local seconds = math.abs(eta_ms) / 1000
|
||||
local minutes = seconds / 60
|
||||
local hours = minutes / 60
|
||||
local days = hours / 24
|
||||
|
||||
if math.abs(eta_ms) < 1000 or (eta_ms ~= eta_ms) then
|
||||
-- really small or NaN
|
||||
str = "No ETA"
|
||||
elseif days < 1000 then
|
||||
days = math.floor(days)
|
||||
hours = math.floor(hours % 24)
|
||||
minutes = math.floor(minutes % 60)
|
||||
seconds = math.floor(seconds % 60)
|
||||
|
||||
if days > 0 then
|
||||
str = days .. "d"
|
||||
elseif hours > 0 then
|
||||
str = hours .. "h " .. minutes .. "m"
|
||||
elseif minutes > 0 then
|
||||
str = minutes .. "m " .. seconds .. "s"
|
||||
elseif seconds > 0 then
|
||||
str = seconds .. "s"
|
||||
end
|
||||
|
||||
str = pre .. str
|
||||
else
|
||||
local years = math.floor(days / 365.25)
|
||||
|
||||
if years <= 99999999 then
|
||||
str = pre .. years .. "y"
|
||||
else
|
||||
str = pre .. "eras"
|
||||
end
|
||||
end
|
||||
|
||||
eta.set_value(str)
|
||||
end)
|
||||
end
|
||||
|
||||
return new_view
|
||||
|
@ -17,7 +17,7 @@ local max_distance = nil
|
||||
local comms = {}
|
||||
|
||||
-- protocol/data versions (protocol/data independent changes tracked by util.lua version)
|
||||
comms.version = "2.5.0"
|
||||
comms.version = "2.5.1"
|
||||
comms.api_version = "0.0.1"
|
||||
|
||||
---@enum PROTOCOL
|
||||
|
@ -22,7 +22,7 @@ local t_pack = table.pack
|
||||
local util = {}
|
||||
|
||||
-- scada-common version
|
||||
util.version = "1.3.0"
|
||||
util.version = "1.3.1"
|
||||
|
||||
util.TICK_TIME_S = 0.05
|
||||
util.TICK_TIME_MS = 50
|
||||
@ -181,8 +181,7 @@ function util.round(x) return math.floor(x + 0.5) end
|
||||
-- get a new moving average object
|
||||
---@nodiscard
|
||||
---@param length integer history length
|
||||
---@param default number value to fill history with for first call to compute()
|
||||
function util.mov_avg(length, default)
|
||||
function util.mov_avg(length)
|
||||
local data = {}
|
||||
local index = 1
|
||||
local last_t = 0 ---@type number|nil
|
||||
@ -215,12 +214,10 @@ function util.mov_avg(length, default)
|
||||
---@return number average
|
||||
function public.compute()
|
||||
local sum = 0
|
||||
for i = 1, length do sum = sum + data[i] end
|
||||
return sum / length
|
||||
for i = 1, #data do sum = sum + data[i] end
|
||||
return sum / #data
|
||||
end
|
||||
|
||||
public.reset(default)
|
||||
|
||||
return public
|
||||
end
|
||||
|
||||
|
@ -128,9 +128,13 @@ function facility.new(config, cooling_conf)
|
||||
test_alarm_states = {},
|
||||
-- statistics
|
||||
im_stat_init = false,
|
||||
avg_charge = util.mov_avg(3, 0.0),
|
||||
avg_inflow = util.mov_avg(6, 0.0),
|
||||
avg_outflow = util.mov_avg(6, 0.0)
|
||||
avg_charge = util.mov_avg(3), -- 3 seconds
|
||||
avg_inflow = util.mov_avg(6), -- 3 seconds
|
||||
avg_outflow = util.mov_avg(6), -- 3 seconds
|
||||
-- induction matrix charge delta stats
|
||||
avg_net = util.mov_avg(60), -- 60 seconds
|
||||
charge_last = 0,
|
||||
charge_last_t = 0
|
||||
}
|
||||
|
||||
-- create units
|
||||
@ -307,15 +311,32 @@ function facility.new(config, cooling_conf)
|
||||
rate_update = db.state.last_update
|
||||
|
||||
if (charge_update > 0) and (rate_update > 0) 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)
|
||||
|
||||
if self.im_stat_init then
|
||||
self.avg_charge.record(util.joules_to_fe(db.tanks.energy), charge_update)
|
||||
self.avg_inflow.record(util.joules_to_fe(db.state.last_input), rate_update)
|
||||
self.avg_outflow.record(util.joules_to_fe(db.state.last_output), rate_update)
|
||||
self.avg_charge.record(energy, charge_update)
|
||||
self.avg_inflow.record(input, rate_update)
|
||||
self.avg_outflow.record(output, rate_update)
|
||||
|
||||
if charge_update ~= self.charge_last_t then
|
||||
local delta = (energy - self.charge_last) / (charge_update - self.charge_last_t)
|
||||
|
||||
self.charge_last = energy
|
||||
self.charge_last_t = charge_update
|
||||
|
||||
self.avg_net.record(delta, charge_update)
|
||||
end
|
||||
else
|
||||
self.im_stat_init = true
|
||||
self.avg_charge.reset(util.joules_to_fe(db.tanks.energy))
|
||||
self.avg_inflow.reset(util.joules_to_fe(db.state.last_input))
|
||||
self.avg_outflow.reset(util.joules_to_fe(db.state.last_output))
|
||||
|
||||
self.avg_charge.reset(energy)
|
||||
self.avg_inflow.reset(input)
|
||||
self.avg_outflow.reset(output)
|
||||
|
||||
self.charge_last = energy
|
||||
self.charge_last_t = charge_update
|
||||
end
|
||||
end
|
||||
else
|
||||
@ -1193,7 +1214,8 @@ function facility.new(config, cooling_conf)
|
||||
status.power = {
|
||||
self.avg_charge.compute(),
|
||||
self.avg_inflow.compute(),
|
||||
self.avg_outflow.compute()
|
||||
self.avg_outflow.compute(),
|
||||
0
|
||||
}
|
||||
|
||||
-- status of induction matricies (including tanks)
|
||||
@ -1201,7 +1223,12 @@ function facility.new(config, cooling_conf)
|
||||
for i = 1, #self.induction do
|
||||
local matrix = self.induction[i] ---@type unit_session
|
||||
local db = matrix.get_db() ---@type imatrix_session_db
|
||||
|
||||
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))
|
||||
status.power[4] = remaining / fe_per_ms
|
||||
end
|
||||
|
||||
-- status of sps
|
||||
|
@ -21,7 +21,7 @@ local supervisor = require("supervisor.supervisor")
|
||||
|
||||
local svsessions = require("supervisor.session.svsessions")
|
||||
|
||||
local SUPERVISOR_VERSION = "v1.3.7"
|
||||
local SUPERVISOR_VERSION = "v1.3.8"
|
||||
|
||||
local println = util.println
|
||||
local println_ts = util.println_ts
|
||||
|
@ -71,8 +71,8 @@ function unit.new(reactor_id, num_boilers, num_turbines, ext_idle)
|
||||
---@class _unit_self
|
||||
local self = {
|
||||
r_id = reactor_id,
|
||||
plc_s = nil, ---@class plc_session_struct
|
||||
plc_i = nil, ---@class plc_session
|
||||
plc_s = nil, ---@type plc_session_struct
|
||||
plc_i = nil, ---@type plc_session
|
||||
num_boilers = num_boilers,
|
||||
num_turbines = num_turbines,
|
||||
types = { DT_KEYS = DT_KEYS, AISTATE = AISTATE },
|
||||
|
Loading…
Reference in New Issue
Block a user