$source */ function array_value(array $source, string $key) { return array_key_exists($key, $source) ? $source[$key] : null; } function numeric_or_null($value): ?float { if ($value === null) { return null; } if (is_numeric($value)) { return (float) $value; } $normalised = str_replace([',', ' '], '', (string) $value); $normalised = preg_replace('/[^0-9.\-]/', '', $normalised ?? ''); if ($normalised === '' || !is_numeric($normalised)) { return null; } return (float) $normalised; } function format_number($value, int $decimals = 0): string { $numeric = numeric_or_null($value); return $numeric === null ? '—' : number_format($numeric, $decimals); } function format_with_unit($value, string $unit, int $decimals = 0): string { $formatted = format_number($value, $decimals); return $formatted === '—' ? $formatted : $formatted . ' ' . $unit; } /** * @param array $values */ function sum_numeric(array $values): ?float { $total = 0.0; $found = false; foreach ($values as $value) { $numeric = numeric_or_null($value); if ($numeric === null) { continue; } $total += $numeric; $found = true; } return $found ? $total : null; } function clamp_percent(?float $value): float { if ($value === null) { return 0.0; } return max(0.0, min(100.0, $value)); } function percent_label($value, int $decimals = 0): string { $numeric = numeric_or_null($value); return $numeric === null ? '—' : format_number($numeric, $decimals) . '%'; } function html(string $value): string { return htmlspecialchars($value, ENT_QUOTES, 'UTF-8'); } /** * @param array $source */ function value_num(array $source, string $key): ?float { return numeric_or_null(array_value($source, $key)); } /** * @param array $source */ function value_as_int(array $source, string $key): ?int { $numeric = value_num($source, $key); return $numeric === null ? null : (int) round($numeric); } function build_status(?int $rawValue, bool $autoIsZero = true): ?array { if ($rawValue === null) { return null; } $isAuto = $autoIsZero ? $rawValue === 0 : $rawValue === 1; return [ 'label' => $isAuto ? 'Auto' : 'Manual', 'class' => $isAuto ? 'status-pill--ok' : 'status-pill--alert', ]; } function build_switch(?int $rawValue, string $labelOn = 'On', string $labelOff = 'Off'): ?array { if ($rawValue === null) { return null; } $isOn = $rawValue === 0; return [ 'label' => $isOn ? $labelOn : $labelOff, 'class' => $isOn ? 'status-pill--ok' : 'status-pill--warn', ]; } function classify_live_steam(?float $value): ?array { if ($value === null) { return null; } if ($value <= 155) { return ['label' => 'Low', 'class' => 'status-pill--alert']; } if ($value <= 165) { return ['label' => 'Watch', 'class' => 'status-pill--warn']; } return ['label' => 'Stable', 'class' => 'status-pill--ok']; } function classify_exhaust(?float $value): ?array { if ($value === null) { return null; } if ($value <= 9) { return ['label' => 'Low', 'class' => 'status-pill--alert']; } if ($value <= 13) { return ['label' => 'Watch', 'class' => 'status-pill--warn']; } return ['label' => 'Stable', 'class' => 'status-pill--ok']; } function tank_level_state(?float $value): ?string { if ($value === null) { return null; } if ($value <= 20) { return 'low'; } if ($value >= 90) { return 'caution'; } return null; } include '../../items.php'; $valuesZero = $value ?? []; $roundedZero = $rounded ?? []; $idsZero = $ID ?? []; $roundedOneZero = $rounded1 ?? []; include '../../items2dec.php'; $valuesTwo = $value ?? []; $idsTwo = $ID ?? []; $value = $valuesZero; $rounded = $roundedZero; $ID = $idsZero; $rounded1 = $roundedOneZero; $now = new DateTimeImmutable('now', new DateTimeZone('America/Chicago')); $generatedAt = $now->format(DateTimeInterface::RFC3339); $cropDayRaw = capture_include('cropday.php'); $cropDay = $cropDayRaw !== '' ? $cropDayRaw : null; $tonsIn = numeric_or_null(capture_include('tonsin.php')); $recordTons = numeric_or_null(capture_include('record.php')); $recordDateRaw = capture_include('recorddate.php'); $recordDate = $recordDateRaw !== '' ? $recordDateRaw : null; $westAvg = numeric_or_null(capture_include('west15minavg.php')); $groundToday = sum_numeric([ value_num($value, 'CANETOT'), value_num($value, 'W TONS GROUND'), ]); $groundYesterday = sum_numeric([ value_num($value, 'PREVTONS'), value_num($value, 'WPREVGROUND'), ]); $runHours = value_num($value, 'RUNHRSTODAY'); $prevRunHours = value_num($value, 'PREVTIME'); $totalTonsPerHour = sum_numeric([ value_num($value, 'TONS_PER_HOUR'), value_num($value, 'RATE'), ]); $lossTime = value_num($value, 'LOSSTIME'); $eastAverage = value_num($value, 'AVG_TONS_PER_HOUR'); $summaryCards = [ [ 'label' => 'Cane In Today', 'value' => format_number($tonsIn), 'unit' => 'tons', ], [ 'label' => 'Ground Today', 'value' => format_number($groundToday), 'unit' => 'tons', ], [ 'label' => 'Total Ground Yesterday', 'value' => format_number($groundYesterday), 'unit' => 'tons', ], [ 'label' => 'Run Hours', 'value' => format_number($runHours, 1), 'unit' => 'hours', ], [ 'label' => 'Prev Run Hours', 'value' => format_number($prevRunHours, 1), 'unit' => 'hours', ], [ 'label' => 'Total Tons per Hour', 'value' => format_number($totalTonsPerHour), 'unit' => 'tons/hr', ], [ 'label' => 'East 15 Minute Avg', 'value' => format_number($eastAverage), 'unit' => 'tons/hr', ], [ 'label' => 'West 15 Minute Avg', 'value' => format_number($westAvg), 'unit' => 'tons/hr', ], [ 'label' => 'Loss Time Today', 'value' => format_number($lossTime, 2), 'unit' => 'hours', ], [ 'label' => 'Record Day', 'value' => format_number($recordTons), 'unit' => 'tons', 'note' => $recordDate ? 'on ' . $recordDate : null, ], ]; $levelThroughputSwitch = value_as_int($value, 'LEVEL_THROUGHPUT_SWITCH'); $millFourUnit = $levelThroughputSwitch === 1 ? 'tons/hr' : '%'; $eastStages = [ [ 'label' => 'Mill 1', 'stage' => '1', 'level' => value_num($value, 'MILL1LVLPV'), 'setpoint' => value_num($value, 'MILL1SP'), 'setpointUnit' => '%', 'rpm' => value_num($value, 'EMILL1RPM'), 'outputLabel' => 'Mill 1 OP', 'outputValue' => value_num($value, 'MILL1OUTPUT'), 'outputUnit' => '%', 'mode' => build_status(value_as_int($value, 'MILL1AUTOMAN'), true), ], [ 'label' => 'Mill 2', 'stage' => '2', 'level' => value_num($value, 'M2LVL'), 'setpoint' => value_num($value, 'MILL2SP'), 'setpointUnit' => '%', 'rpm' => value_num($value, 'EMILL2RPM'), 'outputLabel' => 'MCC Output', 'outputValue' => value_num($value, 'MCCOUTPUT'), 'outputUnit' => '%', 'mode' => null, ], [ 'label' => 'Mill 3', 'stage' => '3', 'level' => value_num($value, 'MIL3LVL'), 'setpoint' => value_num($value, 'MILL3SP'), 'setpointUnit' => '%', 'rpm' => value_num($value, 'EMILL3RPM'), 'outputLabel' => 'MCC Tons', 'outputValue' => value_num($rounded1, 'MCCTONS'), 'outputUnit' => 'tons', 'mode' => null, ], [ 'label' => 'Mill 4', 'stage' => '4', 'level' => value_num($value, 'MIL4LVL'), 'setpoint' => value_num($value, 'MILL4SP'), 'setpointUnit' => '%', 'rpm' => value_num($value, 'EMILL4RPM'), 'outputLabel' => 'Mill 1 SP', 'outputValue' => value_num($value, 'WEIGHT_WSP'), 'outputUnit' => $millFourUnit, 'mode' => build_status(value_as_int($value, 'MILL1AUTOMAN1'), false), ], [ 'label' => 'Mill 5', 'stage' => '5', 'level' => value_num($value, 'MIL5LVL'), 'setpoint' => value_num($value, 'MILL5SP'), 'setpointUnit' => '%', 'rpm' => value_num($value, 'EMILL5RPM'), 'outputLabel' => 'Grinding Rate', 'outputValue' => value_num($value, 'TONS_PER_HOUR'), 'outputUnit' => 'tons/hr', 'mode' => null, ], [ 'label' => 'Mill 6', 'stage' => '6', 'level' => value_num($value, 'MIL6LVL'), 'setpoint' => value_num($value, 'MILL6SP'), 'setpointUnit' => '%', 'rpm' => value_num($value, 'EMILL6RPM'), 'outputLabel' => 'Average Rate', 'outputValue' => value_num($value, 'AVG_TONS_PER_HOUR'), 'outputUnit' => 'tons/15 min', 'mode' => null, ], ]; $eastFooterMetrics = [ ['label' => 'Imbibition 6 Flow', 'value' => format_with_unit(value_num($value, 'IMBFLOW'), 'gpm')], ['label' => 'Imbibition 6 SP', 'value' => format_with_unit(value_num($value, 'IMBSP'), 'gpm')], ['label' => 'Imbibition 5 Flow', 'value' => format_with_unit(value_num($value, 'IMBFLOW'), 'gpm')], ['label' => 'Imbibition 5 SP', 'value' => format_with_unit(value_num($value, 'IMB5SP'), 'gpm')], ]; $westStages = [ [ 'label' => 'Mill 1', 'stage' => '1', 'level' => value_num($ID, '00654'), 'setpoint' => null, 'setpointUnit' => '%', 'rpm' => value_num($ID, '00666'), 'outputLabel' => 'MCC FPM', 'outputValue' => value_num($value, 'Feet/Minute'), 'outputUnit' => 'fpm', 'mode' => null, ], [ 'label' => 'Mill 2', 'stage' => '2', 'level' => value_num($ID, '00656'), 'setpoint' => null, 'setpointUnit' => '%', 'rpm' => value_num($ID, '00670'), 'outputLabel' => 'MCC Output', 'outputValue' => value_num($ID, '00638'), 'outputUnit' => '%', 'mode' => null, ], [ 'label' => 'Mill 4', 'stage' => '4', 'level' => value_num($ID, '00658'), 'setpoint' => null, 'setpointUnit' => '%', 'rpm' => value_num($ID, '00674'), 'outputLabel' => 'Mill 1 SP', 'outputValue' => null, 'outputUnit' => '%', 'mode' => null, ], [ 'label' => 'Mill 5', 'stage' => '5', 'level' => value_num($ID, '00660'), 'setpoint' => null, 'setpointUnit' => '%', 'rpm' => value_num($ID, '00680'), 'outputLabel' => 'Grinding Rate', 'outputValue' => value_num($value, 'RATE'), 'outputUnit' => 'tons/hr', 'mode' => null, ], ]; $westFooterMetrics = [ ['label' => 'Imbibition Flow', 'value' => format_with_unit(value_num($ID, '00624'), 'gpm')], ['label' => 'Average Rate', 'value' => format_with_unit($westAvg, 'tons/15 min')], ]; $steamFlow = value_num($value, 'TTL_STEAMFLOW2'); $liveSteam = value_num($value, 'PT_001'); $exhaustPressure = value_num($ID, '00244'); $exhaustMode = build_status(value_as_int($value, 'ExhaustAM'), true); $vaporHeader = value_num($value, 'VAPOR HDR PRES'); $boilerOverview = [ [ 'label' => 'Total Steam Flow', 'value' => format_number($steamFlow), 'unit' => 'kpph', ], [ 'label' => 'Live Steam Pressure', 'value' => format_number($liveSteam), 'unit' => 'psi', 'status' => classify_live_steam($liveSteam), ], [ 'label' => 'Exhaust Pressure', 'value' => format_number($exhaustPressure), 'unit' => 'psi', 'status' => classify_exhaust($exhaustPressure), 'mode' => $exhaustMode, ], [ 'label' => 'Vapor Header Pressure', 'value' => format_number($vaporHeader), 'unit' => 'psi', ], ]; $boilerFlows = [ ['label' => 'Boiler 1', 'value' => format_number(value_num($ID, '00252'))], ['label' => 'Boiler 2', 'value' => format_number(value_num($ID, '00256'))], ['label' => 'Boiler 3', 'value' => format_number(value_num($value, 'FT_301'))], ['label' => 'Boiler 4', 'value' => format_number(value_num($value, 'FT_401'))], ['label' => 'Boiler 5', 'value' => format_number(value_num($value, 'FT_501'))], ['label' => 'Boiler 6', 'value' => format_number(value_num($value, 'FT_601'))], ['label' => 'Boiler 7', 'value' => format_number(value_num($ID, '00046'))], ['label' => 'Boiler 8', 'value' => format_number(value_num($ID, '00074'))], ]; $syrupOverflow = value_num($value, 'Syrup Overflow Lvl'); $syrupReceiver = value_num($value, 'Syrup RCVR'); $totalSyrup = null; if ($syrupOverflow !== null || $syrupReceiver !== null) { $totalSyrup = 0.0; if ($syrupOverflow !== null) { $totalSyrup += $syrupOverflow * 0.82569; } if ($syrupReceiver !== null) { $totalSyrup += $syrupReceiver * 0.17431; } } $tankLevels = [ ['label' => 'Juice Tank 1', 'value' => value_num($value, 'Juice Tank1')], ['label' => 'Juice Tank 2', 'value' => value_num($value, 'Juice Tank2')], ['label' => 'Syrup Receiver', 'value' => $syrupReceiver], ['label' => 'Syrup Overflow', 'value' => $syrupOverflow], ['label' => 'Total Syrup', 'value' => $totalSyrup], ['label' => 'Condensate Water', 'value' => value_num($value, 'CondensateWater')], ['label' => 'Sweet Water', 'value' => value_num($value, 'SweetwaterTank')], ['label' => 'Cold Water INJ', 'value' => value_num($value, 'Cold Water Injection LVL')], ['label' => 'A1 Receiver', 'value' => value_num($value, 'A1 RCVR')], ['label' => 'A1 Overflow', 'value' => value_num($value, 'A1 Molasses Overflow Lvl')], ['label' => 'A2 Receiver', 'value' => value_num($value, 'A2 RCVR')], ['label' => 'A2 Overflow', 'value' => value_num($value, 'A2 Molasses Overflow Lvl')], ['label' => 'B Receiver', 'value' => value_num($value, 'B RCVR')], ['label' => 'B Overflow', 'value' => value_num($value, 'B Molasses Overflow Lvl')], ['label' => 'Flash Tank', 'value' => value_num($value, 'FlashTankLVL')], ]; $truckDumpState = build_status(value_as_int($value, 'LATCHON'), true); $truckDumpMetrics = [ ['label' => 'PV', 'value' => format_number(value_num($valuesTwo, 'TD INPUT'), 1)], [ 'label' => 'Setpoint', 'value' => format_number( value_as_int($value, 'TD SP3 ON/OFF') === 1 ? value_num($valuesTwo, 'TD SP3') : value_num($valuesTwo, 'TD SP1'), 1 ), 'suffix' => value_as_int($value, 'TD SP3 ON/OFF') === 1 ? 'SP3' : 'SP', ], ['label' => 'Output', 'value' => format_with_unit(value_num($valuesTwo, 'TD OUTPUT'), '%', 1)], ['label' => 'Ratio', 'value' => format_number(value_num($valuesTwo, 'TD RATIO'), 2)], ['label' => 'Belt Scale', 'value' => format_with_unit(value_num($valuesTwo, 'TDBELTSCALE'), 'lbs', 0)], [ 'label' => 'Belt State', 'status' => build_switch(value_as_int($value, 'TDBELTSCALEONOFF'), 'Scale On', 'Scale Off'), ], [ 'label' => 'Mode', 'value' => value_as_int($value, 'TD MILLGROUND') === null ? '—' : ( value_as_int($value, 'TD MILLGROUND') === 0 ? 'Dump Mill' : 'Dump Ground' ), ], ]; $tables = [ [ 'label' => 'S Table', 'pv' => format_number(value_num($valuesTwo, 'SE SCALE'), 1), 'sp' => format_number( value_as_int($value, 'STABLE SP3 ON/OFF') === 1 ? value_num($valuesTwo, 'STABLE SP1') : value_num($valuesTwo, 'SE SETPOINT'), 1 ), 'spLabel' => value_as_int($value, 'STABLE SP3 ON/OFF') === 1 ? 'SP3' : 'SP', 'output' => format_with_unit(value_num($valuesTwo, 'SE OUTPUT'), '%', 1), 'mode' => build_status(value_as_int($value, 'SAM'), true), ], [ 'label' => 'NE Table', 'pv' => format_number(value_num($valuesTwo, 'NE SCALE'), 1), 'sp' => format_number( value_as_int($value, 'NE SP SWITCH') === 1 ? value_num($valuesTwo, 'NE SETPOINT2') : value_num($valuesTwo, 'NE SETPOINT'), 1 ), 'spLabel' => value_as_int($value, 'NE SP SWITCH') === 1 ? 'SP3' : 'SP', 'output' => format_with_unit(value_num($valuesTwo, 'NE OUTPUT'), '%', 1), 'mode' => build_status(value_as_int($value, 'NAM'), true), ], [ 'label' => 'W Table', 'pv' => format_number(value_num($valuesTwo, 'W SCALE'), 1), 'sp' => format_number( value_as_int($value, 'W SP SWITCH') === 1 ? value_num($valuesTwo, 'W SETPOINT2') : value_num($valuesTwo, 'W SETPOINT'), 1 ), 'spLabel' => value_as_int($value, 'W SP SWITCH') === 1 ? 'SP3' : 'SP', 'output' => format_with_unit(value_num($valuesTwo, 'W OUTPUT'), '%', 1), 'mode' => build_status(value_as_int($value, 'WAM'), true), ], ]; $knives = [ [ 'label' => 'Knife 1', 'pressure' => format_with_unit(value_num($valuesTwo, 'KNF1PRES'), 'psi', 1), 'speed' => format_with_unit(value_num($valuesTwo, 'K1SPD'), 'rpm', 0), 'output' => format_with_unit(value_num($valuesTwo, 'KNIFE1OP'), '%', 1), 'mode' => value_as_int($value, 'KC1') === null ? null : ( value_as_int($value, 'KC1') === 1 ? ['label' => 'Control', 'class' => 'status-pill--ok'] : ['label' => 'Knife', 'class' => 'status-pill--warn'] ), ], [ 'label' => 'Knife 2', 'pressure' => format_with_unit(value_num($valuesTwo, 'KNF2PRES'), 'psi', 1), 'speed' => format_with_unit(value_num($valuesTwo, 'KNF2SPD'), 'rpm', 0), 'output' => format_with_unit(value_num($valuesTwo, 'KNIFE2OP'), '%', 1), 'mode' => value_as_int($value, 'KC2') === null ? null : ( value_as_int($value, 'KC2') === 1 ? ['label' => 'Control', 'class' => 'status-pill--ok'] : ['label' => 'Knife', 'class' => 'status-pill--warn'] ), ], [ 'label' => 'Knife 3', 'pressure' => format_with_unit(value_num($valuesTwo, 'KNF3PRES'), 'psi', 1), 'speed' => format_with_unit(value_num($valuesTwo, 'KNF3SPD'), 'rpm', 0), 'output' => format_with_unit(value_num($valuesTwo, 'KNIFE3OP'), '%', 1), 'mode' => value_as_int($value, 'KC3') === null ? null : ( value_as_int($value, 'KC3') === 1 ? ['label' => 'Control', 'class' => 'status-pill--ok'] : ['label' => 'Knife', 'class' => 'status-pill--warn'] ), ], ]; ?>
Crop Day Server time format('M j, Y g:i:s A')); ?>

Key Production Metrics

East Tandem

Level
Setpoint
RPM

West Tandem

Level
RPM

Boilers

kpph

Tank Levels

data-level="" >

Truck Dump & Tables

Truck Dump
PV
Setpoint
Output
Knife Train
Pressure
Speed
Output