add all files

This commit is contained in:
Rucus
2026-02-17 09:29:34 -06:00
parent b8c8d67c67
commit 782d203799
21925 changed files with 2433086 additions and 0 deletions

View File

@@ -0,0 +1,17 @@
<?php
include("../dbinfo3.php");
$con=mysqli_connect($host,$username,$password,$database);
$query = "SELECT Value FROM items where ID = '0000524'";
$result=mysqli_query($con,$query);
$include1=mysqli_fetch_array($result,MYSQLI_ASSOC);
mysqli_close($con);
?>
<?php
$rawValue = isset($include1['Value']) ? (float) $include1['Value'] : 0.0;
echo round($rawValue / 10, 2);
?>

View File

@@ -0,0 +1,17 @@
<?php
include("../dbinfo3.php");
$con=mysqli_connect($host,$username,$password,$database);
$query = "SELECT Value FROM items where ID = '0000542'";
$result=mysqli_query($con,$query);
$include1=mysqli_fetch_array($result,MYSQLI_ASSOC);
mysqli_close($con);
?>
<?php
$rawValue = isset($include1['Value']) ? (float) $include1['Value'] : 0.0;
echo round($rawValue, 2);
?>

View File

@@ -0,0 +1,17 @@
<?php
include("../dbinfo3.php");
$con=mysqli_connect($host,$username,$password,$database);
$query = "SELECT Value FROM items where ID = '0000522'";
$result=mysqli_query($con,$query);
$include1=mysqli_fetch_array($result,MYSQLI_ASSOC);
mysqli_close($con);
?>
<?php
$rawValue = isset($include1['Value']) ? (float) $include1['Value'] : 0.0;
echo round($rawValue / 10, 2);
?>

View File

@@ -0,0 +1,309 @@
<?php
/**
* System-wide alerts include
*
* Include this file in data pages to display conditional alerts.
* Expects $value array to be populated from items.php or shared endpoint.
*
* Usage: require __DIR__ . '/../includes/alerts.php';
*/
$alerts = [];
// ============================================================================
// Database Connection for Alerts (singleton)
// ============================================================================
function getAlertConnection() {
static $connection = null;
if ($connection === null) {
$connection = mysqli_connect('192.168.0.16', 'lasucaai', 'is413#dfslw', 'controls');
if ($connection) {
mysqli_set_charset($connection, 'utf8mb4');
// Create tables if not exists
$createLogTable = "CREATE TABLE IF NOT EXISTS alert_log (
id INT AUTO_INCREMENT PRIMARY KEY,
alert_type VARCHAR(50) NOT NULL,
alert_tag VARCHAR(100) NOT NULL,
alert_value DECIMAL(18,4) NULL,
threshold_value DECIMAL(18,4) NULL,
alert_message VARCHAR(500) NOT NULL,
source_page VARCHAR(255) NULL,
logged_at DATETIME DEFAULT CURRENT_TIMESTAMP,
INDEX idx_alert_type (alert_type),
INDEX idx_alert_tag (alert_tag),
INDEX idx_logged_at (logged_at)
)";
mysqli_query($connection, $createLogTable);
// Create throttle table to track last log time per alert
$createThrottleTable = "CREATE TABLE IF NOT EXISTS alert_throttle (
alert_key VARCHAR(150) PRIMARY KEY,
last_logged DATETIME NOT NULL,
INDEX idx_last_logged (last_logged)
)";
mysqli_query($connection, $createThrottleTable);
// Create condition state table to track duration
$createStateTable = "CREATE TABLE IF NOT EXISTS alert_condition_state (
alert_key VARCHAR(150) PRIMARY KEY,
condition_started DATETIME NOT NULL,
last_seen DATETIME NOT NULL,
INDEX idx_last_seen (last_seen)
)";
mysqli_query($connection, $createStateTable);
}
}
return $connection;
}
// ============================================================================
// Check if condition has persisted for required duration (in seconds)
// Returns true if condition has been active for >= duration seconds
// ============================================================================
function checkAlertDuration($alertKey, $conditionMet, $durationSeconds = 0) {
if ($durationSeconds <= 0) {
// No duration requirement - trigger immediately
return $conditionMet;
}
$conn = getAlertConnection();
if (!$conn) {
return $conditionMet; // Fallback to immediate if no DB
}
$now = date('Y-m-d H:i:s');
if ($conditionMet) {
// Condition is currently true - check/update state
$stmt = mysqli_prepare($conn,
"SELECT condition_started FROM alert_condition_state WHERE alert_key = ?"
);
if ($stmt) {
mysqli_stmt_bind_param($stmt, 's', $alertKey);
mysqli_stmt_execute($stmt);
$result = mysqli_stmt_get_result($stmt);
$row = mysqli_fetch_assoc($result);
mysqli_stmt_close($stmt);
if ($row) {
// Condition already being tracked - update last_seen
$updateStmt = mysqli_prepare($conn,
"UPDATE alert_condition_state SET last_seen = ? WHERE alert_key = ?"
);
if ($updateStmt) {
mysqli_stmt_bind_param($updateStmt, 'ss', $now, $alertKey);
mysqli_stmt_execute($updateStmt);
mysqli_stmt_close($updateStmt);
}
// Check if duration has been met
$started = strtotime($row['condition_started']);
$elapsed = time() - $started;
return $elapsed >= $durationSeconds;
} else {
// First time seeing this condition - start tracking
$insertStmt = mysqli_prepare($conn,
"INSERT INTO alert_condition_state (alert_key, condition_started, last_seen)
VALUES (?, ?, ?)"
);
if ($insertStmt) {
mysqli_stmt_bind_param($insertStmt, 'sss', $alertKey, $now, $now);
mysqli_stmt_execute($insertStmt);
mysqli_stmt_close($insertStmt);
}
return false; // Just started, duration not met yet
}
}
} else {
// Condition is false - clear the tracking state
$deleteStmt = mysqli_prepare($conn,
"DELETE FROM alert_condition_state WHERE alert_key = ?"
);
if ($deleteStmt) {
mysqli_stmt_bind_param($deleteStmt, 's', $alertKey);
mysqli_stmt_execute($deleteStmt);
mysqli_stmt_close($deleteStmt);
}
return false;
}
return $conditionMet;
}
// ============================================================================
// Alert Logging Function (throttled to once per minute per alert)
// ============================================================================
function logAlert($alertType, $alertTag, $alertValue, $alertMessage, $threshold = null) {
$conn = getAlertConnection();
if (!$conn) {
return;
}
try {
// Check throttle - only log once per minute per alert type+tag
$alertKey = $alertType . ':' . $alertTag;
$throttleCheck = mysqli_prepare($conn,
"SELECT last_logged FROM alert_throttle
WHERE alert_key = ? AND last_logged > DATE_SUB(NOW(), INTERVAL 1 MINUTE)"
);
if ($throttleCheck) {
mysqli_stmt_bind_param($throttleCheck, 's', $alertKey);
mysqli_stmt_execute($throttleCheck);
$result = mysqli_stmt_get_result($throttleCheck);
$recentLog = mysqli_fetch_assoc($result);
mysqli_stmt_close($throttleCheck);
if ($recentLog) {
return; // Skip - already logged within last minute
}
}
// Log the alert
$sourcePage = $_SERVER['PHP_SELF'] ?? 'unknown';
$stmt = mysqli_prepare($conn,
"INSERT INTO alert_log (alert_type, alert_tag, alert_value, threshold_value, alert_message, source_page)
VALUES (?, ?, ?, ?, ?, ?)"
);
if ($stmt) {
mysqli_stmt_bind_param($stmt, 'ssddss',
$alertType,
$alertTag,
$alertValue,
$threshold,
$alertMessage,
$sourcePage
);
mysqli_stmt_execute($stmt);
mysqli_stmt_close($stmt);
// Update throttle timestamp
$throttleUpdate = mysqli_prepare($conn,
"INSERT INTO alert_throttle (alert_key, last_logged) VALUES (?, NOW())
ON DUPLICATE KEY UPDATE last_logged = NOW()"
);
if ($throttleUpdate) {
mysqli_stmt_bind_param($throttleUpdate, 's', $alertKey);
mysqli_stmt_execute($throttleUpdate);
mysqli_stmt_close($throttleUpdate);
}
}
} catch (Exception $e) {
// Silent fail - logging should never break the page
error_log('Alert logging failed: ' . $e->getMessage());
}
}
// ============================================================================
// Alert Definitions (Now managed via alerts-admin.php)
// ============================================================================
// All alerts are now loaded from the alert_definitions table below.
// Use the admin panel at /alerts-admin.php to add, edit, or disable alerts.
// ============================================================================
// Database-Driven Alerts (from alerts-admin.php)
// ============================================================================
$alertConn = getAlertConnection();
if ($alertConn) {
$defResult = mysqli_query($alertConn,
"SELECT * FROM alert_definitions WHERE is_active = 1"
);
if ($defResult) {
while ($def = mysqli_fetch_assoc($defResult)) {
$tagName = $def['tag_name'];
$tagValue = $value[$tagName] ?? null;
if ($tagValue === null) {
continue; // Tag not found in current data
}
// Evaluate condition based on comparison operator
$conditionMet = false;
$threshold = floatval($def['threshold_value']);
switch ($def['comparison']) {
case '<':
$conditionMet = ($tagValue < $threshold);
break;
case '<=':
$conditionMet = ($tagValue <= $threshold);
break;
case '>':
$conditionMet = ($tagValue > $threshold);
break;
case '>=':
$conditionMet = ($tagValue >= $threshold);
break;
case '=':
$conditionMet = ($tagValue == $threshold);
break;
case '!=':
$conditionMet = ($tagValue != $threshold);
break;
}
// Check duration requirement
$alertKey = 'db_' . $def['id'] . '_' . $tagName;
$durationMet = checkAlertDuration($alertKey, $conditionMet, intval($def['duration_seconds']));
if ($durationMet) {
// Build message from template
$alertMessage = str_replace(
['{value}', '{threshold}', '{tag}'],
[$tagValue, $threshold, $tagName],
$def['message_template']
);
$alerts[] = [
'type' => $def['alert_type'],
'icon' => $def['icon'],
'tag' => $tagName,
'value' => $tagValue,
'threshold' => $threshold,
'display' => $def['display_alert'],
'message' => htmlspecialchars($alertMessage, ENT_QUOTES, 'UTF-8')
];
logAlert($def['alert_type'], $tagName, $tagValue, $alertMessage, $threshold);
}
}
}
}
// ============================================================================
// Render Alerts (info alerts are logged only, not displayed)
// ============================================================================
if (!empty($alerts)) {
foreach ($alerts as $alert) {
// Skip info alerts - they are logged but not displayed
if ($alert['type'] === 'info') {
continue;
}
// Skip alerts with display=0 (database-driven alerts can disable display)
if (isset($alert['display']) && !$alert['display']) {
continue;
}
$bgColor = '#c62828'; // danger (red)
if ($alert['type'] === 'warning') {
$bgColor = '#f57c00'; // warning (orange)
}
echo '<tr>';
echo '<td colspan="4" style="background: ' . $bgColor . '; color: white; text-align: center; font-weight: bold; padding: 10px;">';
echo $alert['icon'] . ' ' . $alert['message'];
echo '</td>';
echo '</tr>';
}
}

View File

@@ -0,0 +1,34 @@
<?php
/**
* Fetch both apron FPM values in a single database connection.
*
* Populates:
* $etdApronFPM - East Truck Dump Apron FPM (ID 0000524)
* $wtdApronFPM - West Truck Dump Apron FPM (ID 0000522)
*/
include __DIR__ . '/../dbinfo3.php';
$con = mysqli_connect($host, $username, $password, $database);
$etdApronFPM = 0;
$wtdApronFPM = 0;
if ($con) {
// Fetch both values in one query
$query = "SELECT ID, Value FROM items WHERE ID IN ('0000522', '0000524')";
$result = mysqli_query($con, $query);
if ($result) {
while ($row = mysqli_fetch_assoc($result)) {
$rawValue = (float) $row['Value'];
if ($row['ID'] === '0000524') {
$etdApronFPM = round($rawValue / 10, 2);
} elseif ($row['ID'] === '0000522') {
$wtdApronFPM = round($rawValue / 10, 2);
}
}
}
mysqli_close($con);
}

