This commit is contained in:
sebseb7
2025-12-25 04:20:40 +01:00
parent 9db13f3589
commit ebfc848c82

View File

@@ -22,6 +22,13 @@ try {
console.error(`[UI Server] Failed to connect to database at ${dbPath}:`, err.message);
}
// Output bindings: map virtual outputs to physical devices
// Format: outputChannel -> { device, channel, type }
const OUTPUT_BINDINGS = {
'BigDehumid': { device: 'tapo', channel: 'r0', type: 'switch' },
'CO2Valve': { device: 'tapo', channel: 'c', type: 'switch' },
};
// =============================================
// WebSocket Server for Agents (port 3962)
// =============================================
@@ -217,6 +224,11 @@ function handleAgentMessage(ws, message, clientState, clientId) {
ws.send(JSON.stringify({ type: 'auth', success: true, devicePrefix: keyInfo.device_prefix, name: keyInfo.name }));
break;
case 'pong':
// Keepalive from agent - just update timestamp
clientState.lastPong = Date.now();
break;
case 'data':
if (!clientState.authenticated) {
ws.send(JSON.stringify({ type: 'error', error: 'Not authenticated' }));
@@ -266,6 +278,45 @@ function sendCommandToDevicePrefix(devicePrefix, command) {
return sent > 0;
}
// Periodic sync: push non-zero output states to agents every 60s
function syncOutputStates() {
if (!db) return;
try {
// Get current output values
const stmt = db.prepare(`
SELECT channel, value FROM output_events
WHERE id IN (SELECT MAX(id) FROM output_events GROUP BY channel)
`);
const rows = stmt.all();
for (const row of rows) {
// Only sync non-zero values
if (row.value > 0) {
const binding = OUTPUT_BINDINGS[row.channel];
if (binding) {
const success = sendCommandToDevicePrefix(`${binding.device}:`, {
device: binding.channel,
action: 'set_state',
value: 1
});
if (!success) {
console.error(`[Sync] ERROR: Cannot deliver 'on' command for ${row.channel} -> ${binding.device}:${binding.channel} (no agent connected)`);
}
}
}
}
} catch (err) {
console.error('[Sync] Error syncing output states:', err.message);
}
}
// Start output state sync interval (every 60s)
setInterval(syncOutputStates, 60000);
// Also sync immediately on startup after a short delay
setTimeout(syncOutputStates, 5000);
// Start the WebSocket server
const agentWss = createAgentWebSocketServer();
@@ -515,13 +566,6 @@ module.exports = {
}
});
// Output bindings: map virtual outputs to physical devices
// Format: outputChannel -> { device, channel, type }
const OUTPUT_BINDINGS = {
'BigDehumid': { device: 'tapo', channel: 'r0', type: 'switch' },
'CO2Valve': { device: 'tapo', channel: 'c', type: 'switch' },
};
// GET /api/outputs/commands - Get desired states for bound devices
// Agents poll this to get commands. Returns { "device:channel": { state: 0|1 } }
app.get('/api/outputs/commands', (req, res) => {