feat: initial myprimal MQTT bridge service
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>
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
'use strict';
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { EventEmitter } = require('events');
|
||||
|
||||
const CONFIG_PATH = process.env.MYPRIMAL_CONFIG_PATH || path.join(__dirname, '..', 'config.json');
|
||||
|
||||
const DEFAULTS = {
|
||||
poll: {
|
||||
fast: parseInt(process.env.POLL_FAST) || 60,
|
||||
normal: parseInt(process.env.POLL_NORMAL) || 300,
|
||||
slow: parseInt(process.env.POLL_SLOW) || 900,
|
||||
overrides: {},
|
||||
},
|
||||
expressions: {}, // inputId → expression string override, e.g. "value/10"
|
||||
};
|
||||
|
||||
const emitter = new EventEmitter();
|
||||
let _config = deepMerge({}, DEFAULTS);
|
||||
|
||||
function deepMerge(target, source) {
|
||||
for (const key of Object.keys(source || {})) {
|
||||
if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) {
|
||||
target[key] = deepMerge(target[key] || {}, source[key]);
|
||||
} else {
|
||||
target[key] = source[key];
|
||||
}
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
function loadConfig() {
|
||||
if (fs.existsSync(CONFIG_PATH)) {
|
||||
try {
|
||||
const saved = JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf8'));
|
||||
_config = deepMerge(deepMerge({}, DEFAULTS), saved);
|
||||
} catch (e) {
|
||||
console.warn('[config] Failed to parse config.json, using defaults:', e.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function saveConfig() {
|
||||
fs.writeFileSync(CONFIG_PATH, JSON.stringify(_config, null, 2));
|
||||
}
|
||||
|
||||
function getConfig() {
|
||||
return _config;
|
||||
}
|
||||
|
||||
function patchConfig(patch) {
|
||||
_config = deepMerge(_config, patch);
|
||||
saveConfig();
|
||||
emitter.emit('change', _config);
|
||||
}
|
||||
|
||||
module.exports = { loadConfig, getConfig, patchConfig, on: emitter.on.bind(emitter) };
|
||||
Reference in New Issue
Block a user