View File

@@ -0,0 +1,42 @@
<?php // phpcs:ignoreFile
/**
* Create a PDO connection to the archive SQL Server instance that hosts dbo.id_names.
*
* @throws \RuntimeException When the required PDO sqlsrv driver is unavailable.
*/
function archive_db_connect(): \PDO
{
if (!class_exists(\PDO::class)) {
throw new \RuntimeException('PDO is required to connect to the archive database.');
}
if (!in_array('sqlsrv', \PDO::getAvailableDrivers(), true)) {
throw new \RuntimeException('The sqlsrv PDO driver is not available. Enable it to query the archive database.');
}
static $cachedConnection = null;
if ($cachedConnection instanceof \PDO) {
return $cachedConnection;
}
$server = getenv('ARCHIVE_DB_SERVER') ?: '192.168.0.13\SQLEXPRESS';
$database = getenv('ARCHIVE_DB_NAME') ?: 'history';
$username = getenv('ARCHIVE_DB_USER') ?: 'opce';
$password = getenv('ARCHIVE_DB_PASSWORD') ?: 'opcelasuca';
$dsn = sprintf('sqlsrv:Server=%s;Database=%s;LoginTimeout=5', $server, $database);
$cachedConnection = new \PDO(
$dsn,
$username,
$password,
[
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
\PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC,
]
);
return $cachedConnection;
}

View File

@@ -0,0 +1,71 @@
<?php
$username="corey";
$password="41945549";
$database="controls";
mysql_connect('127.0.0.1',$username,$password);
@mysql_select_db($database) or die( "Unable to select database");
$query = "SELECT * FROM boilerstm24hravg WHERE TIME(time) = '04:59:59' ORDER BY id DESC";
$result=mysql_query($query);
$num=mysql_numrows($result);
mysql_close();
?>
<table width="100%" border="1" cellspacing="0" cellpadding="4">
<tr>
<td colspan="13" id="title">Boilers Total Steam Flow 24 Hour Average</td>
</tr>
<tr>
<td width="14%" id="title" colspan="2" bgcolor="#FFFFFF" align="center" width="16.6%"><font color="#000000">Date</font></td>
<td width="13.2%" id="title" colspan="2" bgcolor="#FFFFFF" align="center" width="16.6%"><font color="#000000">Boiler 1</font></td>
<td width="13.2%" id="title" colspan="2" bgcolor="#FFFFFF" align="center" width="16.6%"><font color="#000000">Boiler 2</font></td>
<td width="13.2%" id="title" colspan="2" bgcolor="#FFFFFF" align="center" width="16.6%"><font color="#000000">Boiler 3</font></td>
<td width="13.2%" id="title" colspan="2" bgcolor="#FFFFFF" align="center" width="16.6%"><font color="#000000">Boiler 4</font></td>
<td width="13.2%" id="title" colspan="2" bgcolor="#FFFFFF" align="center" width="16.6%"><font color="#000000">Boiler 5</font></td>
<td width="13.2%" id="title" colspan="2" bgcolor="#FFFFFF" align="center" width="16.6%"><font color="#000000">Boiler 6</font></td>
</tr>
</table>
<?php
$i=0;
while ($i < $num) {
$f1=mysql_result($result,$i,"BLR1TOTSF");
$f2=mysql_result($result,$i,"BLR2TOTSF");
$f3=mysql_result($result,$i,"BLR3TOTSF");
$f4=mysql_result($result,$i,"BLR4TOTSF");
$f5=mysql_result($result,$i,"BLR5TOTSF");
$f6=mysql_result($result,$i,"BLR6TOTSF");
$f7=mysql_result($result,$i,"TIME");
?>
<div id="stories">
<table width="100%" border="1" cellspacing="0" cellpadding="4">
<tr>
<td width="14%" id="vtitle" bgcolor="#FFFFFF" align="left"><font color="#000000" ><?php echo $f7; ?></font></td>
<td width="6.6%" id="vtitle" bgcolor="#FFFFFF" align="left"><font color="#000000"><?php echo $f1; ?></font></td>
<td width="6.6%" id="vtitle" bgcolor="#FFFFFF" align="right"><font color="#000000">KPPH</font></td>
<td width="6.6%" id="vtitle" bgcolor="#FFFFFF" align="left"><font color="#000000"><?php echo $f2; ?></font></td>
<td width="6.6%" id="vtitle" bgcolor="#FFFFFF" align="right"><font color="#000000">KPPH</font></td>
<td width="6.6%" id="vtitle" bgcolor="#FFFFFF" align="left"><font color="#000000"><?php echo $f3; ?></font></td>
<td width="6.6%" id="vtitle" bgcolor="#FFFFFF" align="right"><font color="#000000">KPPH</font></td>
<td width="6.6%" id="vtitle" bgcolor="#FFFFFF" align="left"><font color="#000000"><?php echo $f4; ?></font></td>
<td width="6.6%" id="vtitle" bgcolor="#FFFFFF" align="right"><font color="#000000">KPPH</font></td>
<td width="6.6%" id="vtitle" bgcolor="#FFFFFF" align="left"><font color="#000000"><?php echo $f5; ?></font></td>
<td width="6.6%" id="vtitle" bgcolor="#FFFFFF" align="right"><font color="#000000">KPPH</font></td>
<td width="6.6%" id="vtitle" bgcolor="#FFFFFF" align="left"><font color="#000000"><?php echo $f6; ?></font></td>
<td width="6.6%" id="vtitle" bgcolor="#FFFFFF" align="right"><font color="#000000">KPPH</font></td>
</tr>
</div>
<?php
$i++;
}
?>

View File

@@ -0,0 +1,172 @@
<?php // phpcs:ignoreFile
declare(strict_types=1);
require_once __DIR__ . '/db.php';
if (!function_exists('control_log_write')) {
/**
* Persist a control write audit entry into the configured log store.
*
* @param array<string, mixed> $entry
*
* @return array{success:bool, driver:?string, error:?string, path:?string}
*/
function control_log_write(array $entry): array
{
static $tableName;
static $fallbackPath;
/** @var array<string, array<int, string>> $columnsCache */
static $columnsCache = [];
$result = [
'success' => false,
'driver' => null,
'error' => null,
'path' => null,
];
$settings = include __DIR__ . '/../config/control-settings.php';
if ($tableName === null) {
$configuredTable = $settings['log_table'] ?? null;
if (!is_string($configuredTable) || trim($configuredTable) === '') {
$result['error'] = 'Control log table name is not configured.';
error_log('Control write log insert failed: ' . $result['error']);
return $result;
}
$tableName = trim($configuredTable);
}
if ($fallbackPath === null) {
$configuredFallback = $settings['log_fallback_path'] ?? '';
if (is_string($configuredFallback) && trim($configuredFallback) !== '') {
$fallbackPath = $configuredFallback;
} else {
$fallbackPath = '';
}
}
try {
$connection = controls_db_connect();
$tableKey = $tableName;
if (!isset($columnsCache[$tableKey])) {
$tableEscaped = $connection->real_escape_string($tableName);
$columnsResult = $connection->query('SHOW COLUMNS FROM `' . $tableEscaped . '`');
if ($columnsResult === false) {
throw new RuntimeException('Unable to determine columns for control write log table.');
}
$columns = [];
while ($column = $columnsResult->fetch_assoc()) {
if (isset($column['Field'])) {
$columns[] = $column['Field'];
}
}
$columnsResult->free();
$columnsCache[$tableKey] = $columns;
}
$availableColumns = $columnsCache[$tableKey] ?? [];
if ($availableColumns === []) {
throw new RuntimeException('No columns available on control write log table.');
}
$insertData = [];
foreach ($entry as $column => $value) {
if (in_array($column, $availableColumns, true)) {
$insertData[$column] = $value;
}
}
if ($insertData === []) {
$result['error'] = 'None of the provided fields matched the log table columns.';
error_log('Control write log insert skipped: ' . $result['error']);
} else {
$fields = [];
$values = [];
foreach ($insertData as $column => $value) {
$fields[] = '`' . $connection->real_escape_string($column) . '`';
if ($value === null) {
$values[] = 'NULL';
continue;
}
if (is_bool($value)) {
$values[] = $value ? "'1'" : "'0'";
continue;
}
$values[] = "'" . $connection->real_escape_string((string) $value) . "'";
}
$tableEscaped = $connection->real_escape_string($tableName);
$sql = sprintf(
'INSERT INTO `%s` (%s) VALUES (%s)',
$tableEscaped,
implode(', ', $fields),
implode(', ', $values)
);
$connection->query($sql);
$result['success'] = true;
$result['driver'] = 'database';
$result['error'] = null;
return $result;
}
} catch (Throwable $exception) {
$result['error'] = $exception->getMessage();
error_log('Control write log insert failed: ' . $exception->getMessage());
}
if ($fallbackPath === '') {
return $result;
}
try {
$directory = dirname($fallbackPath);
if ($directory !== '' && !is_dir($directory)) {
if (!mkdir($directory, 0775, true) && !is_dir($directory)) {
throw new RuntimeException('Unable to create fallback log directory: ' . $directory);
}
}
$record = [
'timestamp' => gmdate('c'),
'entry' => $entry,
'error' => $result['error'],
];
$json = json_encode($record, JSON_THROW_ON_ERROR);
file_put_contents($fallbackPath, $json . PHP_EOL, FILE_APPEND | LOCK_EX);
$result['success'] = true;
$result['driver'] = 'file';
$result['path'] = $fallbackPath;
error_log('Control write log stored in fallback file: ' . $fallbackPath);
} catch (Throwable $fallbackException) {
$result['driver'] = 'none';
$result['path'] = null;
$fallbackMessage = $fallbackException->getMessage();
if ($result['error'] !== null) {
$result['error'] .= '; ' . $fallbackMessage;
} else {
$result['error'] = $fallbackMessage;
}
error_log('Control write log fallback failed: ' . $fallbackMessage);
}
return $result;
}
}

View File

