u
This commit is contained in:
@@ -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) => {
|
||||
|
||||
Reference in New Issue
Block a user