[ 'name' => 'Milling', 'description' => 'Mill grinding operations - East and West', 'sections' => [ 'production' => [ 'name' => 'Production Totals', 'tags' => [ 'CANETOT' => ['label' => 'East Tons Ground', 'unit' => 'Tons'], 'W TONS GROUND' => ['label' => 'West Tons Ground', 'unit' => 'Tons'], 'TotalGround' => ['label' => 'Combined Total', 'unit' => 'Tons'], ], ], 'rates' => [ 'name' => 'Grinding Rates', 'tags' => [ 'RATE' => ['label' => 'West Tons/Hr', 'unit' => 'Tons/Hr'], 'MAINSPD' => ['label' => 'East MCC Speed', 'unit' => 'FPM'], 'Feet/Minute' => ['label' => 'West BC-09 Speed', 'unit' => 'FPM'], ], ], 'tanks' => [ 'name' => 'Tank Levels', 'tags' => [ 'Juice Tank1' => ['label' => 'Juice Tank 1', 'unit' => '%'], 'Juice Tank2' => ['label' => 'Juice Tank 2', 'unit' => '%'], 'Syrup Overflow Lvl' => ['label' => 'Syrup Overflow', 'unit' => '%'], 'Syrup RCVR' => ['label' => 'Syrup Receiver', 'unit' => '%'], ], ], 'steam' => [ 'name' => 'Steam', 'tags' => [ 'PT_001' => ['label' => 'Live Steam Pressure', 'unit' => 'PSI'], ], ], 'imbibition' => [ 'name' => 'Imbibition', 'tags' => [ 'IMB5Flow' => ['label' => 'IMB 5 Flow', 'unit' => 'GPM'], 'IMB6Flow' => ['label' => 'IMB 6 Flow', 'unit' => 'GPM'], 'WMillIMBFlow' => ['label' => 'West IMB Flow', 'unit' => 'GPM'], ], ], 'runtime' => [ 'name' => 'Run Time', 'tags' => [ 'RUNHRSTODAY' => ['label' => 'East Run Hours', 'unit' => 'Hours'], 'todayrun' => ['label' => 'West Run Hours', 'unit' => 'Hours'], 'LOSSTIME' => ['label' => 'East Loss Time', 'unit' => 'Hours'], 'todayloss' => ['label' => 'West Loss Time', 'unit' => 'Hours'], ], ], ], ], 'boilers' => [ 'name' => 'Boilers', 'description' => 'Boiler operations and steam generation', 'sections' => [ 'steam_totals' => [ 'name' => 'Steam Totals', 'tags' => [ 'B1TotSteam' => ['label' => 'Boiler 1 Steam', 'unit' => 'PPH'], 'B2TotSteam' => ['label' => 'Boiler 2 Steam', 'unit' => 'PPH'], 'B3TotSteam' => ['label' => 'Boiler 3 Steam', 'unit' => 'PPH'], 'B4TotSteam' => ['label' => 'Boiler 4 Steam', 'unit' => 'PPH'], ], ], 'pressures' => [ 'name' => 'Pressures', 'tags' => [ 'HouseAirPressure' => ['label' => 'House Air', 'unit' => 'PSI'], ], ], ], ], 'fabrication' => [ 'name' => 'Fabrication', 'description' => 'Sugar fabrication and dryers', 'sections' => [ 'tanks' => [ 'name' => 'Tank Levels', 'tags' => [ 'BBTankLvl' => ['label' => 'Broadbent Tank', 'unit' => '%'], 'ACVPMassecuiteLVL' => ['label' => 'A CVP Massecuite', 'unit' => '%'], ], ], 'dryers' => [ 'name' => 'Dryers', 'tags' => [ 'A1Running' => ['label' => 'Dryer A1', 'unit' => 'On/Off'], 'A2Running' => ['label' => 'Dryer A2', 'unit' => 'On/Off'], 'A3Running' => ['label' => 'Dryer A3', 'unit' => 'On/Off'], 'A4Running' => ['label' => 'Dryer A4', 'unit' => 'On/Off'], 'A5Running' => ['label' => 'Dryer A5', 'unit' => 'On/Off'], 'A6Running' => ['label' => 'Dryer A6', 'unit' => 'On/Off'], 'A7Running' => ['label' => 'Dryer A7', 'unit' => 'On/Off'], ], ], ], ], ]; /** * Get database connection */ function getReportDbConnection(): ?PDO { static $pdo = null; if ($pdo === null) { try { $pdo = new PDO( "sqlsrv:Server=" . REPORT_DB_SERVER . ";Database=" . REPORT_DB_NAME, REPORT_DB_USER, REPORT_DB_PASS, [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC ] ); } catch (PDOException $e) { error_log('Report DB connection failed: ' . $e->getMessage()); return null; } } return $pdo; } /** * Get tag ID from name (cached) */ function getTagId(PDO $pdo, string $tagName): ?string { static $cache = []; if (isset($cache[$tagName])) { return $cache[$tagName]; } $stmt = $pdo->prepare("SELECT idnumber FROM dbo.id_names WHERE name = ?"); $stmt->execute([$tagName]); $row = $stmt->fetch(); $cache[$tagName] = $row ? $row['idnumber'] : null; return $cache[$tagName]; }