@@ -0,0 +1,200 @@
<?php // phpcs:ignoreFile
declare(strict_types=1);
if (!function_exists('control_tags_raw')) {
/**
* Load the raw tag configuration array from config/control-tags.php.
*
* @return array<string, mixed>
*/
function control_tags_raw(): array
{
static $cache;
if ($cache !== null) {
return $cache;
}
$configPath = __DIR__ . '/../config/control-tags.php';
if (!file_exists($configPath)) {
throw new RuntimeException('Tag configuration file not found at config/control-tags.php');
}
$data = include $configPath;
if (!is_array($data)) {
throw new RuntimeException('Tag configuration file must return an array.');
}
$cache = $data;
return $cache;
}
}
if (!function_exists('control_tag_resolve_mode')) {
/**
* Resolve the control mode (numeric or boolean) for a tag configuration entry.
*
* @param array<string, mixed> $meta
*/
function control_tag_resolve_mode(array $meta): string
{
$modeHint = $meta['mode'] ?? $meta['control_mode'] ?? null;
if (is_string($modeHint)) {
$normalized = strtolower(trim($modeHint));
if (in_array($normalized, ['boolean', 'bool', 'toggle', 'switch', 'binary', 'onoff'], true)) {
return 'boolean';
}
if (in_array($normalized, ['numeric', 'number', 'float', 'analog'], true)) {
return 'numeric';
}
}
$typeHint = $meta['type'] ?? $meta['type_hint'] ?? null;
if (is_string($typeHint)) {
$compact = preg_replace('/[^a-z0-9]+/', '', strtolower($typeHint)) ?? '';
foreach (['bool', 'boolean', 'binary', 'switch', 'toggle', 'onoff', 'startstop', 'runstop'] as $token) {
if ($token !== '' && strpos($compact, $token) !== false) {
return 'boolean';
}
}
}
return 'numeric';
}
}
if (!function_exists('control_tags_normalize')) {
/**
* Normalise and enrich the configured tags for convenient consumption.
*
* @return array<string, array<string, mixed>>
*/
function control_tags_normalize(): array
{
$raw = control_tags_raw();
$normalised = [];
foreach ($raw as $rawId => $meta) {
if (is_string($meta)) {
$meta = ['name' => $meta];
} elseif (!is_array($meta)) {
continue;
}
if (array_key_exists('enabled', $meta) && !$meta['enabled']) {
continue;
}
$candidateId = is_string($rawId) && $rawId !== '' ? $rawId : (
is_string($meta['id'] ?? null) ? $meta['id'] : (
is_string($meta['tag'] ?? null) ? $meta['tag'] : null
)
);
if (!is_string($candidateId) || trim($candidateId) === '') {
continue;
}
$tagId = trim($candidateId);
$name = isset($meta['name']) && is_string($meta['name']) && trim($meta['name']) !== ''
? trim($meta['name'])
: $tagId;
$typeLabel = isset($meta['type']) && is_string($meta['type']) && trim($meta['type']) !== ''
? trim($meta['type'])
: 'General';
$typeKey = strtolower(preg_replace('/[^a-z0-9]+/', '-', $typeLabel));
$typeKey = $typeKey !== '' ? $typeKey : 'general';
$mode = control_tag_resolve_mode($meta);
$step = isset($meta['step']) && is_numeric($meta['step']) ? (float) $meta['step'] : null;
$min = isset($meta['min']) && is_numeric($meta['min']) ? (float) $meta['min'] : null;
$max = isset($meta['max']) && is_numeric($meta['max']) ? (float) $meta['max'] : null;
$precision = null;
if (isset($meta['precision']) && is_numeric($meta['precision'])) {
$precision = (int) $meta['precision'];
} elseif (isset($meta['decimals']) && is_numeric($meta['decimals'])) {
$precision = (int) $meta['decimals'];
}
$normalised[$tagId] = [
'id' => $tagId,
'name' => $name,
'type_label' => $typeLabel,
'type_key' => $typeKey,
'control_mode' => $mode,
'control' => 1,
'config' => $meta,
'step' => $step,
'min' => $min,
'max' => $max,
'precision' => $precision,
'units' => isset($meta['units']) && is_string($meta['units']) ? trim($meta['units']) : null,
'description' => isset($meta['description']) && is_string($meta['description'])
? trim($meta['description'])
: null,
];
}
uasort(
$normalised,
static function (array $left, array $right): int {
$typeComparison = strcasecmp($left['type_label'], $right['type_label']);
if ($typeComparison !== 0) {
return $typeComparison;
}
return strcasecmp($left['name'], $right['name']);
}
);
return $normalised;
}
}
if (!function_exists('control_tag_find')) {
/**
* Retrieve a single normalised tag definition by its identifier.
*
* @return array<string, mixed>|null
*/
function control_tag_find(string $tagId): ?array
{
$tags = control_tags_normalize();
return $tags[$tagId] ?? null;
}
}
if (!function_exists('control_format_timestamp')) {
/**
* Format an ISO-8601 timestamp for display.
*/
function control_format_timestamp(?string $timestamp): ?string
{
if ($timestamp === null || $timestamp === '') {
return null;
}
try {
$date = new DateTimeImmutable($timestamp);
} catch (Throwable $exception) {
return $timestamp;
}
return $date->format('M j, Y g:i:s A');
}
}

View File

@@ -0,0 +1,29 @@
<?php
$serverName = "CBM2K12\SQLEXPRESS";
$uid = "cbmclient";
$pwd = "ascbm2k";
$connectionInfo = array( "UID"=>$uid, "PWD"=>$pwd,'ReturnDatesAsStrings'=> true, "CharacterSet" => 'utf-8', "Database"=>"SugarCaneScale" );
/* Connect using SQL Server Authentication. */
$conn = sqlsrv_connect( $serverName, $connectionInfo);
if( $conn === false )
{
echo "Unable to connect.</br>";
die( print_r( sqlsrv_errors(), true));
}
$sql = "SELECT CropDay FROM Parameters";
$stmt = sqlsrv_query( $conn, $sql );
if( $stmt === false) {
die( print_r( sqlsrv_errors(), true) );
}
while( $row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_ASSOC) ) {
echo $row['CropDay'];
}
sqlsrv_free_stmt( $stmt);
sqlsrv_close( $conn);
?>

View File

@@ -0,0 +1,33 @@
<?php
// phpcs:ignoreFile
require_once __DIR__ . '/../config.php';
/**
* Create and return a new mysqli connection using the shared configuration.
*
* @return mysqli
*/
function controls_db_connect()
{
if (!defined('DB_HOST') || !defined('DB_USER') || !defined('DB_PASSWORD') || !defined('DB_DATABASE')) {
$configPath = __DIR__ . '/../config.php';
if (file_exists($configPath)) {
require $configPath;
}
}
if (!defined('DB_HOST') || !defined('DB_USER') || !defined('DB_PASSWORD') || !defined('DB_DATABASE')) {
throw new RuntimeException('Database configuration constants are not defined.');
}
if (!function_exists('mysqli_report')) {
throw new RuntimeException('The mysqli extension is not available.');
}
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$connection = new mysqli(DB_HOST, DB_USER, DB_PASSWORD, DB_DATABASE);
$connection->set_charset('utf8mb4');
return $connection;
}

View File

@@ -0,0 +1,6 @@
<?php
$host="192.168.0.10";
$username="corey";
$password="41945549";
$database="controls";
?>

View File

@@ -0,0 +1,6 @@
<?php
$host="192.168.0.9";
$username="corey";
$password="41945549";
$database="controls";
?>

View File

@@ -0,0 +1,6 @@
<?php
$host="192.168.0.16";
$username="corey";
$password="41945549";
$database="controls";
?>

View File

@@ -0,0 +1,19 @@
<?php
include("../dbinfo.php");
$con=mysqli_connect($host,$username,$password,$database);
$query = "SELECT TIMEDIFF ((SELECT date FROM plc GROUP BY totnorth ORDER BY id DESC LIMIT 1),(SELECT date FROM plc GROUP BY totnorth ORDER BY id DESC LIMIT 1, 1)) AS time";
$result=mysqli_query($con,$query);
$include2=mysqli_fetch_array($result,MYSQLI_ASSOC);
mysqli_close($con);
?>
<table>
<tr>
<?php echo $include2['time']; ?>
</tr>
</table>

View File

@@ -0,0 +1,19 @@
<?php
include("../dbinfo.php");
$con=mysqli_connect($host,$username,$password,$database);
$query = "SELECT TIMEDIFF ((SELECT date FROM plc GROUP BY totsouth ORDER BY id DESC LIMIT 1),(SELECT date FROM plc GROUP BY totsouth ORDER BY id DESC LIMIT 1, 1)) AS time";
$result=mysqli_query($con,$query);
$include4=mysqli_fetch_array($result,MYSQLI_ASSOC);
mysqli_close($con);
?>
<table>
<tr>
<?php echo $include4['time']; ?>
</tr>
</table>

View File

@@ -0,0 +1,19 @@
<?php
include("../dbinfo.php");
$con=mysqli_connect($host,$username,$password,$database);
$query = "SELECT TIMEDIFF ((SELECT date FROM plc GROUP BY totwest2 ORDER BY id DESC LIMIT 1),(SELECT date FROM plc GROUP BY totwest2 ORDER BY id DESC LIMIT 1, 1)) AS time";
$result=mysqli_query($con,$query);
$include2=mysqli_fetch_array($result,MYSQLI_ASSOC);
mysqli_close($con);
?>
<table>
<tr>
<?php echo $include2['time']; ?>
</tr>
</table>

View File

@@ -0,0 +1,15 @@
<?php
include("../dbinfo.php");
$con=mysqli_connect($host,$username,$password,$database);
$query = "SELECT ((SELECT easttotground FROM easttotalground ORDER BY id DESC LIMIT 1) - (SELECT easttotground FROM easttotalground ORDER BY id DESC LIMIT 899, 1))*4 AS eastavg";
$result=mysqli_query($con,$query);
$include4=mysqli_fetch_array($result,MYSQLI_ASSOC);
mysqli_close($con);
?>
<?php echo round($include4['eastavg']); ?>

View File

@@ -0,0 +1,14 @@
<?php
include("../dbinfo.php");
$con=mysqli_connect($host,$username,$password,$database);
$query = "SELECT DISTINCT EastTotal FROM mill_ytd_totals ORDER BY ID DESC LIMIT 1";
$result=mysqli_query($con,$query);
$include1=mysqli_fetch_array($result,MYSQLI_ASSOC);
mysqli_close($con);
?>
<?php echo round($include1['EastTotal']); ?>

View File

@@ -0,0 +1,52 @@
<?php
require "itemsAI.php";
?>
<tr>
<td colspan="4" id="title">Shell & Heater Tubes</td>
</tr>
<tr>
<td id="vtitle" id="padded" colspan="1" width="30%"></a></td>
<td id="vtitle" id="padded">Temp:</a></td>
<td id="vtitle" id="padded">Setpoint:</a></td>
</tr>
<tr>
<td id="vtitle" id="padded" colspan="1" width="40%">Heater 1:</a></td>
<td id="sum-count"><?php echo $ID['0000344']; ?></td>
<td id="vtitle"><?php echo $value['TubeHeater1SP']; ?></td>
</tr>
<tr>
<td id="vtitle" id="padded" colspan="1">Heater 2:</a></td>
<td id="sum-count"><?php echo $rounded['TubeHeater2Temp']; ?></td>
<td id="vtitle"><?php echo $value['TubeHeater2SP']; ?></td>
</tr>
<tr>
<td id="vtitle" id="padded" colspan="1">Heater 3:</a></td>
<td id="sum-count"><?php echo $rounded['TubeHeater3Temp']; ?></td>
<td id="vtitle"><?php echo $value['TubeHeater3SP']; ?></td>
</tr>
<tr>
<td id="vtitle" id="padded" colspan="1">Heater 4:</a></td>
<td id="sum-count"><?php echo $rounded['TubeHeater4Temp']; ?></td>
<td id="vtitle"><?php echo $value['TubeHeater4SP']; ?></td>
</tr>
<tr>
<td id="vtitle" id="padded" colspan="1">Heater 5:</a></td>
<td id="sum-count"><?php echo $rounded['TubeHeater5Temp']; ?></td>
<td id="vtitle"><?php echo $value['TubeHeater5SP']; ?></td>
</tr>
<tr>
<td id="vtitle" id="padded" colspan="1">Heater 6:</a></td>
<td id="sum-count"><?php echo $rounded['TubeHeater6Temp']; ?></td>
<td id="vtitle"><?php echo $value['TubeHeater6SP']; ?></td>
</tr>
<tr>
<td id="vtitle" id="padded" colspan="1">Heater 7:</a></td>
<td id="sum-count"><?php echo $rounded['TubeHeater7Temp']; ?></td>
<td id="vtitle"><?php echo $value['TubeHeater7SP']; ?></td>
</tr>
<tr>
<td id="vtitle" id="padded">Heater 8:</a></td>
<td id="sum-count"><?php echo $rounded['TubeHeater8TempPV']; ?></td>
<td id="sum-count"><?php echo $value['TubeHeater8TempSP']; ?></td>
</tr>

View File

