Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 26 additions & 2 deletions tests/unit/handlers/coolingSystem.handlers.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ const createMockEquipment = () => ({
{ equipment: 'TC-7501', is_active: true, miner_side_out_temp: { value: 37.1, unit: '°C' }, tower_side_in_temp: { value: 29.2, unit: '°C' }, tower_side_out_temp: { value: 36.9, unit: '°C' }, tcv_position: { value: 55, unit: '%' } }
],
cooling_towers: [
{ equipment: 'TR-7501', is_running: true, fan_status: 'Running', fan_cv: { value: 60, unit: 'CV' }, level: { value: 82, unit: '%' }, vibration: { value: 0.8, unit: 'mm/s', status: 'Normal' } },
{ equipment: 'TR-7502', is_running: true, fan_status: 'Running', fan_cv: { value: 45, unit: 'CV' }, level: { value: 85, unit: '%' }, vibration: { value: 0.6, unit: 'mm/s', status: 'Normal' } }
{ equipment: 'TR-7501', circuit: 'COOLING_TOWER', is_running: true, fan_status: 'Running', fan_cv: { value: 60, unit: 'CV' }, level: { value: 82, unit: '%' }, vibration: { value: 0.8, unit: 'mm/s', status: 'Normal' } },
{ equipment: 'TR-7502', circuit: 'HVAC_CONDENSER', is_running: true, fan_status: 'Running', fan_cv: { value: 45, unit: 'CV' }, level: { value: 85, unit: '%' }, vibration: { value: 0.6, unit: 'mm/s', status: 'Normal' } }
],
valves: [
{ equipment: 'PCV-7502', position: { value: 12, unit: '%' } },
Expand Down Expand Up @@ -1409,6 +1409,30 @@ test('6 - differential_pressure populated when per-group PTs configured', (t) =>
t.pass()
})

test('6 - differential_pressure from single-transmitter array (supply/return/diff)', (t) => {
const equipment = createMockEquipment()
equipment.pressures = [
...equipment.pressures,
{ equipment: 'PT-7502-A', value: 2.81, unit: 'bar', supply_pressure: 2.81, return_pressure: 2.2, differential_pressure: 0.61 },
{ equipment: 'PT-7502-B', value: 2.9, unit: 'bar', supply_pressure: 2.9, return_pressure: 2.3 }
]
const config = createMockConfig()
config.cooling_system.miner_loop.line1.group_pressure_sensors = ['PT-7502-A', 'PT-7502-B']
const view = buildMinersCircuit1View(equipment, config)

const dp = view.lines[0].differential_pressure
t.is(dp.length, 2, 'one row per transmitter')
// Group 1: device-provided differential is preferred
t.is(dp[0].supply.tag, 'PT-7502-A', 'supply tag = transmitter id')
t.is(dp[0].return.tag, 'PT-7502-A', 'return tag = same transmitter id')
t.is(dp[0].supply.reading.value, 2.81, 'supply from supply_pressure')
t.is(dp[0].return.reading.value, 2.2, 'return from return_pressure')
t.is(dp[0].delta_p.value, 0.61, 'uses device-provided differential_pressure')
// Group 2: no device differential -> derived from supply - return
t.is(dp[1].delta_p.value, 0.6, 'derived delta-p = supply - return when DP absent')
t.pass()
})

test('7 - rack_statuses derived from live rack power (online = power > 0)', (t) => {
const equipment = createMockEquipment()
const config = createMockConfig()
Expand Down
71 changes: 59 additions & 12 deletions workers/lib/server/handlers/cooling.system.handlers.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,34 @@ function buildVibrationSwitch (vibrationSwitches, switchTag) {

function buildGroupDifferentialPressure (lineConfig, pressures) {
const groupSensors = lineConfig.group_pressure_sensors || {}

if (Array.isArray(groupSensors)) {
return groupSensors.map((sensorId, i) => {
const pt = pressures?.find(s => s.equipment === sensorId) || null
const mkSlot = (val) => ({
tag: sensorId,
type: pt?.type || null,
reading: val != null ? { value: val, unit: pt?.unit || 'bar' } : null
})
const supply = mkSlot(pt?.supply_pressure)
const ret = mkSlot(pt?.return_pressure)
const supplyVal = supply.reading?.value
const returnVal = ret.reading?.value
const deltaPVal = pt?.differential_pressure != null
? Math.round(pt.differential_pressure * 100) / 100
: (supplyVal != null && returnVal != null
? Math.round((supplyVal - returnVal) * 100) / 100
: null)
const unit = supply.reading?.unit || ret.reading?.unit || pt?.unit || 'bar'
return {
group: i + 1,
supply,
return: ret,
delta_p: deltaPVal != null ? { value: deltaPVal, unit } : null
}
})
}

const supplyIds = groupSensors.supply || []
const returnIds = groupSensors.return || []
const count = Math.max(supplyIds.length, returnIds.length)
Expand Down Expand Up @@ -183,13 +211,25 @@ function buildMinersCircuit1View (equipment, config) {
// Compute summary values from line sensor data — units derived from sensors
const tempUnit = lines[0]?.supply?.temperature?.unit
const flowUnit = lines[0]?.supply?.flow?.unit
const pressureUnit = lines[0]?.supply?.pressure?.unit
// avg over the 16 per-group PTs, not the unset per-line pressure sensors
const allGroups = lines.flatMap(l => l.differential_pressure || [])
const pressureUnit = allGroups.find(g => g.supply?.reading?.unit)?.supply?.reading?.unit ||
allGroups.find(g => g.return?.reading?.unit)?.return?.reading?.unit ||
lines[0]?.supply?.pressure?.unit

const allSupplyTemps = lines.map(l => l.supply.temperature?.value).filter(v => v != null)
const allReturnTemps = lines.map(l => l.return.temperature?.value).filter(v => v != null)
const allSupplyFlows = lines.map(l => l.supply.flow?.value).filter(v => v != null)
const allSupplyPressures = lines.map(l => l.supply.pressure?.value).filter(v => v != null)
const allReturnPressures = lines.map(l => l.return.pressure?.value).filter(v => v != null)
const groupSupplyPressures = allGroups.map(g => g.supply?.reading?.value).filter(v => v != null)
const groupReturnPressures = allGroups.map(g => g.return?.reading?.value).filter(v => v != null)
const allGroupDeltaP = allGroups.map(g => g.delta_p?.value).filter(v => v != null)
// prefer per-group PTs; fall back to line-level pressure
const allSupplyPressures = groupSupplyPressures.length > 0
? groupSupplyPressures
: lines.map(l => l.supply.pressure?.value).filter(v => v != null)
const allReturnPressures = groupReturnPressures.length > 0
? groupReturnPressures
: lines.map(l => l.return.pressure?.value).filter(v => v != null)

const avgSupplyTemp = allSupplyTemps.length > 0
? Math.round((allSupplyTemps.reduce((a, b) => a + b, 0) / allSupplyTemps.length) * 10) / 10
Expand All @@ -213,9 +253,11 @@ function buildMinersCircuit1View (equipment, config) {
const outletPressureAvg = allReturnPressures.length > 0
? Math.round((allReturnPressures.reduce((a, b) => a + b, 0) / allReturnPressures.length) * 100) / 100
: null
const deltaPAvg = (inletPressureAvg != null && outletPressureAvg != null)
? Math.round((inletPressureAvg - outletPressureAvg) * 100) / 100
: null
const deltaPAvg = allGroupDeltaP.length > 0
? Math.round((allGroupDeltaP.reduce((a, b) => a + b, 0) / allGroupDeltaP.length) * 100) / 100
: ((inletPressureAvg != null && outletPressureAvg != null)
? Math.round((inletPressureAvg - outletPressureAvg) * 100) / 100
: null)

const controlValveEntries = coolingConfig.control_valves || {}
const controlValves = {}
Expand Down Expand Up @@ -261,7 +303,7 @@ function buildMinersCircuit2View (equipment, config) {
const temperatures = equipment.temperatures
const levels = equipment.levels
const heatExchangers = equipment.heat_exchangers
const coolingTowers = equipment.cooling_towers
const coolingTowers = (equipment.cooling_towers || []).filter(ct => ct.circuit === 'COOLING_TOWER')
const vibrationSwitches = equipment.vibration_switches
const valves = equipment.valves
const tanks = equipment.tanks
Expand Down Expand Up @@ -321,19 +363,24 @@ function buildMinersCircuit2View (equipment, config) {
}
})

// Summary: pre-HX and post-HX temps from heat exchangers
// pre/post-HX from the loop's configured sensors, else HX-derived
const preHxConfigReading = getSensorReading(temperatures, towerConfig.pre_hx_temp_sensor)
const postHxConfigReading = getSensorReading(temperatures, towerConfig.post_hx_temp_sensor)

const allTowerSideIn = heatExchangerData.map(hx => hx.tower_side_in_temp?.value).filter(v => v != null)
const allTowerSideOut = heatExchangerData.map(hx => hx.tower_side_out_temp?.value).filter(v => v != null)
const preHxTemp = allTowerSideIn.length > 0
const hxPreHxTemp = allTowerSideIn.length > 0
? Math.round((allTowerSideIn.reduce((a, b) => a + b, 0) / allTowerSideIn.length) * 10) / 10
: null
const postHxTemp = allTowerSideOut.length > 0
const hxPostHxTemp = allTowerSideOut.length > 0
? Math.round((allTowerSideOut.reduce((a, b) => a + b, 0) / allTowerSideOut.length) * 10) / 10
: null
const preHxTemp = preHxConfigReading?.value ?? hxPreHxTemp
const postHxTemp = postHxConfigReading?.value ?? hxPostHxTemp
const deltaT = (preHxTemp != null && postHxTemp != null)
? Math.round((postHxTemp - preHxTemp) * 10) / 10
: null
const tempUnit = heatExchangerData[0]?.tower_side_in_temp?.unit
const tempUnit = preHxConfigReading?.unit || postHxConfigReading?.unit || heatExchangerData[0]?.tower_side_in_temp?.unit

// Tower level from config sensor
const towerLevelSensor = towerConfig.tower_level_sensor
Expand Down Expand Up @@ -706,7 +753,7 @@ function buildHvacCircuit2View (equipment, config) {
const temperatures = equipment.temperatures
const flows = equipment.flows
const levels = equipment.levels
const coolingTowers = equipment.cooling_towers
const coolingTowers = (equipment.cooling_towers || []).filter(ct => ct.circuit === 'HVAC_CONDENSER')
const condenserConfig = config?.cooling_system?.hvac_condenser || {}
const viewConfig = config?.cooling_system?.view_metadata?.hvac?.circuit2 || {}

Expand Down
Loading