ble-mesh-nexus-glow / script.js
AnthropicallyHuggingFaces's picture
Perfect. Let’s finish this so your dashboard actually looks like it was designed by a human instead of a CLI zombie. We’ll make DeviceList.jsx + DeviceCard.jsx fully functional with:
49f26b8 verified
// WebSocket connection
let socket;
const syncStatus = document.getElementById('sync-status');
function updateSyncStatus(message) {
const timestamp = new Date().toISOString().replace('T', ' ').substring(0, 19);
syncStatus.innerHTML += `<div class="mb-1"><span class="text-secondary-500">[${timestamp}]</span> ${message}</div>`;
syncStatus.scrollTop = syncStatus.scrollHeight;
}
document.addEventListener('DOMContentLoaded', function() {
// Initialize WebSocket
function connectWebSocket() {
socket = new WebSocket('wss://your-websocket-server.com/ble-mesh');
socket.onopen = () => {
updateSyncStatus('WebSocket connected');
};
socket.onmessage = (event) => {
updateSyncStatus(`Received data: ${event.data}`);
// Handle incoming sync data
};
socket.onclose = () => {
updateSyncStatus('WebSocket disconnected - attempting reconnect...');
setTimeout(connectWebSocket, 5000);
};
}
connectWebSocket();
// Enhanced device data with metrics
const devices = [
{
id: 'node-042',
type: 'ESP32 Mesh Node',
status: 'active',
lastSeen: new Date().toISOString(),
lastRtt: 24,
aggregated: {
summary: 'Stable connection, low latency',
metrics: {
health: 'ok',
packetLoss: '0.2%',
uptime: '99.8%'
}
}
},
{
id: 'imu-015',
type: 'IMU Sensor',
status: 'active',
lastSeen: new Date(Date.now() - 120000).toISOString(),
lastRtt: 58,
aggregated: {
summary: 'Higher than usual latency',
metrics: {
health: 'warn',
packetLoss: '1.8%',
uptime: '98.1%'
}
}
},
{
id: 'proxy-007',
type: 'GATT Proxy',
status: 'inactive',
lastSeen: new Date(Date.now() - 900000).toISOString(),
lastRtt: null,
aggregated: {
summary: 'Device unreachable',
metrics: {
health: 'critical',
packetLoss: '100%',
uptime: '0%'
}
}
},
{
id: 'gateway-001',
type: 'Manabox Gateway',
status: 'active',
lastSeen: new Date().toISOString(),
lastRtt: 32,
aggregated: {
summary: 'Normal operation',
metrics: {
health: 'ok',
packetLoss: '0.1%',
uptime: '99.9%'
}
}
},
];
// Populate device table
const tableBody = document.getElementById('device-table-body');
devices.forEach(device => {
const row = document.createElement('tr');
row.className = 'border-b border-stone-700 hover:bg-stone-700/50 transition-colors';
const health = device.aggregated?.metrics?.health || '';
const statusClass = health === 'ok' ? 'text-green-400' :
health === 'warn' ? 'text-amber-400' : 'text-red-400';
row.innerHTML = `
<td class="py-3 px-4 font-mono">${device.id}</td>
<td class="py-3 px-4">${device.type}</td>
<td class="py-3 px-4 ${statusClass} flex items-center gap-2">
<span class="h-2 w-2 rounded-full ${health === 'ok' ? 'bg-green-400' :
health === 'warn' ? 'bg-amber-400' : 'bg-red-400'}"></span>
${device.status}
</td>
<td class="py-3 px-4">${new Date(device.lastSeen).toLocaleTimeString()}</td>
<td class="py-3 px-4">${device.lastRtt ? device.lastRtt + 'ms' : '-'}</td>
`;
tableBody.appendChild(row);
});
// Telemetry stream simulation
const telemetryStream = document.getElementById('telemetry-stream');
const startBtn = document.getElementById('start-stream');
const clearBtn = document.getElementById('clear-stream');
let streamInterval;
// Bluetooth sync handler
document.getElementById('sync-bluetooth').addEventListener('click', async () => {
updateSyncStatus('Initiating BLE Mesh sync...');
try {
// Mock BLE sync - in real implementation this would use Web Bluetooth API
updateSyncStatus('Discovering nearby mesh nodes...');
await new Promise(resolve => setTimeout(resolve, 1000));
updateSyncStatus('Connected to 3 mesh nodes');
await new Promise(resolve => setTimeout(resolve, 500));
updateSyncStatus('Syncing configuration data...');
await new Promise(resolve => setTimeout(resolve, 1500));
updateSyncStatus('Sync complete! Updated 12 devices');
} catch (error) {
updateSyncStatus(`BLE Sync failed: ${error.message}`);
}
});
// WebSocket sync handler
document.getElementById('sync-websocket').addEventListener('click', () => {
if (socket.readyState === WebSocket.OPEN) {
updateSyncStatus('Sending sync request via WebSocket...');
socket.send(JSON.stringify({
type: 'sync_request',
devices: devices // Send current device state
}));
} else {
updateSyncStatus('WebSocket not connected - attempting reconnect');
connectWebSocket();
}
});
// Data export handler
document.getElementById('export-data').addEventListener('click', () => {
const config = {
timestamp: new Date().toISOString(),
devices: devices,
settings: {
meshId: 'nexus-glow-001',
networkKey: '********',
appKey: '********'
}
};
const blob = new Blob([JSON.stringify(config, null, 2)], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `ble-mesh-config-${new Date().toISOString().split('T')[0]}.json`;
a.click();
updateSyncStatus('Configuration exported as JSON');
});
startBtn.addEventListener('click', function() {
if (streamInterval) {
clearInterval(streamInterval);
startBtn.innerHTML = '<i data-feather="play"></i> Start Stream';
feather.replace();
return;
}
startBtn.innerHTML = '<i data-feather="pause"></i> Stop Stream';
feather.replace();
streamInterval = setInterval(() => {
const now = new Date();
const timestamp = now.toISOString().replace('T', ' ').substring(0, 19);
const telemetryData = {
timestamp,
device_id: 'node-' + Math.floor(Math.random() * 100).toString().padStart(3, '0'),
accel: {
x: (Math.random() * 2 - 1).toFixed(2),
y: (Math.random() * 2 - 1).toFixed(2),
z: (9.8 + Math.random() * 0.2 - 0.1).toFixed(2)
},
buttons: {
A: Math.random() > 0.7 ? 1 : 0,
B: Math.random() > 0.8 ? 1 : 0,
Guard: Math.random() > 0.9 ? 1 : 0
}
};
const entry = document.createElement('div');
entry.className = 'mb-2 p-3 bg-stone-700/50 rounded-lg font-mono text-sm';
entry.innerHTML = `<span class="text-secondary-500">${timestamp}</span> ${JSON.stringify(telemetryData)}`;
telemetryStream.appendChild(entry);
// Auto-scroll to bottom
telemetryStream.scrollTop = telemetryStream.scrollHeight;
}, 1000);
});
clearBtn.addEventListener('click', function() {
telemetryStream.innerHTML = '';
});
});