@@ -0,0 +1,17 @@
<?php
include("../dbinfo3.php");
$con=mysqli_connect($host,$username,$password,$database);
$query = "SELECT Value FROM items where ID = '0000638'";
$result=mysqli_query($con,$query);
$include1=mysqli_fetch_array($result,MYSQLI_ASSOC);
mysqli_close($con);
?>
<?php
$rawValue = isset($include1['Value']) ? (float) $include1['Value'] : 0.0;
echo round($rawValue, 2);
?>

View File

@@ -0,0 +1,17 @@
<?php
include("../dbinfo3.php");
$con=mysqli_connect($host,$username,$password,$database);
$query = "SELECT Value FROM items where ID = '0000636'";
$result=mysqli_query($con,$query);
$include1=mysqli_fetch_array($result,MYSQLI_ASSOC);
mysqli_close($con);
?>
<?php
$rawValue = isset($include1['Value']) ? (float) $include1['Value'] : 0.0;
echo round($rawValue, 2);
?>

View File

@@ -0,0 +1,17 @@
<?php
include("../dbinfo3.php");
$con=mysqli_connect($host,$username,$password,$database);
$query = "SELECT Value FROM items where ID = '0000634'";
$result=mysqli_query($con,$query);
$include1=mysqli_fetch_array($result,MYSQLI_ASSOC);
mysqli_close($con);
?>
<?php
$rawValue = isset($include1['Value']) ? (float) $include1['Value'] : 0.0;
echo round($rawValue, 2);
?>

View File

@@ -0,0 +1,17 @@
<?php
include("../dbinfo3.php");
$con=mysqli_connect($host,$username,$password,$database);
$query = "SELECT Value FROM items where ID = '0000632'";
$result=mysqli_query($con,$query);
$include1=mysqli_fetch_array($result,MYSQLI_ASSOC);
mysqli_close($con);
?>
<?php
$rawValue = isset($include1['Value']) ? (float) $include1['Value'] : 0.0;
echo round($rawValue, 2);
?>

View File

@@ -0,0 +1,17 @@
<?php
include("../dbinfo3.php");
$con=mysqli_connect($host,$username,$password,$database);
$query = "SELECT Value FROM items where ID = '0000630'";
$result=mysqli_query($con,$query);
$include1=mysqli_fetch_array($result,MYSQLI_ASSOC);
mysqli_close($con);
?>
<?php
$rawValue = isset($include1['Value']) ? (float) $include1['Value'] : 0.0;
echo round($rawValue, 2);
?>

View File

@@ -0,0 +1,17 @@
<?php
include("../dbinfo3.php");
$con=mysqli_connect($host,$username,$password,$database);
$query = "SELECT Value FROM items where ID = '0000628'";
$result=mysqli_query($con,$query);
$include1=mysqli_fetch_array($result,MYSQLI_ASSOC);
mysqli_close($con);
?>
<?php
$rawValue = isset($include1['Value']) ? (float) $include1['Value'] : 0.0;
echo round($rawValue, 2);
?>

View File

@@ -0,0 +1,17 @@
<?php
include("../dbinfo3.php");
$con=mysqli_connect($host,$username,$password,$database);
$query = "SELECT Value FROM items where ID = '0000626'";
$result=mysqli_query($con,$query);
$include1=mysqli_fetch_array($result,MYSQLI_ASSOC);
mysqli_close($con);
?>
<?php
$rawValue = isset($include1['Value']) ? (float) $include1['Value'] : 0.0;
echo round($rawValue, 2);
?>

View File

@@ -0,0 +1,17 @@
<?php
include("../dbinfo3.php");
$con=mysqli_connect($host,$username,$password,$database);
$query = "SELECT Value FROM items where ID = '0000624'";
$result=mysqli_query($con,$query);
$include1=mysqli_fetch_array($result,MYSQLI_ASSOC);
mysqli_close($con);
?>
<?php
$rawValue = isset($include1['Value']) ? (float) $include1['Value'] : 0.0;
echo round($rawValue, 2);
?>

View File

@@ -0,0 +1,17 @@
<?php
$con=mysqli_connect('192.168.0.10', 'corey', '41945549', 'controls');
$query="SELECT ID, Name, ROUND(Value, 0) AS Value, ROUND(Value, 1) AS RoundedValue1, ROUND(Value, 2) AS RoundedValue, Timestamp FROM items ORDER BY ID ASC";
$result=mysqli_query($con, $query);
mysqli_close($con);
while ($row=mysqli_fetch_array($result, MYSQLI_ASSOC)) {
$value[$row['Name']] = $row['Value'];
$rounded[$row['Name']] = $row['RoundedValue'];
$time[$row['Name']] = $row['Timestamp'];
$ID[$row['ID']] = $row['Value'];
$roundedid[$row['ID']] = $row['RoundedValue'];
$rounded1[$row['ID']] = $row['RoundedValue1'];
$rounded1[$row['Name']] = $row['RoundedValue1'];
}
?>

View File

@@ -0,0 +1,13 @@
<?php
$con=mysqli_connect('192.168.0.10', 'corey', '41945549', 'controls');
$query="SELECT ID, Name, ROUND(Value, 2) AS Value, Timestamp FROM items ORDER BY ID ASC";
$result=mysqli_query($con, $query);
mysqli_close($con);
while ($row=mysqli_fetch_array($result, MYSQLI_ASSOC)) {
$value[$row['Name']] = $row['Value'];
$time[$row['Name']] = $row['Timestamp'];
$ID[$row['ID']] = $row['Value'];
}
?>

View File

@@ -0,0 +1,17 @@
<?php
$con=mysqli_connect('192.168.0.16', 'corey', '41945549', 'controls');
$query="SELECT ID, Name, ROUND(Value, 0) AS Value, ROUND(Value, 1) AS RoundedValue1, ROUND(Value, 2) AS RoundedValue, Timestamp FROM items ORDER BY ID ASC";
$result=mysqli_query($con, $query);
mysqli_close($con);
while ($row=mysqli_fetch_array($result, MYSQLI_ASSOC)) {
$value[$row['Name']] = $row['Value'];
$rounded[$row['Name']] = $row['RoundedValue'];
$time[$row['Name']] = $row['Timestamp'];
$ID[$row['ID']] = $row['Value'];
$roundedid[$row['ID']] = $row['RoundedValue'];
$rounded1[$row['ID']] = $row['RoundedValue1'];
$rounded1[$row['Name']] = $row['RoundedValue1'];
}
?>

View File

@@ -0,0 +1,12 @@
<?php
$con=mysqli_connect('192.168.0.10', 'corey', '41945549', 'controls');
$query="SELECT ID, Name, ROUND(Value, 2) AS Value, Timestamp FROM items ORDER BY ID ASC";
$result=mysqli_query($con, $query);
while ($row=mysqli_fetch_array($result, MYSQLI_ASSOC)) {
$value[$row['Name']] = $row['Value'];
$time[$row['Name']] = $row['Timestamp'];
}
echo $value['FD Temp'];
echo $time['FD Temp'];
?>

View File

@@ -0,0 +1,238 @@
<?php // phpcs:ignoreFile
declare(strict_types=1);
require_once __DIR__ . '/../config/control-settings.php';
/**
* Procedural helper functions for talking to the Kepware IoT Gateway REST API.
*/
if (!function_exists('kepware_config')) {
/**
* Retrieve Kepware REST configuration values.
*
* @return array<string, mixed>
*/
function kepware_config(): array
{
static $config;
if ($config === null) {
$settings = include __DIR__ . '/../config/control-settings.php';
$config = $settings['kepware'] ?? [];
}
return $config;
}
}
if (!function_exists('kepware_rest_request')) {
/**
* Issue an HTTP request to the Kepware REST server.
*
* @param string $method HTTP verb (GET, POST, ...).
* @param string $path Relative REST path.
* @param array<string, mixed>|null $body Optional JSON payload.
*
* @return array<string, mixed>
*/
function kepware_rest_request(string $method, string $path, ?array $body = null): array
{
$config = kepware_config();
$baseUrl = rtrim((string) ($config['base_url'] ?? ''), '/');
if ($baseUrl === '') {
throw new RuntimeException('Kepware base URL is not configured.');
}
$url = $baseUrl . '/' . ltrim($path, '/');
$username = (string) ($config['username'] ?? '');
$password = (string) ($config['password'] ?? '');
$timeout = (float) ($config['timeout'] ?? 5.0);
$verify = (bool) ($config['verify_tls'] ?? false);
$attempts = (int) ($config['retry_attempts'] ?? 1);
if ($attempts < 1) {
$attempts = 1;
}
$retryDelay = (float) ($config['retry_delay'] ?? 0.0);
if ($retryDelay < 0) {
$retryDelay = 0.0;
}
$postFields = null;
if ($body !== null) {
$postFields = json_encode($body, JSON_THROW_ON_ERROR);
}
$options = [
CURLOPT_URL => $url,
CURLOPT_CUSTOMREQUEST => strtoupper($method),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_USERPWD => $username . ':' . $password,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Accept: application/json',
],
CURLOPT_TIMEOUT => $timeout,
CURLOPT_CONNECTTIMEOUT => $timeout,
CURLOPT_SSL_VERIFYPEER => $verify,
CURLOPT_SSL_VERIFYHOST => $verify ? 2 : 0,
];
if ($postFields !== null) {
$options[CURLOPT_POSTFIELDS] = $postFields;
}
$retryableCurlErrors = [
CURLE_COULDNT_CONNECT,
CURLE_COULDNT_RESOLVE_HOST,
CURLE_COULDNT_RESOLVE_PROXY,
CURLE_GOT_NOTHING,
CURLE_OPERATION_TIMEDOUT,
CURLE_PARTIAL_FILE,
CURLE_RECV_ERROR,
CURLE_SEND_ERROR,
CURLE_SSL_CONNECT_ERROR,
];
for ($attempt = 1; $attempt <= $attempts; $attempt++) {
$handle = curl_init();
if ($handle === false) {
throw new RuntimeException('Unable to initialise cURL for Kepware request.');
}
curl_setopt_array($handle, $options);
$response = curl_exec($handle);
$error = curl_error($handle);
$errno = curl_errno($handle);
$status = (int) curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);
if ($response === false) {
$shouldRetry = in_array($errno, $retryableCurlErrors, true) && $attempt < $attempts;
if ($shouldRetry) {
error_log(sprintf(
'Kepware request to %s attempt %d failed with cURL error %d: %s. Retrying in %.2f seconds.',
$path,
$attempt,
$errno,
$error,
$retryDelay
));
if ($retryDelay > 0.0) {
usleep((int) round($retryDelay * 1_000_000));
}
continue;
}
throw new RuntimeException('Kepware request failed: ' . $error, $errno);
}
$decoded = json_decode($response, true);
if (!is_array($decoded)) {
$snippet = substr($response, 0, 200);
error_log('Kepware returned a non-JSON payload: ' . $snippet);
if ($attempt < $attempts) {
if ($retryDelay > 0.0) {
usleep((int) round($retryDelay * 1_000_000));
}
continue;
}
throw new RuntimeException('Invalid JSON response from Kepware: ' . $snippet);
}
if ($status >= 400) {
if ($status >= 500 && $status < 600 && $attempt < $attempts) {
error_log(sprintf(
'Kepware request to %s attempt %d returned HTTP %d. Retrying in %.2f seconds.',
$path,
$attempt,
$status,
$retryDelay
));
if ($retryDelay > 0.0) {
usleep((int) round($retryDelay * 1_000_000));
}
continue;
}
throw new RuntimeException('Kepware request error (HTTP ' . $status . ').');
}
if ($attempt > 1) {
error_log(sprintf('Kepware request to %s succeeded on attempt %d.', $path, $attempt));
}
return $decoded;
}
throw new RuntimeException('Kepware request failed after ' . $attempts . ' attempts.');
}
}
if (!function_exists('kepware_read')) {
/**
* Read tag values from Kepware.
*
* @param string[] $tagIds List of tag identifiers.
*
* @return array<string, array<string, mixed>>
*/
function kepware_read(array $tagIds): array
{
if ($tagIds === []) {
return [];
}
$query = http_build_query(['ids' => implode(',', $tagIds)]);
$payload = kepware_rest_request('GET', 'read?' . $query);
$results = [];
foreach ($payload['readResults'] ?? [] as $result) {
if (!isset($result['id'])) {
continue;
}
$results[$result['id']] = [
'value' => $result['v'] ?? null,
'timestamp' => $result['t'] ?? null,
'status' => $result['s'] ?? null,
];
}
return $results;
}
}
if (!function_exists('kepware_write')) {
/**
* Write tag values via Kepware.
*
* @param array<int, array<string, mixed>> $writeRequest
*
* @return array<int, array<string, mixed>>
*/
function kepware_write(array $writeRequest): array
{
if ($writeRequest === []) {
return [];
}
$payload = kepware_rest_request('POST', 'write', $writeRequest);
if (isset($payload['writeResults']) && is_array($payload['writeResults'])) {
return $payload['writeResults'];
}
return $payload;
}
}

