Initial release — Dibby Wemo Manager v2.0.0

Desktop (Electron/Windows): device dashboard, DWM scheduling engine,
native firmware rules editor, Windows background service, web remote,
sunrise/sunset support.

Homebridge plugin (homebridge-dibby-wemo v1.0.0): HomeKit switches for
all local Wemo devices, custom UI with DWM rules, device rules,
scheduler heartbeat, and location-based sunrise/sunset scheduling.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
SRS IT
2026-03-28 16:30:43 -04:00
commit 27be1892ed
75 changed files with 14322 additions and 0 deletions
+118
View File
@@ -0,0 +1,118 @@
'use strict';
/**
* DWM Store — Homebridge edition.
*
* Stores devices, DWM rules, and location in a single JSON file inside
* Homebridge's storagePath (passed in at construction time, not via Electron).
*
* Schema mirrors the desktop store exactly so DWM rules created in the desktop
* app can be imported / shared.
*/
const path = require('path');
const fs = require('fs');
const DEFAULTS = {
location: null,
devices: [],
deviceGroups: [],
deviceOrder: [],
disabledRules: {},
dwmRules: [],
schedulerHeartbeat: null,
};
class DwmStore {
constructor(storagePath) {
this._filePath = path.join(storagePath, 'dibby-wemo.json');
}
// ── Internal I/O ──────────────────────────────────────────────────────────
_load() {
try {
return { ...DEFAULTS, ...JSON.parse(fs.readFileSync(this._filePath, 'utf8')) };
} catch {
return { ...DEFAULTS };
}
}
_save(data) {
fs.writeFileSync(this._filePath, JSON.stringify(data, null, 2), 'utf8');
}
// ── Location ──────────────────────────────────────────────────────────────
getLocation() { return this._load().location; }
setLocation(loc) { const d = this._load(); d.location = loc; this._save(d); }
// ── Devices ───────────────────────────────────────────────────────────────
getDevices() { return this._load().devices ?? []; }
saveDevices(list) { const d = this._load(); d.devices = list; this._save(d); }
getDeviceOrder() { return this._load().deviceOrder ?? []; }
saveDeviceOrder(order) { const d = this._load(); d.deviceOrder = order; this._save(d); }
getDeviceGroups() { return this._load().deviceGroups ?? []; }
saveDeviceGroups(groups) { const d = this._load(); d.deviceGroups = groups; this._save(d); }
// ── Disabled-rule backups ─────────────────────────────────────────────────
getDisabledRules() { return this._load().disabledRules ?? {}; }
setDisabledRule(key, ruleDevicesRows) {
const d = this._load();
if (!d.disabledRules) d.disabledRules = {};
d.disabledRules[key] = ruleDevicesRows;
this._save(d);
}
clearDisabledRule(key) {
const d = this._load();
if (!d.disabledRules) return;
delete d.disabledRules[key];
this._save(d);
}
// ── DWM Rules ─────────────────────────────────────────────────────────────
getDwmRules() { return this._load().dwmRules ?? []; }
createDwmRule(rule) {
const d = this._load();
if (!d.dwmRules) d.dwmRules = [];
const id = `dwm-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;
const now = new Date().toISOString();
const newRule = { ...rule, id, createdAt: now, updatedAt: now };
d.dwmRules.push(newRule);
this._save(d);
return newRule;
}
updateDwmRule(id, updates) {
const d = this._load();
if (!d.dwmRules) d.dwmRules = [];
const idx = d.dwmRules.findIndex((r) => r.id === id);
if (idx === -1) throw new Error(`DWM rule not found: ${id}`);
d.dwmRules[idx] = { ...d.dwmRules[idx], ...updates, id, updatedAt: new Date().toISOString() };
this._save(d);
return d.dwmRules[idx];
}
deleteDwmRule(id) {
const d = this._load();
if (!d.dwmRules) return;
d.dwmRules = d.dwmRules.filter((r) => r.id !== id);
this._save(d);
}
// ── Scheduler heartbeat ───────────────────────────────────────────────────
getHeartbeat() { return this._load().schedulerHeartbeat ?? null; }
saveHeartbeat(hb) {
const d = this._load();
d.schedulerHeartbeat = { ...hb, ts: new Date().toISOString() };
this._save(d);
}
}
module.exports = DwmStore;