Files
tischlerCtrl/uiserver/api/outputs.js
sebseb7 86bea2fa6d u
2025-12-26 01:57:15 +01:00

76 lines
2.6 KiB
JavaScript

/**
* Outputs API - Output channel definitions and values
*/
module.exports = function setupOutputsApi(app, { db, getOutputChannels, getOutputBindings }) {
// GET /api/outputs - List output channel definitions
app.get('/api/outputs', (req, res) => {
res.json(getOutputChannels());
});
// GET /api/outputs/values - Get current output values
app.get('/api/outputs/values', (req, res) => {
try {
if (!db) throw new Error('Database not connected');
const result = {};
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();
rows.forEach(row => {
result[row.channel] = row.value;
});
// Fill in defaults for missing channels
const outputChannels = getOutputChannels();
outputChannels.forEach(ch => {
if (result[ch.channel] === undefined) {
result[ch.channel] = 0;
}
});
res.json(result);
} catch (err) {
res.status(500).json({ error: err.message });
}
});
// 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) => {
try {
if (!db) throw new Error('Database not connected');
// 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();
const outputValues = {};
rows.forEach(row => {
outputValues[row.channel] = row.value;
});
// Map to device commands
const bindings = getOutputBindings();
const commands = {};
for (const [outputChannel, binding] of Object.entries(bindings)) {
const value = outputValues[outputChannel] ?? 0;
const deviceKey = `${binding.device}:${binding.channel}`;
commands[deviceKey] = {
state: value > 0 ? 1 : 0,
source: outputChannel
};
}
res.json(commands);
} catch (err) {
res.status(500).json({ error: err.message });
}
});
};