View File

@@ -0,0 +1,14 @@
<?php // phpcs:ignoreFile ?>
</div>
</main>
<footer class="app-footer">
<div class="app-footer__inner">
<p>&copy; <?php echo date('Y'); ?> Louisiana Sugarcane Cooperative, Inc. All rights reserved.</p>
</div>
</footer>
<button type="button" data-back-to-top aria-label="Back to top">Top</button>
</div>
<script src="<?php echo htmlspecialchars($assetBasePath ?? ''); ?>assets/js/mobile-header.js?v=<?php echo rawurlencode($assetVersion ?? '2025.10.02'); ?>" defer></script>
<script src="<?php echo htmlspecialchars($assetBasePath ?? ''); ?>assets/js/refresh.js?v=<?php echo rawurlencode($assetVersion ?? '2025.10.02'); ?>" defer></script>
</body>
</html>

View File

@@ -0,0 +1,88 @@
<?php // phpcs:ignoreFile
$pageTitle = $pageTitle ?? 'LASUCA Controls';
$pageSubtitle = $pageSubtitle ?? 'Real-time operations dashboard';
$pageDescription = $pageDescription ?? 'Monitoring suite for mill, boilers, and fabrication systems.';
$layoutWithoutSidebar = $layoutWithoutSidebar ?? false;
$layoutReturnUrl = $layoutReturnUrl ?? null;
$layoutReturnLabel = $layoutReturnLabel ?? 'Back to overview';
$layoutCloseWindowLabel = $layoutCloseWindowLabel ?? null;
$shellClasses = 'app-shell' . ($layoutWithoutSidebar ? ' app-shell--no-sidebar' : '');
$assetVersion = $assetVersion ?? '2025.10.06.3';
$assetBasePath = $assetBasePath ?? '';
if ($assetBasePath !== '' && substr($assetBasePath, -1) !== '/') {
$assetBasePath .= '/';
}
// Fetch crop day stats for header display
$headerCropDay = null;
$headerPassedHours = null;
$headerRemainingHours = null;
$cropDayFile = __DIR__ . '/../../includes/cropday.php';
$passedHoursFile = __DIR__ . '/../../includes/passedhours.php';
$remainingHoursFile = __DIR__ . '/../../includes/remaininghours.php';
if (is_file($cropDayFile)) {
ob_start();
include $cropDayFile;
$headerCropDay = trim(ob_get_clean());
}
if (is_file($passedHoursFile)) {
ob_start();
include $passedHoursFile;
$headerPassedHours = trim(ob_get_clean());
}
if (is_file($remainingHoursFile)) {
ob_start();
include $remainingHoursFile;
$headerRemainingHours = trim(ob_get_clean());
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="<?php echo htmlspecialchars($pageDescription); ?>">
<title><?php echo htmlspecialchars($pageTitle); ?> | LASUCA Controls</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="<?php echo htmlspecialchars($assetBasePath); ?>style.css?v=<?php echo rawurlencode($assetVersion); ?>">
</head>
<body>
<div class="<?php echo $shellClasses; ?>">
<header class="app-header">
<div class="app-header__inner">
<div class="branding">
<h1><?php echo htmlspecialchars($pageTitle); ?></h1>
<?php if (!empty($pageSubtitle)) : ?>
<p><?php echo htmlspecialchars($pageSubtitle); ?></p>
<?php endif; ?>
<div class="header-stats">
<span class="header-stat"><strong>Crop Day:</strong> <?php echo $headerCropDay ?: '—'; ?></span>
<span class="header-stat"><strong>Hours Passed:</strong> <?php echo $headerPassedHours ? number_format((float)$headerPassedHours, 1) : '—'; ?></span>
<span class="header-stat"><strong>Hours Remaining:</strong> <?php echo $headerRemainingHours ? number_format((float)$headerRemainingHours, 1) : '—'; ?></span>
</div>
</div>
<div class="header-actions">
<?php include __DIR__ . '/../../darkmode.php'; ?>
<?php if ($layoutWithoutSidebar && $layoutCloseWindowLabel) : ?>
<button type="button" class="button button--ghost" onclick="window.close();">
<?php echo htmlspecialchars($layoutCloseWindowLabel); ?>
</button>
<?php elseif ($layoutWithoutSidebar && $layoutReturnUrl) : ?>
<a class="button button--ghost" href="<?php echo htmlspecialchars($layoutReturnUrl); ?>">
← <?php echo htmlspecialchars($layoutReturnLabel); ?>
</a>
<?php elseif (!$layoutWithoutSidebar) : ?>
<button type="button" data-menu-toggle aria-expanded="false" aria-label="Toggle navigation">
<span aria-hidden="true">☰</span>
</button>
<?php endif; ?>
</div>
</div>
</header>
<main class="app-layout">
<div class="app-layout__inner">

View File

@@ -0,0 +1,17 @@
<?php // phpcs:ignoreFile
$con = mysqli_connect('192.168.0.10', 'corey', '41945549', 'controls');
$query = "SELECT ID, Name, ROUND(Value, 0) AS Value, ROUND(Value, 1) AS RoundedValue1, ROUND(Value, 2) AS RoundedValue, Timestamp FROM items ORDER BY ID ASC";
$result = mysqli_query($con, $query);
mysqli_close($con);
while ($row = mysqli_fetch_array($result, MYSQLI_ASSOC)) {
$value[$row['Name']] = $row['Value'];
$rounded[$row['Name']] = $row['RoundedValue'];
$time[$row['Name']] = $row['Timestamp'];
$ID[$row['ID']] = $row['Value'];
$roundedid[$row['ID']] = $row['RoundedValue'];
$rounded1[$row['ID']] = $row['RoundedValue1'];
$rounded1[$row['Name']] = $row['RoundedValue1'];
}

View File

@@ -0,0 +1,150 @@
<?php // phpcs:ignoreFile
/**
* Query logging helper for NL2SQL few-shot seeding.
*
* Usage:
* require_once __DIR__ . '/includes/log_query.php';
* logControlsQuery($userQuery, $sqlTemplate, $params, $sourceForm, $executionMs, $rowCount);
*/
// Logging database connection (separate from historian)
function getLoggingPdo(): ?PDO
{
static $pdo = null;
if ($pdo !== null) {
return $pdo;
}
$servername = '192.168.0.16';
$username = 'lasucaai';
$password = 'is413#dfslw';
$dbname = 'lasucaai';
try {
$pdo = new PDO(
"sqlsrv:Server=$servername;Database=$dbname",
$username,
$password,
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]
);
return $pdo;
} catch (PDOException $e) {
error_log('getLoggingPdo connection error: ' . $e->getMessage());
return null;
}
}
/**
* Log a query to dbo.controls_query_log for NL2SQL training.
*
* @param string $userQuery Natural-language description of the search.
* @param string $sqlTemplate Parameterized SQL with placeholders.
* @param array|null $params Associative array of parameter values.
* @param string|null $sourceForm Originating form identifier.
* @param int|null $executionMs Query runtime in milliseconds.
* @param int|null $rowCount Number of rows returned.
* @return bool True on success, false on failure.
*/
function logControlsQuery(
string $userQuery,
string $sqlTemplate,
?array $params = null,
?string $sourceForm = null,
?int $executionMs = null,
?int $rowCount = null
): bool {
// Silently skip if inputs are empty
if (trim($userQuery) === '' || trim($sqlTemplate) === '') {
return false;
}
$pdo = getLoggingPdo();
if ($pdo === null) {
return false;
}
$sql = "
INSERT INTO dbo.controls_query_log
(user_query, sql_template, params, source_form, user_session, execution_ms, row_count)
VALUES
(:user_query, :sql_template, :params, :source_form, :user_session, :execution_ms, :row_count)
";
try {
$stmt = $pdo->prepare($sql);
$result = $stmt->execute([
':user_query' => mb_substr($userQuery, 0, 1000),
':sql_template' => $sqlTemplate,
':params' => $params !== null ? json_encode($params, JSON_UNESCAPED_UNICODE) : null,
':source_form' => $sourceForm,
':user_session' => session_id() ?: null,
':execution_ms' => $executionMs,
':row_count' => $rowCount,
]);
return $result;
} catch (Throwable $e) {
return false;
}
}
/**
* Build a natural-language description from form inputs.
*
* @param string $searchType 'single_name' or 'multiple_names'.
* @param string $searchName Single tag name (if applicable).
* @param array $selectedTags Array of tag names for multi-tag search.
* @param string $startDate Start datetime string.
* @param string $endDate End datetime string.
* @param int $limit Row limit.
* @param int $timeInterval Sampling interval in seconds.
* @return string Human-readable query description.
*/
function buildUserQueryDescription(
string $searchType,
string $searchName,
array $selectedTags,
string $startDate,
string $endDate,
int $limit,
int $timeInterval
): string {
$parts = [];
// Tag(s)
if ($searchType === 'single_name' && $searchName !== '') {
$parts[] = "Show data for tag \"{$searchName}\"";
} elseif ($searchType === 'multiple_names' && !empty($selectedTags)) {
$tagList = implode(', ', array_map(fn($t) => "\"{$t}\"", $selectedTags));
$parts[] = "Compare tags {$tagList}";
} else {
return '';
}
// Date range
if ($startDate !== '' && $endDate !== '') {
$parts[] = "from {$startDate} to {$endDate}";
} elseif ($startDate !== '') {
$parts[] = "starting from {$startDate}";
} elseif ($endDate !== '') {
$parts[] = "up until {$endDate}";
}
// Sampling
if ($timeInterval > 1) {
if ($timeInterval >= 60) {
$minutes = (int) ($timeInterval / 60);
$parts[] = "sampled every {$minutes} minute" . ($minutes > 1 ? 's' : '');
} else {
$parts[] = "sampled every {$timeInterval} seconds";
}
}
// Limit
$parts[] = "limit {$limit} rows";
return implode(' ', $parts);
}

View File

