941abd98d5
Dynamic MySolem/MyIndygo IoT bridge with MQTT, Home Assistant autodiscovery, and Homebridge EasyMQTT compatibility. - Device discovery via MySolem API on startup (all modules/inputs/outputs) - Configurable poll engine (fast/normal/slow buckets, per-input overrides) - MQTT retained state publishing + HA autodiscovery payloads - Unified manual command routing (linesControl vs sendManualModuleCommand) - Runtime config via MQTT $config/set, persisted to config.json - Expression override system (API-provided > hardcoded > passthrough) - Minimal REST API: /health, /state, /control, /rediscover - Docker deployment (Dockerfile + docker-compose.yml) - 38 unit tests Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
57 lines
1.8 KiB
JavaScript
57 lines
1.8 KiB
JavaScript
'use strict';
|
|
const { getClient, getPrefix, publish } = require('./client');
|
|
const { allOutputs } = require('../registry');
|
|
const { sendCommand } = require('../control');
|
|
|
|
function subscribeAll() {
|
|
const client = getClient();
|
|
if (!client) return;
|
|
const prefix = getPrefix();
|
|
|
|
for (const out of allOutputs()) {
|
|
const topic = `${prefix}/${out.moduleSlug}/output/${out.index}/set`;
|
|
client.subscribe(topic);
|
|
}
|
|
|
|
client.on('message', async (topic, buf) => {
|
|
const prefix_ = `${prefix}/`;
|
|
if (!topic.startsWith(prefix_)) return;
|
|
|
|
// Match: {prefix}/{slug}/output/{index}/set
|
|
const parts = topic.slice(prefix_.length).split('/');
|
|
if (parts.length !== 4 || parts[1] !== 'output' || parts[3] !== 'set') return;
|
|
|
|
const [slug, , indexStr] = parts;
|
|
const outputIndex = parseInt(indexStr, 10);
|
|
|
|
let cmd;
|
|
try {
|
|
cmd = JSON.parse(buf.toString());
|
|
} catch {
|
|
console.warn(`[commands] Invalid JSON on ${topic}`);
|
|
return;
|
|
}
|
|
|
|
// Find module by slug
|
|
const output = allOutputs().find(o => o.moduleSlug === slug && o.index === outputIndex);
|
|
if (!output) {
|
|
console.warn(`[commands] No output found for ${slug}/output/${outputIndex}`);
|
|
return;
|
|
}
|
|
|
|
try {
|
|
await sendCommand(output.moduleId, outputIndex, cmd);
|
|
// Reflect running state optimistically
|
|
const stateValue = (cmd.action === 'run' || cmd.action === 'boost') ? 1 : 0;
|
|
publish(`${slug}/output/${outputIndex}/state`, { value: stateValue, ts: new Date().toISOString() });
|
|
console.log(`[commands] ${slug}/output/${outputIndex} → ${cmd.action}`);
|
|
} catch (e) {
|
|
console.error(`[commands] Command failed for ${slug}/output/${outputIndex}:`, e.message);
|
|
}
|
|
});
|
|
|
|
console.log(`[commands] Subscribed to ${allOutputs().length} output set topics`);
|
|
}
|
|
|
|
module.exports = { subscribeAll };
|