This commit is contained in:
2026-02-12 11:51:16 -08:00
parent b8f6fd80f8
commit 54298dbd54
2 changed files with 459 additions and 25 deletions

View File

@@ -244,6 +244,66 @@
#toast.error {
background: #f890e7;
}
/* Admin panel styles */
.admin-toggle {
text-align: center;
margin-top: 20px;
padding: 10px;
font-size: 10px;
color: #555;
cursor: pointer;
letter-spacing: 1px;
text-transform: uppercase;
}
.admin-toggle:hover {
color: #888;
}
#adminPanel {
display: none;
background: #111;
border: 1px solid #333;
border-radius: 8px;
padding: 15px;
margin-top: 10px;
}
#adminPanel.visible {
display: block;
}
.admin-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
}
.admin-btn {
padding: 12px;
font-size: 11px;
background: #1a1a1a;
border: 1px solid #444;
color: #888;
border-radius: 6px;
cursor: pointer;
}
.admin-btn:hover {
border-color: #0bd3d3;
color: #0bd3d3;
}
.admin-btn.danger {
border-color: #f890e7;
color: #f890e7;
}
.admin-btn.danger:hover {
background: #f890e7;
color: #000;
}
</style>
</head>
<body>
@@ -268,6 +328,19 @@
<button id="silence" onclick="sendSilence()">Silence</button>
</div>
<!-- Admin Panel -->
<div class="admin-toggle" onclick="toggleAdmin()">⚙ Admin</div>
<div id="adminPanel">
<div class="admin-grid">
<button class="admin-btn" onclick="sendAdmin('MODE_SCREEN')">Screen Mode</button>
<button class="admin-btn" onclick="sendAdmin('MODE_LED')">LED Mode</button>
<button class="admin-btn" onclick="sendAdmin('SILENCE')">Force Silence</button>
<button class="admin-btn" onclick="sendAdmin('PING')">Ping Device</button>
<button class="admin-btn danger" onclick="sendAdmin('REBOOT')">Reboot</button>
<button class="admin-btn" onclick="showHelp()">Help</button>
</div>
</div>
<div id="toast">Sent</div>
<script>
@@ -275,6 +348,7 @@
const COMMAND_POST_URL = 'https://ntfy.sh/ALERT_klubhaus_topic';
const SILENCE_POST_URL = 'https://ntfy.sh/SILENCE_klubhaus_topic';
const METRICS_POST_URL = 'https://ntfy.sh/METRICS_klubhaus_topic';
const ADMIN_POST_URL = 'https://ntfy.sh/ADMIN_klubhaus_topic'; // NEW
const STATUS_WS_URL = 'wss://ntfy.sh/STATUS_klubhaus_topic/ws';
// ============== BACKOFF CONFIGURATION ==============
@@ -288,7 +362,7 @@
300000
];
// ============== CLIENT ID (persistent, anonymous) ==============
// ============== CLIENT ID ==============
function getOrCreateClientId() {
let id = localStorage.getItem('klubhaus_client_id');
if (!id) {
@@ -318,7 +392,7 @@
const CLIENT_ID = getOrCreateClientId();
// ============== METRICS (with localStorage persistence) ==============
// ============== METRICS ==============
function loadMetrics() {
const saved = localStorage.getItem('klubhaus_metrics');
if (saved) {
@@ -401,7 +475,7 @@
setInterval(updateBackoffDisplay, 10000);
// ============== WEBSOCKET WITH ADAPTIVE RECONNECT ==============
// ============== WEBSOCKET ==============
function connectWebSocket() {
const connEl = document.getElementById('connection');
const interval = getCurrentInterval();
@@ -481,6 +555,10 @@
} else if (state === 'SILENT') {
statusEl.className = 'silent';
statusEl.innerHTML = `<span>SILENT</span><span class="status-detail">System Ready</span>`;
} else if (state === 'CONFIG') {
statusEl.className = 'confirming';
statusEl.innerHTML = `<span>CONFIG</span><span class="status-detail">${escapeHtml(message)}</span>`;
setTimeout(() => updateStatusDisplay({state: 'SILENT'}), 2000);
} else {
statusEl.className = 'offline';
statusEl.innerHTML = `<span>UNKNOWN</span>`;
@@ -627,6 +705,41 @@
} catch (e) {}
}
// ============== ADMIN COMMANDS ==============
function toggleAdmin() {
const panel = document.getElementById('adminPanel');
panel.classList.toggle('visible');
}
async function sendAdmin(command) {
recordInteraction();
try {
const response = await fetch(ADMIN_POST_URL, {
method: 'POST',
body: command,
headers: { 'Title': 'KLUBHAUS ADMIN' }
});
if (response.ok) {
showToast(`ADMIN: ${command}`);
} else {
showToast('ADMIN FAILED', true);
}
} catch (e) {
showToast('NETWORK ERROR', true);
}
}
function showHelp() {
alert('Admin Commands:\n\n' +
'MODE_SCREEN - Use display normally\n' +
'MODE_LED - LED only (broken screen)\n' +
'SILENCE - Force silence\n' +
'PING - Test device connectivity\n' +
'REBOOT - Restart device');
}
// ============== CUSTOM & SILENCE ==============
function sendCustom() {
const input = document.getElementById('customInput');
@@ -709,7 +822,7 @@
el.textContent = `${CLIENT_ID} | posted:${metrics.totalPosted} confirmed:${metrics.totalConfirmed} errors:${metrics.totalErrors} avg:${avgRtt}ms | session:${sessionHours}h`;
}
// ============== AGGREGATE METRICS (deduplicated) ==============
// ============== AGGREGATE METRICS ==============
let lastMetricsHash = null;
let lastMetricsTimestamp = 0;
@@ -795,7 +908,7 @@
updateMetricsDisplay();
updateBackoffDisplay();
console.log('KLUBHAUS ALERT v4.2 initialized');
console.log('KLUBHAUS ALERT v4.3 initialized');
console.log('Client ID:', CLIENT_ID);
console.log('Loaded metrics:', metrics);
</script>