@@ -0,0 +1,62 @@
<?php
include '../dbinfo.php';
include '../dbinfo2.php';
$con = mysqli_connect('192.168.0.10', 'corey', '41945549', 'controls');
// Second connection for west mill data (dbinfo2.php)
$con2 = mysqli_connect('192.168.0.9', 'corey', '41945549', 'controls');
function fetchLatestAndHourAgo(mysqli $con, string $table, string $column): ?array
{
$sql = "
SELECT $column AS value, timestamp
FROM $table
ORDER BY id DESC
LIMIT 3600
";
$result = mysqli_query($con, $sql);
if (!$result) {
return null;
}
$rows = mysqli_fetch_all($result, MYSQLI_ASSOC);
if (count($rows) === 0) {
return null;
}
$latest = $rows[0];
$hourAgo = $rows[min(count($rows) - 1, 3599)]; // fall back if fewer than 3600 rows
return [
'latest' => (float) $latest['value'],
'hourAgo' => (float) $hourAgo['value'],
'elapsedH' => max(
1,
(strtotime($latest['timestamp']) - strtotime($hourAgo['timestamp'])) / 3600
),
];
}
$east = fetchLatestAndHourAgo($con, 'easttotalground', 'easttotground');
$west = $con2 ? fetchLatestAndHourAgo($con2, 'westtotalground', 'MODBUSENET_TABLE900_WTOTGROUND_VALUE') : null;
$totalToday = (float) mysqli_fetch_column(mysqli_query(
$con,
"SELECT MillTotalGround FROM mill_total_ground ORDER BY id DESC LIMIT 1"
));
mysqli_close($con);
if ($con2) {
mysqli_close($con2);
}
$hoursSinceFive = (time() < strtotime('5:00'))
? (time() + 86400 - strtotime('5:00')) / 3600
: (time() - strtotime('5:00')) / 3600;
$hoursRemaining = max(0, 24 - $hoursSinceFive);
$eastProjected = $east ? ($east['latest'] - $east['hourAgo']) / $east['elapsedH'] * $hoursRemaining : 0;
$westProjected = $west ? ($west['latest'] - $west['hourAgo']) / $west['elapsedH'] * $hoursRemaining : 0;
echo number_format($totalToday + $eastProjected + $westProjected, 0);

View File

@@ -0,0 +1,80 @@
<?php // phpcs:ignoreFile
/**
* Mill Names Helper - Functions to retrieve mill display names
*
* Usage:
* require_once __DIR__ . '/millnames.php';
* $millNames = getMillNames($conn); // Pass existing sqlsrv connection
* $displayName = getMillDisplayName($millNames, 'EastMill'); // Returns 'East Mill' or original
*/
/**
* Get all active mill names from the lookup table
*
* @param resource $conn SQL Server connection
* @return array Associative array: mill_code => display_name
*/
function getMillNames($conn) {
$sql = "SELECT mill_code, display_name FROM mill_names WHERE is_active = 1 ORDER BY sort_order";
$result = sqlsrv_query($conn, $sql);
$names = [];
if ($result) {
while ($row = sqlsrv_fetch_array($result, SQLSRV_FETCH_ASSOC)) {
$names[$row['mill_code']] = $row['display_name'];
}
}
return $names;
}
/**
* Get display name for a mill code, with fallback to original code
*
* @param array $millNames Array from getMillNames()
* @param string $millCode The raw mill code from data
* @return string Display name or original code if not found
*/
function getMillDisplayName($millNames, $millCode) {
return isset($millNames[$millCode]) ? $millNames[$millCode] : $millCode;
}
/**
* Get all mill names including inactive ones
*
* @param resource $conn SQL Server connection
* @return array Full rows with all columns
*/
function getAllMillNames($conn) {
$sql = "SELECT * FROM mill_names ORDER BY sort_order, mill_code";
$result = sqlsrv_query($conn, $sql);
$names = [];
if ($result) {
while ($row = sqlsrv_fetch_array($result, SQLSRV_FETCH_ASSOC)) {
$names[] = $row;
}
}
return $names;
}
/**
* Get sort order for a mill code (for ordering display)
*
* @param resource $conn SQL Server connection
* @return array Associative array: mill_code => sort_order
*/
function getMillSortOrders($conn) {
$sql = "SELECT mill_code, sort_order FROM mill_names WHERE is_active = 1 ORDER BY sort_order";
$result = sqlsrv_query($conn, $sql);
$orders = [];
if ($result) {
while ($row = sqlsrv_fetch_array($result, SQLSRV_FETCH_ASSOC)) {
$orders[$row['mill_code']] = $row['sort_order'];
}
}
return $orders;
}

View File

@@ -0,0 +1,24 @@
<?php
include("../dbinfo.php");
$con=mysqli_connect($host,$username,$password,$database);
$query = "SELECT (SELECT milltotalground FROM mill_total_ground ORDER BY id DESC LIMIT 1) /
(SELECT TIME_TO_SEC(
TIMEDIFF(
CASE
WHEN CURRENT_TIME() < '5:00:00'
THEN ADDTIME(CURRENT_TIME(), '240000')
ELSE CURRENT_TIME() END,
'05:00:00'))/3600 AS hours)
*24
AS millprojected";
$result=mysqli_query($con,$query);
$include4=mysqli_fetch_array($result,MYSQLI_ASSOC);
mysqli_close($con);
?>
<?php echo round($include4['millprojected']); ?>

View File

@@ -0,0 +1,39 @@
<?php
include("../dbinfo.php");
$con=mysqli_connect($host,$username,$password,$database);
$query = "SELECT ROUND(
(((SELECT easttotground FROM easttotalground ORDER BY id DESC LIMIT 1) - (
SELECT easttotground FROM easttotalground ORDER BY id DESC LIMIT 899, 1))*(24
-
((SELECT TIME_TO_SEC(
TIMEDIFF(
CASE
WHEN CURRENT_TIME() < '5:00:00'
THEN ADDTIME(CURRENT_TIME(), '240000')
ELSE CURRENT_TIME() END,
'05:00:00'))/3600))))
+
(((SELECT westtotground FROM westtotalground ORDER BY id DESC LIMIT 1) - (
SELECT westtotground FROM westtotalground ORDER BY id DESC LIMIT 899, 1))*(24
-
((SELECT TIME_TO_SEC(
TIMEDIFF(
CASE
WHEN CURRENT_TIME() < '5:00:00'
THEN ADDTIME(CURRENT_TIME(), '240000')
ELSE CURRENT_TIME() END,
'05:00:00'))/3600)))))*4
+
(SELECT MillTotalGround FROM mill_total_ground ORDER BY id DESC LIMIT 1)
AS millprojected";
$result=mysqli_query($con,$query);
$include4=mysqli_fetch_array($result,MYSQLI_ASSOC);
mysqli_close($con);
?>
<?php echo round($include4['millprojected']); ?>

View File

@@ -0,0 +1,39 @@
<?php
include("../dbinfo.php");
$con=mysqli_connect($host,$username,$password,$database);
$query = "SELECT ROUND(
(((SELECT easttotground FROM easttotalground ORDER BY id DESC LIMIT 1) - (
SELECT easttotground FROM easttotalground ORDER BY id DESC LIMIT 1799, 1))*(24
-
((SELECT TIME_TO_SEC(
TIMEDIFF(
CASE
WHEN CURRENT_TIME() < '5:00:00'
THEN ADDTIME(CURRENT_TIME(), '240000')
ELSE CURRENT_TIME() END,
'05:00:00'))/3600))))
+
(((SELECT westtotground FROM westtotalground ORDER BY id DESC LIMIT 1) - (
SELECT westtotground FROM westtotalground ORDER BY id DESC LIMIT 1799, 1))*(24
-
((SELECT TIME_TO_SEC(
TIMEDIFF(
CASE
WHEN CURRENT_TIME() < '5:00:00'
THEN ADDTIME(CURRENT_TIME(), '240000')
ELSE CURRENT_TIME() END,
'05:00:00'))/3600)))))*2
+
(SELECT MillTotalGround FROM mill_total_ground ORDER BY id DESC LIMIT 1)
AS millprojected";
$result=mysqli_query($con,$query);
$include4=mysqli_fetch_array($result,MYSQLI_ASSOC);
mysqli_close($con);
?>
<?php echo round($include4['millprojected']); ?>

View File

@@ -0,0 +1,39 @@
<?php
include("../dbinfo.php");
$con=mysqli_connect($host,$username,$password,$database);
$query = "SELECT ROUND(
(((SELECT easttotground FROM easttotalground ORDER BY id DESC LIMIT 1) - (
SELECT easttotground FROM easttotalground ORDER BY id DESC LIMIT 299, 1))*(24
-
((SELECT TIME_TO_SEC(
TIMEDIFF(
CASE
WHEN CURRENT_TIME() < '5:00:00'
THEN ADDTIME(CURRENT_TIME(), '240000')
ELSE CURRENT_TIME() END,
'05:00:00'))/3600))))
+
(((SELECT westtotground FROM westtotalground ORDER BY id DESC LIMIT 1) - (
SELECT westtotground FROM westtotalground ORDER BY id DESC LIMIT 299, 1))*(24
-
((SELECT TIME_TO_SEC(
TIMEDIFF(
CASE
WHEN CURRENT_TIME() < '5:00:00'
THEN ADDTIME(CURRENT_TIME(), '240000')
ELSE CURRENT_TIME() END,
'05:00:00'))/3600)))))*12
+
(SELECT MillTotalGround FROM mill_total_ground ORDER BY id DESC LIMIT 1)
AS millprojected";
$result=mysqli_query($con,$query);
$include4=mysqli_fetch_array($result,MYSQLI_ASSOC);
mysqli_close($con);
?>
<?php echo round($include4['millprojected']); ?>

View File

@@ -0,0 +1,63 @@
<?php
include("../dbinfo.php");
include("../dbinfo2.php");
// Connection 1: East mill data (dbinfo.php - 192.168.0.10)
$con = mysqli_connect('192.168.0.10', 'corey', '41945549', 'controls');
// Connection 2: West mill data (192.168.0.9)
$con2 = mysqli_connect('192.168.0.9', 'corey', '41945549', 'controls');
// Calculate hours remaining until 5am
$hoursSinceFive = (time() < strtotime('5:00'))
? (time() + 86400 - strtotime('5:00')) / 3600
: (time() - strtotime('5:00')) / 3600;
$hoursRemaining = max(0, 24 - $hoursSinceFive);
// Get east mill data from primary server
$eastLatest = 0;
$eastHourAgo = 0;
$eastResult = mysqli_query($con, "SELECT easttotground FROM easttotalground ORDER BY id DESC LIMIT 1");
if ($eastResult && $row = mysqli_fetch_assoc($eastResult)) {
$eastLatest = (float) $row['easttotground'];
}
$eastHourAgoResult = mysqli_query($con, "SELECT easttotground FROM easttotalground ORDER BY id DESC LIMIT 3599, 1");
if ($eastHourAgoResult && $row = mysqli_fetch_assoc($eastHourAgoResult)) {
$eastHourAgo = (float) $row['easttotground'];
}
// Get west mill data from secondary server (192.168.0.9)
$westLatest = 0;
$westHourAgo = 0;
if ($con2) {
$westResult = mysqli_query($con2, "SELECT MODBUSENET_TABLE900_WTOTGROUND_VALUE FROM westtotalground ORDER BY id DESC LIMIT 1");
if ($westResult && $row = mysqli_fetch_assoc($westResult)) {
$westLatest = (float) $row['MODBUSENET_TABLE900_WTOTGROUND_VALUE'];
}
$westHourAgoResult = mysqli_query($con2, "SELECT MODBUSENET_TABLE900_WTOTGROUND_VALUE FROM westtotalground ORDER BY id DESC LIMIT 3599, 1");
if ($westHourAgoResult && $row = mysqli_fetch_assoc($westHourAgoResult)) {
$westHourAgo = (float) $row['MODBUSENET_TABLE900_WTOTGROUND_VALUE'];
}
}
// Get current day total from primary server
$totalToday = 0;
$totalResult = mysqli_query($con, "SELECT MillTotalGround FROM mill_total_ground ORDER BY id DESC LIMIT 1");
if ($totalResult && $row = mysqli_fetch_assoc($totalResult)) {
$totalToday = (float) $row['MillTotalGround'];
}
mysqli_close($con);
if ($con2) {
mysqli_close($con2);
}
// Calculate projections
$eastProjected = ($eastLatest - $eastHourAgo) * $hoursRemaining;
$westProjected = ($westLatest - $westHourAgo) * $hoursRemaining;
$millProjected = $totalToday + $eastProjected + $westProjected;
?>
<?php echo round($millProjected); ?>

