0, 'GridPower' => 1, 'HouseMeterTick' => 2, 'HousePV' => 3, 'HouseTick' => 4, 'SOC' => 5, 'LArrayPV' => 6, 'RArrayPV' => 7, 'ArrayTick' => 8, 'GarageFeed' => 9, 'GarageTick' => 10, 'DCPercent' => 11, 'DCTick' => 12, 'Residual' => 13 ] ) {} public static function load(string $file): ?self { if (!file_exists($file)) return null; $f = fopen($file, 'r'); $row = fgetcsv($f); fclose($f); return $row ? new self($row, time()) : null; } public function getVal(string $key): string { return $this->data[$this->map[$key]] ?? 'N/A'; } public function checkStale(string $tickKey): bool { $val = (int)$this->getVal($tickKey); return ($this->serverTime - $val) > 20; } } $sys = PowerSystem::load('status.csv'); $errors = []; if (!$sys) { $errors[] = "CRITICAL: Cannot read status.csv file."; } else { // Audit all ticks $toCheck = ['HouseMeterTick', 'HouseTick', 'ArrayTick', 'GarageTick', 'DCTick']; foreach ($toCheck as $t) { if ($sys->checkStale($t)) $errors[] = "WARNING: $t is STALE (>20s)."; } } ?> Power Monitor v2.0

SYSTEM MONITOR

File Update Time: getVal('UpdateTime') ?? '---' ?>

SECTION GENERATION / STORAGE STATUS
GARAGE L: getVal('LArrayPV') ?>W | R: getVal('RArrayPV') ?>W
Battery SOC: getVal('SOC') ?>% (getVal('DCPercent') ?>%)
Array: getVal('ArrayTick') ?>
DC: getVal('DCTick') ?>
HOUSE PV: getVal('HousePV') ?>W | Residual: getVal('Residual') ?>W
Garage Feed: getVal('GarageFeed') ?>W
House: getVal('HouseTick') ?>
Feed: getVal('GarageTick') ?>
GRID Main Power: getVal('GridPower') ?>W Meter: getVal('HouseMeterTick') ?>
[ERROR_LOG]
", $errors); ?>