View File

@@ -0,0 +1,39 @@
<?php
include("../dbinfo.php");
$con=mysqli_connect($host,$username,$password,$database);
$query = "SELECT ROUND(
(((SELECT easttotground FROM easttotalground ORDER BY id DESC LIMIT 1) - (
SELECT easttotground FROM easttotalground ORDER BY id DESC LIMIT 3599, 1))*(24
-
((SELECT TIME_TO_SEC(
TIMEDIFF(
CASE
WHEN CURRENT_TIME() < '5:00:00'
THEN ADDTIME(CURRENT_TIME(), '240000')
ELSE CURRENT_TIME() END,
'05:00:00'))/3600))))
+
(((SELECT westtotground FROM westtotalground ORDER BY id DESC LIMIT 1) - (
SELECT westtotground FROM westtotalground ORDER BY id DESC LIMIT 3599, 1))*(24
-
((SELECT TIME_TO_SEC(
TIMEDIFF(
CASE
WHEN CURRENT_TIME() < '5:00:00'
THEN ADDTIME(CURRENT_TIME(), '240000')
ELSE CURRENT_TIME() END,
'05:00:00'))/3600)))))*1
+
(SELECT MillTotalGround FROM mill_total_ground ORDER BY id DESC LIMIT 1)
AS millprojected";
$result=mysqli_query($con,$query);
$include4=mysqli_fetch_array($result,MYSQLI_ASSOC);
mysqli_close($con);
?>
<?php echo round($include4['millprojected']); ?>

View File

@@ -0,0 +1,129 @@
<?php
/**
* Mill Projected Total - MSSQL Version (60 minute window)
*
* Uses SQL Server archive table (row-based storage) instead of MySQL
*
* Tags:
* - WTOTGROUND (ID: 342) - West Mill Total Ground
* - CANETOT (ID: 218) - East Mill Total Ground
* - TotalGround (ID: 230) - Total Ground Since 5 AM
*/
$servername = "192.168.0.13\\SQLEXPRESS";
$username = "opce";
$password = "opcelasuca";
$dbname = "history";
try {
$pdo = new PDO(
"sqlsrv:Server=$servername;Database=$dbname",
$username,
$password,
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]
);
} catch (PDOException $e) {
echo "0";
return;
}
// Tag IDs
$eastId = 218; // CANETOT
$westId = 342; // WTOTGROUND
$totalId = 230; // TotalGround
$query = "
DECLARE @now DATETIME = GETDATE();
DECLARE @oneHourAgo DATETIME = DATEADD(HOUR, -1, @now);
-- Calculate hours remaining until 5 AM
-- If before 5 AM, time until 5 AM today
-- If after 5 AM, time until 5 AM tomorrow
DECLARE @hoursRemaining FLOAT;
DECLARE @targetTime DATETIME;
IF CAST(@now AS TIME) < '05:00:00'
SET @targetTime = CAST(CAST(@now AS DATE) AS DATETIME) + CAST('05:00:00' AS DATETIME)
ELSE
SET @targetTime = CAST(DATEADD(DAY, 1, CAST(@now AS DATE)) AS DATETIME) + CAST('05:00:00' AS DATETIME)
SET @hoursRemaining = DATEDIFF(SECOND, @now, @targetTime) / 3600.0;
-- Get latest East value
DECLARE @eastLatest FLOAT = (
SELECT TOP 1 Value
FROM dbo.archive
WHERE ID = :eastId
ORDER BY TimeStamp DESC
);
-- Get East value from ~60 minutes ago
DECLARE @eastOld FLOAT = (
SELECT TOP 1 Value
FROM dbo.archive
WHERE ID = :eastId2 AND TimeStamp <= @oneHourAgo
ORDER BY TimeStamp DESC
);
-- Get latest West value
DECLARE @westLatest FLOAT = (
SELECT TOP 1 Value
FROM dbo.archive
WHERE ID = :westId
ORDER BY TimeStamp DESC
);
-- Get West value from ~60 minutes ago
DECLARE @westOld FLOAT = (
SELECT TOP 1 Value
FROM dbo.archive
WHERE ID = :westId2 AND TimeStamp <= @oneHourAgo
ORDER BY TimeStamp DESC
);
-- Get current total ground
DECLARE @totalGround FLOAT = (
SELECT TOP 1 Value
FROM dbo.archive
WHERE ID = :totalId
ORDER BY TimeStamp DESC
);
-- Calculate rates (tons per hour)
DECLARE @eastRate FLOAT = COALESCE(@eastLatest, 0) - COALESCE(@eastOld, 0);
DECLARE @westRate FLOAT = COALESCE(@westLatest, 0) - COALESCE(@westOld, 0);
-- Handle negative rates (mill reset or bad data)
IF @eastRate < 0 SET @eastRate = 0;
IF @westRate < 0 SET @westRate = 0;
-- Calculate projection
SELECT ROUND(
((@eastRate + @westRate) * @hoursRemaining) + COALESCE(@totalGround, 0),
0
) AS millprojected;
";
try {
$stmt = $pdo->prepare($query);
$stmt->execute([
':eastId' => $eastId,
':eastId2' => $eastId,
':westId' => $westId,
':westId2' => $westId,
':totalId' => $totalId,
]);
$result = $stmt->fetch();
$projected = $result ? round($result['millprojected']) : 0;
} catch (PDOException $e) {
$projected = 0;
}
$pdo = null;
?>
<?php echo $projected; ?>

View File

@@ -0,0 +1,14 @@
<?php
include("../dbinfo.php");
$con=mysqli_connect($host,$username,$password,$database);
$query = "SELECT DISTINCT MillTotal FROM mill_ytd_totals ORDER BY ID DESC LIMIT 1";
$result=mysqli_query($con,$query);
$include1=mysqli_fetch_array($result,MYSQLI_ASSOC);
mysqli_close($con);
?>
<?php echo round($include1['MillTotal'] + 3705); ?>

View File

@@ -0,0 +1,21 @@
<?php
include("dbinfo.php");
$con=mysqli_connect($host,$username,$password,$database);
$query = "SELECT TIME_TO_SEC(
TIMEDIFF(
CASE
WHEN CURRENT_TIME() < '5:00:00'
THEN ADDTIME(CURRENT_TIME(), '240000')
ELSE CURRENT_TIME() END,
'05:00:00'))/3600 AS hoursleft";
$result=mysqli_query($con,$query);
$include4=mysqli_fetch_array($result,MYSQLI_ASSOC);
mysqli_close($con);
?>
<?php echo ($include4['hoursleft']); ?>

View File

@@ -0,0 +1,39 @@
<?php
$serverName = "CBM2K12\SQLEXPRESS";
$uid = "cbmclient";
$pwd = "ascbm2k";
$connectionInfo = array( "UID"=>$uid, "PWD"=>$pwd,'ReturnDatesAsStrings'=> true, "CharacterSet" => 'utf-8', "Database"=>"SugarCaneScale" );
/* Connect using SQL Server Authentication. */
$conn = sqlsrv_connect( $serverName, $connectionInfo);
if( $conn === false )
{
echo "Unable to connect.</br>";
die( print_r( sqlsrv_errors(), true));
}
$sql = "SELECT DISTINCT CropDay, ROUND (Tons,0) AS Tons FROM LoadData ORDER BY CropDay DESC";
$stmt = sqlsrv_query( $conn, $sql );
if( $stmt === false) {
die( print_r( sqlsrv_errors(), true) );
}
echo "<select name='Tons' id='Tons'>";
while( $row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_ASSOC) )
{
$tonsin += $row['Tons'];
$cropday += $row['CropDay'];
}
{
echo "<option value='" . $tonsin . "' >" . $tonsin . " " . $cropday . "</option>";
}
echo "</select>";
//end
?>
<?
$db = null;
?>

View File

@@ -0,0 +1,14 @@
<?php
include("../dbinfo.php");
$con=mysqli_connect($host,$username,$password,$database);
$query = "SELECT DISTINCT record FROM record ORDER BY record DESC LIMIT 1";
$result=mysqli_query($con,$query);
$include1=mysqli_fetch_array($result,MYSQLI_ASSOC);
mysqli_close($con);
?>
<?php echo round($include1['record']); ?>

View File

@@ -0,0 +1,14 @@
<?php
include("../dbinfo.php");
$con=mysqli_connect($host,$username,$password,$database);
$query = "SELECT DISTINCT record, timestamp FROM record ORDER BY record DESC LIMIT 1";
$result=mysqli_query($con,$query);
$include1=mysqli_fetch_array($result,MYSQLI_ASSOC);
mysqli_close($con);
?>
<?php echo date('M, d', strtotime('-1 day', strtotime($include1['timestamp']))); ?>

View File

@@ -0,0 +1,21 @@
<?php
include("dbinfo.php");
$con=mysqli_connect($host,$username,$password,$database);
$query = "SELECT 24-TIME_TO_SEC(
TIMEDIFF(
CASE
WHEN CURRENT_TIME() < '5:00:00'
THEN ADDTIME(CURRENT_TIME(), '240000')
ELSE CURRENT_TIME() END,
'05:00:00'))/3600 AS hoursleft";
$result=mysqli_query($con,$query);
$include4=mysqli_fetch_array($result,MYSQLI_ASSOC);
mysqli_close($con);
?>
<?php echo ($include4['hoursleft']); ?>

View File

@@ -0,0 +1,183 @@
<?php
declare(strict_types=1);
require_once __DIR__ . '/../dbinfo.php';
if (!function_exists('lasuca_normalise_panel_key')) {
/**
* Normalises a dashboard panel key for consistent storage.
*/
function lasuca_normalise_panel_key(string $key): string
{
return trim($key);
}
}
if (!function_exists('lasuca_get_section_layout_connection')) {
/**
* Opens a MySQL connection configured for the section layouts table.
*/
function lasuca_get_section_layout_connection(): mysqli|false
{
$connection = mysqli_connect($GLOBALS['DB_SERVER'], $GLOBALS['DB_USER'], $GLOBALS['DB_PASS']);
if (!$connection) {
error_log('lasuca_get_section_layout_connection: cannot connect to MySQL server: ' . mysqli_connect_error());
return false;
}
if (!mysqli_select_db($connection, $GLOBALS['DB_NAME'])) {
error_log('lasuca_get_section_layout_connection: cannot select database: ' . mysqli_error($connection));
mysqli_close($connection);
return false;
}
if (!mysqli_set_charset($connection, 'utf8mb4')) {
error_log('lasuca_get_section_layout_connection: cannot set charset: ' . mysqli_error($connection));
mysqli_close($connection);
return false;
}
return $connection;
}
}
if (!function_exists('lasuca_get_section_order')) {
/**
* Retrieves the saved section order for a member/panel combination.
*
* @return string[]
*/
function lasuca_get_section_order(mysqli $connection, string $sectionKey, string $memberId): array
{
$normalisedKey = lasuca_normalise_panel_key($sectionKey);
$safeMemberId = trim($memberId);
$sql = 'SELECT section_order FROM section_layouts WHERE panel_key = ? AND member_id = ? LIMIT 1';
$statement = mysqli_prepare($connection, $sql);
if (!$statement) {
error_log('lasuca_get_section_order: failed to prepare statement: ' . mysqli_error($connection));
return [];
}
mysqli_stmt_bind_param($statement, 'ss', $normalisedKey, $safeMemberId);
if (!mysqli_stmt_execute($statement)) {
error_log('lasuca_get_section_order: failed to execute statement: ' . mysqli_stmt_error($statement));
mysqli_stmt_close($statement);
return [];
}
$result = mysqli_stmt_get_result($statement);
mysqli_stmt_close($statement);
if (!$result instanceof mysqli_result) {
return [];
}
$row = mysqli_fetch_assoc($result);
mysqli_free_result($result);
if (!$row) {
return [];
}
$decoded = json_decode((string) $row['section_order'], true);
if (!is_array($decoded)) {
return [];
}
return array_values(array_filter($decoded, static fn($value): bool => is_string($value) && $value !== ''));
}
}
if (!function_exists('lasuca_save_section_order')) {
/**
* Persists a member's preferred section ordering.
*/
function lasuca_save_section_order(mysqli $connection, string $sectionKey, string $memberId, array $sectionOrder): bool
{
$normalisedKey = lasuca_normalise_panel_key($sectionKey);
$safeMemberId = trim($memberId);
$sanitisedOrder = array_values(array_filter($sectionOrder, static fn($value): bool => is_string($value) && $value !== ''));
$payload = json_encode($sanitisedOrder, JSON_THROW_ON_ERROR);
$sql = 'INSERT INTO section_layouts (panel_key, member_id, section_order, updated_at)
VALUES (?, ?, ?, NOW())
ON DUPLICATE KEY UPDATE section_order = VALUES(section_order), updated_at = NOW()';
$statement = mysqli_prepare($connection, $sql);
if (!$statement) {
error_log('lasuca_save_section_order: failed to prepare statement: ' . mysqli_error($connection));
return false;
}
mysqli_stmt_bind_param($statement, 'sss', $normalisedKey, $safeMemberId, $payload);
if (!mysqli_stmt_execute($statement)) {
error_log('lasuca_save_section_order: failed to execute statement: ' . mysqli_stmt_error($statement));
mysqli_stmt_close($statement);
return false;
}
$affected = mysqli_stmt_affected_rows($statement);
mysqli_stmt_close($statement);
return $affected > 0;
}
}
if (!function_exists('lasuca_reset_section_order')) {
/**
* Removes any persisted ordering for the user/panel.
*/
function lasuca_reset_section_order(mysqli $connection, string $sectionKey, string $memberId): bool
{
$normalisedKey = lasuca_normalise_panel_key($sectionKey);
$safeMemberId = trim($memberId);
$sql = 'DELETE FROM section_layouts WHERE panel_key = ? AND member_id = ?';
$statement = mysqli_prepare($connection, $sql);
if (!$statement) {
error_log('lasuca_reset_section_order: failed to prepare statement: ' . mysqli_error($connection));
return false;
}
mysqli_stmt_bind_param($statement, 'ss', $normalisedKey, $safeMemberId);
if (!mysqli_stmt_execute($statement)) {
error_log('lasuca_reset_section_order: failed to execute statement: ' . mysqli_stmt_error($statement));
mysqli_stmt_close($statement);
return false;
}
$affected = mysqli_stmt_affected_rows($statement);
mysqli_stmt_close($statement);
return $affected > 0;
}
}
if (!function_exists('lasuca_section_layout_health_check')) {
/**
* Performs a lightweight connectivity check for diagnostics.
*/
function lasuca_section_layout_health_check(): bool
{
$connection = lasuca_get_section_layout_connection();
if (!$connection) {
return false;
}
$result = mysqli_query($connection, 'SELECT 1');
if ($result instanceof mysqli_result) {
mysqli_free_result($result);
mysqli_close($connection);
return true;
}
mysqli_close($connection);
return false;
}
}

View File

@@ -0,0 +1,18 @@
<?php
include("../dbinfo.php");
$con=mysqli_connect($host,$username,$password,$database);
$query = "SELECT TIMEDIFF ((SELECT NOW()),(SELECT date FROM plc GROUP BY totnorth ORDER BY id DESC LIMIT 1)) AS time";
$result=mysqli_query($con,$query);
$include1=mysqli_fetch_array($result,MYSQLI_ASSOC);
mysqli_close($con);
?>
<table>
<tr>
<?php echo $include1['time']; ?>
</tr>
</table>

View File

@@ -0,0 +1,18 @@
<?php
include("../dbinfo.php");
$con=mysqli_connect($host,$username,$password,$database);
$query = "SELECT TIMEDIFF ((SELECT NOW()),(SELECT date FROM plc GROUP BY totsouth ORDER BY id DESC LIMIT 1)) AS time";
$result=mysqli_query($con,$query);
$include3=mysqli_fetch_array($result,MYSQLI_ASSOC);
mysqli_close($con);
?>
<table>
<tr>
<?php echo $include3['time']; ?>
</tr>
</table>

View File

@@ -0,0 +1,18 @@
<?php
include("../dbinfo.php");
$con=mysqli_connect($host,$username,$password,$database);
$query = "SELECT TIMEDIFF ((SELECT NOW()),(SELECT date FROM plc GROUP BY totwest2 ORDER BY id DESC LIMIT 1)) AS time";
$result=mysqli_query($con,$query);
$include1=mysqli_fetch_array($result,MYSQLI_ASSOC);
mysqli_close($con);
?>
<table>
<tr>
<?php echo $include1['time']; ?>
</tr>
</table>

View File

@@ -0,0 +1,18 @@
<?php
include("../dbinfo.php");
$con=mysqli_connect($host,$username,$password,$database);
$query = "SELECT(((SELECT easttotground FROM easttotalground ORDER BY id DESC LIMIT 1) - (SELECT easttotground FROM easttotalground ORDER BY id DESC LIMIT 29, 1))*120
+
((SELECT westtotground FROM westtotalground ORDER BY id DESC LIMIT 1) - (SELECT westtotground FROM westtotalground ORDER BY id DESC LIMIT 29, 1))*120)
AS stablerate";
$result=mysqli_query($con,$query);
$include4=mysqli_fetch_array($result,MYSQLI_ASSOC);
mysqli_close($con);
?>
<?php echo round($include4['stablerate']); ?>

View File

@@ -0,0 +1,18 @@
<?php
include("../dbinfo.php");
$con=mysqli_connect($host,$username,$password,$database);
$query = "SELECT(((SELECT easttotground FROM easttotalground ORDER BY id DESC LIMIT 1) - (SELECT easttotground FROM easttotalground ORDER BY id DESC LIMIT 29, 1))*120
+
((SELECT westtotground FROM westtotalground ORDER BY id DESC LIMIT 1) - (SELECT westtotground FROM westtotalground ORDER BY id DESC LIMIT 29, 1))*120)
AS stablerate";
$result=mysqli_query($con,$query);
$include4=mysqli_fetch_array($result,MYSQLI_ASSOC);
mysqli_close($con);
?>
<?php echo round($include4['stablerate']); ?>

View File

@@ -0,0 +1,18 @@
<?php
include("../dbinfo.php");
$con=mysqli_connect($host,$username,$password,$database);
$query = "SELECT(((SELECT easttotground FROM easttotalground ORDER BY id DESC LIMIT 1) - (SELECT easttotground FROM easttotalground ORDER BY id DESC LIMIT 59, 1))*60
+
((SELECT westtotground FROM westtotalground ORDER BY id DESC LIMIT 1) - (SELECT westtotground FROM westtotalground ORDER BY id DESC LIMIT 59, 1))*60)
AS stablerate";
$result=mysqli_query($con,$query);
$include4=mysqli_fetch_array($result,MYSQLI_ASSOC);
mysqli_close($con);
?>
<?php echo round($include4['stablerate']); ?>

View File

@@ -0,0 +1,6 @@
<?php
$d1= new DateTime("05:00:00am"); // first date
$d2= new \DateTime("now"); // second date
$interval= $d1->diff($d2); // get difference between two dates
echo $interval->h; // convert days to hours and add hours from difference
?>

View File

@@ -0,0 +1,35 @@
<?php
$serverName = "CBM2K12\SQLEXPRESS";
$uid = "cbmclient";
$pwd = "ascbm2k";
$connectionInfo = array( "UID"=>$uid, "PWD"=>$pwd,'ReturnDatesAsStrings'=> true, "CharacterSet" => 'utf-8', "Database"=>"SugarCaneScale" );
/* Connect using SQL Server Authentication. */
$conn = sqlsrv_connect( $serverName, $connectionInfo);
if( $conn === false )
{
echo "Unable to connect.</br>";
die( print_r( sqlsrv_errors(), true));
}
$sql = "SELECT ROUND (Tons,0) AS Tons FROM LoadData WHERE CropDay = ( SELECT Max(CropDay) FROM LoadData)";
$stmt = sqlsrv_query( $conn, $sql );
if( $stmt === false) {
die( print_r( sqlsrv_errors(), true) );
}
$tonsin = 0;
while( $row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_ASSOC) )
{
$tonsin += $row['Tons'];
}
//end
?>
<?php echo $tonsin; ?>
<?
$db = null;
?>

View File

@@ -0,0 +1,36 @@
<?php
$serverName = "CBM2K12\SQLEXPRESS";
$uid = "cbmclient";
$pwd = "ascbm2k";
$connectionInfo = array( "UID"=>$uid, "PWD"=>$pwd,'ReturnDatesAsStrings'=> true, "CharacterSet" => 'utf-8', "Database"=>"SugarCaneScale" );
/* Connect using SQL Server Authentication. */
$conn = sqlsrv_connect( $serverName, $connectionInfo);
if( $conn === false )
{
echo "Unable to connect.</br>";
die( print_r( sqlsrv_errors(), true));
}
$sql = "SELECT ROUND (Tons,0) AS Tons FROM LoadData WHERE CropDay = ( SELECT Max(CropDay)-1 FROM LoadData)";
$stmt = sqlsrv_query( $conn, $sql );
if( $stmt === false) {
die( print_r( sqlsrv_errors(), true) );
}
$tonsin = 0;
while( $row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_ASSOC) )
{
$tonsin += $row['Tons'];
}
//end
?>
<?php echo $tonsin; ?>
<?
$db = null;
?>

View File

@@ -0,0 +1,35 @@
<?php
$serverName = "CBM2K12\SQLEXPRESS";
$uid = "cbmclient";
$pwd = "ascbm2k";
$connectionInfo = array( "UID"=>$uid, "PWD"=>$pwd,'ReturnDatesAsStrings'=> true, "CharacterSet" => 'utf-8', "Database"=>"SugarCaneScale" );
/* Connect using SQL Server Authentication. */
$conn = sqlsrv_connect( $serverName, $connectionInfo);
if( $conn === false )
{
echo "Unable to connect.</br>";
die( print_r( sqlsrv_errors(), true));
}
$sql = "SELECT ROUND (Tons,0) AS Tons FROM LoadData ORDER BY DateIn DESC";
$stmt = sqlsrv_query( $conn, $sql );
if( $stmt === false) {
die( print_r( sqlsrv_errors(), true) );
}
$tonsin = 0;
while( $row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_ASSOC) )
{
$tonsin += $row['Tons'];
}
//end
?>
<?php echo $tonsin; ?>
<?
$db = null;
?>

View File

@@ -0,0 +1,15 @@
<?php
include("../dbinfo.php");
$con=mysqli_connect($host,$username,$password,$database);
$query = "SELECT ((SELECT westtotground FROM westtotalground ORDER BY id DESC LIMIT 1) - (SELECT westtotground FROM westtotalground ORDER BY id DESC LIMIT 899, 1))*4 AS westavg";
$result=mysqli_query($con,$query);
$include4=mysqli_fetch_array($result,MYSQLI_ASSOC);
mysqli_close($con);
?>
<?php echo round($include4['westavg']); ?>

View File

@@ -0,0 +1,14 @@
<?php
include("../dbinfo.php");
$con=mysqli_connect($host,$username,$password,$database);
$query = "SELECT DISTINCT WestTotal FROM mill_ytd_totals ORDER BY ID DESC LIMIT 1";
$result=mysqli_query($con,$query);
$include1=mysqli_fetch_array($result,MYSQLI_ASSOC);
mysqli_close($con);
?>
<?php echo round($include1['WestTotal']); ?>