@ecopoesis/homebridge-dmx 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +18 -3
- package/dist/config.d.ts +17 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +42 -0
- package/dist/config.js.map +1 -1
- package/dist/platform.d.ts +1 -0
- package/dist/platform.d.ts.map +1 -1
- package/dist/platform.js +26 -3
- package/dist/platform.js.map +1 -1
- package/dist/platformAccessory.d.ts +5 -5
- package/dist/platformAccessory.d.ts.map +1 -1
- package/dist/platformAccessory.js +58 -29
- package/dist/platformAccessory.js.map +1 -1
- package/dist/stateRegistry.d.ts +21 -0
- package/dist/stateRegistry.d.ts.map +1 -0
- package/dist/stateRegistry.js +65 -0
- package/dist/stateRegistry.js.map +1 -0
- package/dist/zoneAccessory.d.ts +30 -0
- package/dist/zoneAccessory.d.ts.map +1 -0
- package/dist/zoneAccessory.js +148 -0
- package/dist/zoneAccessory.js.map +1 -0
- package/package.json +1 -1
- package/src/config.ts +61 -1
- package/src/platform.ts +26 -3
- package/src/platformAccessory.ts +53 -31
- package/src/stateRegistry.ts +71 -0
- package/src/zoneAccessory.ts +170 -0
package/CLAUDE.md
CHANGED
|
@@ -1,8 +1,23 @@
|
|
|
1
|
-
# homebridge-
|
|
1
|
+
# @ecopoesis/homebridge-dmx
|
|
2
2
|
|
|
3
|
-
Homebridge plugin
|
|
3
|
+
Homebridge platform plugin that exposes DMX fixtures as HomeKit Lightbulb accessories. The DMX controller is abstracted (config has a `controllers[]` section + `type` field) so additional controllers can be added later without rewriting the patch; the supported controller today is the **Nicolaudie Stick-DE3**, reverse-engineered from the ESA2 Hardware Manager.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Published to npm as **`@ecopoesis/homebridge-dmx`** (scoped because the unscoped `homebridge-dmx` is squatted on npm by an abandoned 2019 package). Homebridge alias is `DMX`.
|
|
6
|
+
|
|
7
|
+
## Plugin architecture (2026-05-24)
|
|
8
|
+
|
|
9
|
+
- Top-level platform `DmxPlatform` reads `controllers[]`, `profiles[]`, `patch[]` from config (or external YAML via `yamlPath`)
|
|
10
|
+
- One `StickController` per controller spec; one `StickFixture` (Lightbulb accessory) per patch entry, wired to its controller
|
|
11
|
+
- HomeKit set → render bytes via the fixture's color model → write to universe buffer → debounce (750 ms) → spawn `tools/send_dmx.mjs` as a child process per transaction
|
|
12
|
+
- Subprocess approach: empirical workaround — in-process protocol only works for the FIRST transaction per long-lived plugin process; sessions 2+ silently fail to drive output. Fresh node process per transaction reliably works. Cost: ~1.5-2 s per change.
|
|
13
|
+
- Color models: dimmer, cct, rgb, rgbw, rgbww, rgbaw, hsvcct (the WAC native model)
|
|
14
|
+
- `tools/send_dmx.mjs` is now structurally critical (frozen reference shipped in the npm tarball)
|
|
15
|
+
|
|
16
|
+
## Current deployment
|
|
17
|
+
|
|
18
|
+
Running on `homebridge01.local` (192.168.16.40) in a `homebridge/homebridge:latest` docker container managed by Portainer + Watchtower. Config volume bind-mounted at `/opt/containers/homebridge` → `/homebridge` inside the container. All 18 WAC fixtures patched at universe A, DMX 1/6/11/.../86.
|
|
19
|
+
|
|
20
|
+
## Architecture (RE / hardware context)
|
|
6
21
|
|
|
7
22
|
- 18x WAC DC-WD05 fixtures on a DMX chain
|
|
8
23
|
- Nicolaudie Stick-DE3 wall-mount DMX controller at 192.168.96.2
|
package/dist/config.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ChannelDef, ColorModel } from './color/types.js';
|
|
1
|
+
import { ChannelDef, ColorModel, HKCharacteristic } from './color/types.js';
|
|
2
2
|
export interface ControllerSpec {
|
|
3
3
|
id: string;
|
|
4
4
|
type: string;
|
|
@@ -17,12 +17,18 @@ export interface PatchSpec {
|
|
|
17
17
|
universe?: string;
|
|
18
18
|
start: number;
|
|
19
19
|
}
|
|
20
|
+
export interface ZoneSpec {
|
|
21
|
+
id: string;
|
|
22
|
+
name: string;
|
|
23
|
+
members: string[];
|
|
24
|
+
}
|
|
20
25
|
export interface RawConfig {
|
|
21
26
|
name?: string;
|
|
22
27
|
yamlPath?: string;
|
|
23
28
|
controllers?: ControllerSpec[];
|
|
24
29
|
profiles?: ProfileSpec[];
|
|
25
30
|
patch?: PatchSpec[];
|
|
31
|
+
zones?: ZoneSpec[];
|
|
26
32
|
}
|
|
27
33
|
export interface Profile {
|
|
28
34
|
name: string;
|
|
@@ -45,10 +51,20 @@ export interface Fixture {
|
|
|
45
51
|
startCh: number;
|
|
46
52
|
nChannels: number;
|
|
47
53
|
}
|
|
54
|
+
/** A virtual "zone" Lightbulb: appears as a single accessory in HomeKit;
|
|
55
|
+
* setting its state dispatches to every member fixture. The intersection
|
|
56
|
+
* of the members' color-model characteristics is what HomeKit sees. */
|
|
57
|
+
export interface Zone {
|
|
58
|
+
id: string;
|
|
59
|
+
name: string;
|
|
60
|
+
members: Fixture[];
|
|
61
|
+
characteristics: HKCharacteristic[];
|
|
62
|
+
}
|
|
48
63
|
export interface LoadedConfig {
|
|
49
64
|
name: string;
|
|
50
65
|
controllers: Controller[];
|
|
51
66
|
fixtures: Fixture[];
|
|
67
|
+
zones: Zone[];
|
|
52
68
|
}
|
|
53
69
|
export declare const DEFAULT_PLATFORM_NAME = "DMX";
|
|
54
70
|
/** Load + validate the platform config. `rawJson` is the Homebridge
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAuCA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAuCA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAI5E,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,cAAc,EAAE,CAAC;IAC/B,QAAQ,CAAC,EAAE,WAAW,EAAE,CAAC;IACzB,KAAK,CAAC,EAAE,SAAS,EAAE,CAAC;IACpB,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,UAAU,CAAC;IAClB,QAAQ,EAAE,UAAU,EAAE,CAAC;CACxB;AAED,eAAO,MAAM,gBAAgB,uBAAwB,CAAC;AACtD,MAAM,MAAM,cAAc,GAAG,OAAO,gBAAgB,CAAC,MAAM,CAAC,CAAC;AAE7D,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,cAAc,CAAC;IACrB,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,UAAU,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;wEAEwE;AACxE,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,EAAE,CAAC;IACnB,eAAe,EAAE,gBAAgB,EAAE,CAAC;CACrC;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,KAAK,EAAE,IAAI,EAAE,CAAC;CACf;AAED,eAAO,MAAM,qBAAqB,QAAQ,CAAC;AAE3C;;;;oEAIoE;AACpE,wBAAgB,UAAU,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,YAAY,CAmLzE"}
|
package/dist/config.js
CHANGED
|
@@ -182,10 +182,52 @@ export function loadConfig(rawJson, cwd) {
|
|
|
182
182
|
nChannels: nch,
|
|
183
183
|
});
|
|
184
184
|
}
|
|
185
|
+
// Zones — virtual Lightbulb accessories. Each zone's members must be
|
|
186
|
+
// existing fixture ids. Zones never reference other zones (no recursion).
|
|
187
|
+
const fixturesById = new Map(fixtures.map((f) => [f.id, f]));
|
|
188
|
+
const zoneSpecs = raw.zones ?? [];
|
|
189
|
+
const zones = [];
|
|
190
|
+
const seenZoneIds = new Set();
|
|
191
|
+
for (const zs of zoneSpecs) {
|
|
192
|
+
if (!zs.id)
|
|
193
|
+
throw new Error('zone: missing id');
|
|
194
|
+
if (seenZoneIds.has(zs.id)) {
|
|
195
|
+
throw new Error(`zone: duplicate id "${zs.id}"`);
|
|
196
|
+
}
|
|
197
|
+
if (fixturesById.has(zs.id)) {
|
|
198
|
+
throw new Error(`zone id "${zs.id}" collides with fixture id`);
|
|
199
|
+
}
|
|
200
|
+
seenZoneIds.add(zs.id);
|
|
201
|
+
if (!Array.isArray(zs.members) || zs.members.length === 0) {
|
|
202
|
+
throw new Error(`zone "${zs.id}": members must be a non-empty array of fixture ids`);
|
|
203
|
+
}
|
|
204
|
+
const members = [];
|
|
205
|
+
for (const m of zs.members) {
|
|
206
|
+
const fx = fixturesById.get(m);
|
|
207
|
+
if (!fx) {
|
|
208
|
+
throw new Error(`zone "${zs.id}": unknown fixture "${m}"`);
|
|
209
|
+
}
|
|
210
|
+
members.push(fx);
|
|
211
|
+
}
|
|
212
|
+
// Intersection of member characteristics — HomeKit only exposes what
|
|
213
|
+
// ALL members can do.
|
|
214
|
+
let chars = new Set(members[0].profile.model.characteristics);
|
|
215
|
+
for (let i = 1; i < members.length; i++) {
|
|
216
|
+
const mc = new Set(members[i].profile.model.characteristics);
|
|
217
|
+
chars = new Set([...chars].filter((c) => mc.has(c)));
|
|
218
|
+
}
|
|
219
|
+
zones.push({
|
|
220
|
+
id: zs.id,
|
|
221
|
+
name: zs.name || zs.id,
|
|
222
|
+
members,
|
|
223
|
+
characteristics: [...chars],
|
|
224
|
+
});
|
|
225
|
+
}
|
|
185
226
|
return {
|
|
186
227
|
name: raw.name ?? DEFAULT_PLATFORM_NAME,
|
|
187
228
|
controllers: [...controllersById.values()],
|
|
188
229
|
fixtures,
|
|
230
|
+
zones,
|
|
189
231
|
};
|
|
190
232
|
}
|
|
191
233
|
//# sourceMappingURL=config.js.map
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,6BAA6B;AAC7B,EAAE;AACF,UAAU;AACV,mEAAmE;AACnE,uEAAuE;AACvE,oDAAoD;AACpD,mDAAmD;AACnD,EAAE;AACF,SAAS;AACT,MAAM;AACN,yBAAyB;AACzB,qBAAqB;AACrB,gDAAgD;AAChD,uBAAuB;AACvB,mEAAmE;AACnE,SAAS;AACT,oBAAoB;AACpB,iDAAiD;AACjD,6DAA6D;AAC7D,0EAA0E;AAC1E,SAAS;AACT,iBAAiB;AACjB,2DAA2D;AAC3D,8DAA8D;AAC9D,QAAQ;AACR,MAAM;AACN,EAAE;AACF,wEAAwE;AACxE,0DAA0D;AAC1D,2EAA2E;AAC3E,6BAA6B;AAC7B,wEAAwE;AACxE,0EAA0E;AAC1E,qCAAqC;AAErC,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,IAAI,MAAM,SAAS,CAAC;AAG3B,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/platform.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export declare class DmxPlatform implements DynamicPlatformPlugin {
|
|
|
8
8
|
readonly accessories: PlatformAccessory[];
|
|
9
9
|
private cfg;
|
|
10
10
|
private controllers;
|
|
11
|
+
private registry;
|
|
11
12
|
constructor(log: Logger, config: PlatformConfig, api: API);
|
|
12
13
|
private makeController;
|
|
13
14
|
/** Called by Homebridge for each cached accessory at startup. */
|
package/dist/platform.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACV,GAAG,EACH,cAAc,EACd,qBAAqB,EACrB,MAAM,EACN,iBAAiB,EACjB,cAAc,EACd,OAAO,EACR,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACV,GAAG,EACH,cAAc,EACd,qBAAqB,EACrB,MAAM,EACN,iBAAiB,EACjB,cAAc,EACd,OAAO,EACR,MAAM,YAAY,CAAC;AASpB,qBAAa,WAAY,YAAW,qBAAqB;aAUrC,GAAG,EAAE,MAAM;aACX,MAAM,EAAE,cAAc;aACtB,GAAG,EAAE,GAAG;IAX1B,SAAgB,OAAO,EAAE,OAAO,OAAO,CAAC;IACxC,SAAgB,cAAc,EAAE,OAAO,cAAc,CAAC;IACtD,SAAgB,WAAW,EAAE,iBAAiB,EAAE,CAAM;IAEtD,OAAO,CAAC,GAAG,CAA6B;IACxC,OAAO,CAAC,WAAW,CAAsC;IACzD,OAAO,CAAC,QAAQ,CAAuB;gBAGrB,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,cAAc,EACtB,GAAG,EAAE,GAAG;IAgC1B,OAAO,CAAC,cAAc;IAStB,iEAAiE;IACjE,kBAAkB,CAAC,SAAS,EAAE,iBAAiB,GAAG,IAAI;IAKtD,OAAO,CAAC,eAAe;CA0DxB"}
|
package/dist/platform.js
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
import { loadConfig } from './config.js';
|
|
7
7
|
import { StickController } from './controller.js';
|
|
8
8
|
import { StickFixture } from './platformAccessory.js';
|
|
9
|
+
import { StateRegistry } from './stateRegistry.js';
|
|
10
|
+
import { ZoneFixture } from './zoneAccessory.js';
|
|
9
11
|
import { PLATFORM_NAME, PLUGIN_NAME } from './settings.js';
|
|
10
12
|
export class DmxPlatform {
|
|
11
13
|
log;
|
|
@@ -16,6 +18,7 @@ export class DmxPlatform {
|
|
|
16
18
|
accessories = [];
|
|
17
19
|
cfg = null;
|
|
18
20
|
controllers = new Map();
|
|
21
|
+
registry = new StateRegistry();
|
|
19
22
|
constructor(log, config, api) {
|
|
20
23
|
this.log = log;
|
|
21
24
|
this.config = config;
|
|
@@ -34,7 +37,8 @@ export class DmxPlatform {
|
|
|
34
37
|
}
|
|
35
38
|
this.log.info(`DMX platform configured: ${this.cfg.controllers.length} controller` +
|
|
36
39
|
`${this.cfg.controllers.length === 1 ? '' : 's'}, ` +
|
|
37
|
-
`${this.cfg.fixtures.length} fixture${this.cfg.fixtures.length === 1 ? '' : 's'}`
|
|
40
|
+
`${this.cfg.fixtures.length} fixture${this.cfg.fixtures.length === 1 ? '' : 's'}, ` +
|
|
41
|
+
`${this.cfg.zones.length} zone${this.cfg.zones.length === 1 ? '' : 's'}`);
|
|
38
42
|
this.api.on('didFinishLaunching', () => this.discoverDevices());
|
|
39
43
|
this.api.on('shutdown', () => {
|
|
40
44
|
for (const c of this.controllers.values())
|
|
@@ -70,13 +74,32 @@ export class DmxPlatform {
|
|
|
70
74
|
if (existing) {
|
|
71
75
|
this.log.debug(`wiring cached accessory ${fx.id}`);
|
|
72
76
|
existing.context.fixture = { id: fx.id, controllerId: fx.controller.id };
|
|
73
|
-
new StickFixture(this, existing, fx, controller);
|
|
77
|
+
new StickFixture(this, existing, fx, controller, this.registry);
|
|
74
78
|
}
|
|
75
79
|
else {
|
|
76
80
|
this.log.info(`registering new accessory: ${fx.name} (${fx.id})`);
|
|
77
81
|
const accessory = new this.api.platformAccessory(fx.name, uuid);
|
|
78
82
|
accessory.context.fixture = { id: fx.id, controllerId: fx.controller.id };
|
|
79
|
-
new StickFixture(this, accessory, fx, controller);
|
|
83
|
+
new StickFixture(this, accessory, fx, controller, this.registry);
|
|
84
|
+
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
|
|
85
|
+
this.accessories.push(accessory);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// Zones — virtual accessories that dispatch to their member fixtures.
|
|
89
|
+
for (const zone of this.cfg.zones) {
|
|
90
|
+
const uuid = this.api.hap.uuid.generate(`dmx-zone:${zone.id}`);
|
|
91
|
+
wantUuids.add(uuid);
|
|
92
|
+
const existing = this.accessories.find((a) => a.UUID === uuid);
|
|
93
|
+
if (existing) {
|
|
94
|
+
this.log.debug(`wiring cached zone ${zone.id}`);
|
|
95
|
+
existing.context.zone = { id: zone.id };
|
|
96
|
+
new ZoneFixture(this, existing, zone, this.controllers, this.registry);
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
this.log.info(`registering new zone: ${zone.name} (${zone.id}, ${zone.members.length} members)`);
|
|
100
|
+
const accessory = new this.api.platformAccessory(zone.name, uuid);
|
|
101
|
+
accessory.context.zone = { id: zone.id };
|
|
102
|
+
new ZoneFixture(this, accessory, zone, this.controllers, this.registry);
|
|
80
103
|
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
|
|
81
104
|
this.accessories.push(accessory);
|
|
82
105
|
}
|
package/dist/platform.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"platform.js","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"AAAA,wDAAwD;AACxD,EAAE;AACF,0EAA0E;AAC1E,2EAA2E;AAC3E,kBAAkB;AAYlB,OAAO,EAA4B,UAAU,EAAa,MAAM,aAAa,CAAC;AAC9E,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE3D,MAAM,OAAO,WAAW;
|
|
1
|
+
{"version":3,"file":"platform.js","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,17 +2,17 @@ import type { PlatformAccessory } from 'homebridge';
|
|
|
2
2
|
import { Fixture } from './config.js';
|
|
3
3
|
import { StickController } from './controller.js';
|
|
4
4
|
import type { DmxPlatform } from './platform.js';
|
|
5
|
+
import { StateRegistry } from './stateRegistry.js';
|
|
5
6
|
export declare class StickFixture {
|
|
6
7
|
private readonly platform;
|
|
7
8
|
private readonly accessory;
|
|
8
9
|
private readonly fixture;
|
|
9
10
|
private readonly controller;
|
|
10
|
-
|
|
11
|
-
private state;
|
|
12
|
-
/** Debounce timer for HomeKit's multi-characteristic dispatch
|
|
13
|
-
* (Hue/Saturation/Brightness arrive as 3 separate set calls). */
|
|
11
|
+
private readonly registry;
|
|
14
12
|
private pending;
|
|
15
|
-
|
|
13
|
+
private bulb;
|
|
14
|
+
constructor(platform: DmxPlatform, accessory: PlatformAccessory, fixture: Fixture, controller: StickController, registry: StateRegistry);
|
|
15
|
+
private pushFromRegistry;
|
|
16
16
|
private schedule;
|
|
17
17
|
}
|
|
18
18
|
//# sourceMappingURL=platformAccessory.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"platformAccessory.d.ts","sourceRoot":"","sources":["../src/platformAccessory.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"platformAccessory.d.ts","sourceRoot":"","sources":["../src/platformAccessory.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAEV,iBAAiB,EAElB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAEtC,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD,qBAAa,YAAY;IAKrB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAR3B,OAAO,CAAC,OAAO,CAA+B;IAC9C,OAAO,CAAC,IAAI,CAAU;gBAGH,QAAQ,EAAE,WAAW,EACrB,SAAS,EAAE,iBAAiB,EAC5B,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,eAAe,EAC3B,QAAQ,EAAE,aAAa;IAoE1C,OAAO,CAAC,gBAAgB;IAaxB,OAAO,CAAC,QAAQ;CAcjB"}
|
|
@@ -1,80 +1,109 @@
|
|
|
1
1
|
// StickFixture — one HomeKit Lightbulb accessory per patched fixture.
|
|
2
|
+
//
|
|
3
|
+
// State is owned by the platform-wide StateRegistry. We read on .onGet,
|
|
4
|
+
// write on .onSet, and subscribe to changes so the HomeKit-displayed
|
|
5
|
+
// values track the registry (e.g. when a zone updates this fixture).
|
|
2
6
|
import { CHARACTERISTIC_UPDATE_DELAY_MS } from './settings.js';
|
|
3
7
|
export class StickFixture {
|
|
4
8
|
platform;
|
|
5
9
|
accessory;
|
|
6
10
|
fixture;
|
|
7
11
|
controller;
|
|
8
|
-
|
|
9
|
-
state = { on: false, brightness: 100 };
|
|
10
|
-
/** Debounce timer for HomeKit's multi-characteristic dispatch
|
|
11
|
-
* (Hue/Saturation/Brightness arrive as 3 separate set calls). */
|
|
12
|
+
registry;
|
|
12
13
|
pending = null;
|
|
13
|
-
|
|
14
|
+
bulb;
|
|
15
|
+
constructor(platform, accessory, fixture, controller, registry) {
|
|
14
16
|
this.platform = platform;
|
|
15
17
|
this.accessory = accessory;
|
|
16
18
|
this.fixture = fixture;
|
|
17
19
|
this.controller = controller;
|
|
20
|
+
this.registry = registry;
|
|
18
21
|
const C = platform.Characteristic;
|
|
19
22
|
const info = accessory.getService(platform.Service.AccessoryInformation);
|
|
20
23
|
info?.setCharacteristic(C.Manufacturer, 'Stick-DE3 DMX')
|
|
21
24
|
?.setCharacteristic(C.Model, fixture.profile.name)
|
|
22
25
|
?.setCharacteristic(C.SerialNumber, fixture.id);
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
+
this.bulb =
|
|
27
|
+
accessory.getService(platform.Service.Lightbulb)
|
|
28
|
+
?? accessory.addService(platform.Service.Lightbulb, fixture.name);
|
|
29
|
+
this.bulb.setCharacteristic(C.Name, fixture.name);
|
|
26
30
|
const chars = fixture.profile.model.characteristics;
|
|
27
|
-
bulb.getCharacteristic(C.On)
|
|
28
|
-
.onGet(() =>
|
|
29
|
-
.onSet((v) => {
|
|
31
|
+
this.bulb.getCharacteristic(C.On)
|
|
32
|
+
.onGet(() => registry.get(fixture.id).on)
|
|
33
|
+
.onSet((v) => {
|
|
34
|
+
registry.update(fixture.id, { on: Boolean(v) });
|
|
35
|
+
this.schedule();
|
|
36
|
+
});
|
|
30
37
|
if (chars.includes('Brightness')) {
|
|
31
|
-
bulb.getCharacteristic(C.Brightness)
|
|
32
|
-
.onGet(() =>
|
|
38
|
+
this.bulb.getCharacteristic(C.Brightness)
|
|
39
|
+
.onGet(() => registry.get(fixture.id).brightness)
|
|
33
40
|
.onSet((v) => {
|
|
34
|
-
|
|
41
|
+
registry.update(fixture.id, { brightness: Number(v) });
|
|
35
42
|
this.schedule();
|
|
36
43
|
});
|
|
37
44
|
}
|
|
38
45
|
if (chars.includes('Hue')) {
|
|
39
|
-
bulb.getCharacteristic(C.Hue)
|
|
40
|
-
.onGet(() =>
|
|
46
|
+
this.bulb.getCharacteristic(C.Hue)
|
|
47
|
+
.onGet(() => registry.get(fixture.id).hue ?? 0)
|
|
41
48
|
.onSet((v) => {
|
|
42
|
-
|
|
43
|
-
// setting hue implies color mode (sat>0); leave saturation as-is
|
|
49
|
+
registry.update(fixture.id, { hue: Number(v) });
|
|
44
50
|
this.schedule();
|
|
45
51
|
});
|
|
46
52
|
}
|
|
47
53
|
if (chars.includes('Saturation')) {
|
|
48
|
-
bulb.getCharacteristic(C.Saturation)
|
|
49
|
-
.onGet(() =>
|
|
54
|
+
this.bulb.getCharacteristic(C.Saturation)
|
|
55
|
+
.onGet(() => registry.get(fixture.id).saturation ?? 0)
|
|
50
56
|
.onSet((v) => {
|
|
51
|
-
|
|
57
|
+
registry.update(fixture.id, { saturation: Number(v) });
|
|
52
58
|
this.schedule();
|
|
53
59
|
});
|
|
54
60
|
}
|
|
55
61
|
if (chars.includes('ColorTemperature')) {
|
|
56
|
-
bulb.getCharacteristic(C.ColorTemperature)
|
|
57
|
-
.onGet(() =>
|
|
62
|
+
this.bulb.getCharacteristic(C.ColorTemperature)
|
|
63
|
+
.onGet(() => registry.get(fixture.id).colorTemperatureMireds ?? 200)
|
|
58
64
|
.onSet((v) => {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
65
|
+
// CCT change implies white mode; zero saturation.
|
|
66
|
+
registry.update(fixture.id, {
|
|
67
|
+
colorTemperatureMireds: Number(v),
|
|
68
|
+
saturation: 0,
|
|
69
|
+
});
|
|
63
70
|
this.schedule();
|
|
64
71
|
});
|
|
65
72
|
}
|
|
73
|
+
// Refresh HomeKit characteristics whenever this fixture's state changes
|
|
74
|
+
// in the registry (e.g. via a zone set, or another channel of itself).
|
|
75
|
+
registry.onChange((changedId) => {
|
|
76
|
+
if (changedId !== fixture.id)
|
|
77
|
+
return;
|
|
78
|
+
this.pushFromRegistry();
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
pushFromRegistry() {
|
|
82
|
+
const s = this.registry.get(this.fixture.id);
|
|
83
|
+
const C = this.platform.Characteristic;
|
|
84
|
+
const chars = this.fixture.profile.model.characteristics;
|
|
85
|
+
this.bulb.updateCharacteristic(C.On, s.on);
|
|
86
|
+
if (chars.includes('Brightness'))
|
|
87
|
+
this.bulb.updateCharacteristic(C.Brightness, s.brightness);
|
|
88
|
+
if (chars.includes('Hue') && s.hue != null)
|
|
89
|
+
this.bulb.updateCharacteristic(C.Hue, s.hue);
|
|
90
|
+
if (chars.includes('Saturation') && s.saturation != null)
|
|
91
|
+
this.bulb.updateCharacteristic(C.Saturation, s.saturation);
|
|
92
|
+
if (chars.includes('ColorTemperature') && s.colorTemperatureMireds != null) {
|
|
93
|
+
this.bulb.updateCharacteristic(C.ColorTemperature, s.colorTemperatureMireds);
|
|
94
|
+
}
|
|
66
95
|
}
|
|
67
96
|
schedule() {
|
|
68
97
|
if (this.pending)
|
|
69
98
|
clearTimeout(this.pending);
|
|
70
99
|
this.pending = setTimeout(() => {
|
|
71
100
|
this.pending = null;
|
|
72
|
-
const s = this.
|
|
101
|
+
const s = this.registry.get(this.fixture.id);
|
|
73
102
|
this.platform.log.info(`[${this.fixture.id}] HK set: on=${s.on} br=${s.brightness}` +
|
|
74
103
|
(s.hue != null ? ` h=${s.hue}` : '') +
|
|
75
104
|
(s.saturation != null ? ` s=${s.saturation}` : '') +
|
|
76
105
|
(s.colorTemperatureMireds != null ? ` ct=${s.colorTemperatureMireds}` : ''));
|
|
77
|
-
this.controller.setFixture(this.fixture,
|
|
106
|
+
this.controller.setFixture(this.fixture, s);
|
|
78
107
|
}, CHARACTERISTIC_UPDATE_DELAY_MS);
|
|
79
108
|
}
|
|
80
109
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"platformAccessory.js","sourceRoot":"","sources":["../src/platformAccessory.ts"],"names":[],"mappings":"AAAA,sEAAsE;
|
|
1
|
+
{"version":3,"file":"platformAccessory.js","sourceRoot":"","sources":["../src/platformAccessory.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,EAAE;AACF,wEAAwE;AACxE,qEAAqE;AACrE,qEAAqE;AAYrE,OAAO,EAAE,8BAA8B,EAAE,MAAM,eAAe,CAAC;AAG/D,MAAM,OAAO,YAAY;IAKJ;IACA;IACA;IACA;IACA;IARX,OAAO,GAA0B,IAAI,CAAC;IACtC,IAAI,CAAU;IAEtB,YACmB,QAAqB,EACrB,SAA4B,EAC5B,OAAgB,EAChB,UAA2B,EAC3B,QAAuB;QAJvB,aAAQ,GAAR,QAAQ,CAAa;QACrB,cAAS,GAAT,SAAS,CAAmB;QAC5B,YAAO,GAAP,OAAO,CAAS;QAChB,eAAU,GAAV,UAAU,CAAiB;QAC3B,aAAQ,GAAR,QAAQ,CAAe;QAExC,MAAM,CAAC,GAAG,QAAQ,CAAC,cAAc,CAAC;QAClC,MAAM,IAAI,GAAG,SAAS,CAAC,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC;QACzE,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,YAAY,EAAE,eAAe,CAAC;YACpD,EAAE,iBAAiB,CAAC,CAAC,CAAC,KAAK,EAAE,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC;YAClD,EAAE,iBAAiB,CAAC,CAAC,CAAC,YAAY,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;QAEpD,IAAI,CAAC,IAAI;YACP,SAAS,CAAC,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC;mBAC7C,SAAS,CAAC,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;QAEpE,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;QAElD,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC;QAEpD,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,CAAC;aAC9B,KAAK,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;aACxC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;YACX,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAChD,IAAI,CAAC,QAAQ,EAAE,CAAC;QAClB,CAAC,CAAC,CAAC;QAEL,IAAI,KAAK,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;YACjC,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC,UAAU,CAAC;iBACtC,KAAK,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC;iBAChD,KAAK,CAAC,CAAC,CAAsB,EAAE,EAAE;gBAChC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;gBACvD,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,CAAC,CAAC,CAAC;QACP,CAAC;QACD,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YAC1B,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC,GAAG,CAAC;iBAC/B,KAAK,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;iBAC9C,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;gBACX,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;gBAChD,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,CAAC,CAAC,CAAC;QACP,CAAC;QACD,IAAI,KAAK,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;YACjC,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC,UAAU,CAAC;iBACtC,KAAK,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC;iBACrD,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;gBACX,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;gBACvD,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,CAAC,CAAC,CAAC;QACP,CAAC;QACD,IAAI,KAAK,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC;YACvC,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC,gBAAgB,CAAC;iBAC5C,KAAK,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,sBAAsB,IAAI,GAAG,CAAC;iBACnE,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;gBACX,kDAAkD;gBAClD,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,EAAE;oBAC1B,sBAAsB,EAAE,MAAM,CAAC,CAAC,CAAC;oBACjC,UAAU,EAAE,CAAC;iBACd,CAAC,CAAC;gBACH,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,CAAC,CAAC,CAAC;QACP,CAAC;QAED,wEAAwE;QACxE,uEAAuE;QACvE,QAAQ,CAAC,QAAQ,CAAC,CAAC,SAAS,EAAE,EAAE;YAC9B,IAAI,SAAS,KAAK,OAAO,CAAC,EAAE;gBAAE,OAAO;YACrC,IAAI,CAAC,gBAAgB,EAAE,CAAC;QAC1B,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,gBAAgB;QACtB,MAAM,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC7C,MAAM,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC;QACvC,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC;QACzD,IAAI,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;QAC3C,IAAI,KAAK,CAAC,QAAQ,CAAC,YAAY,CAAC;YAAE,IAAI,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC;QAC7F,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,IAAI;YAAE,IAAI,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;QACzF,IAAI,KAAK,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,UAAU,IAAI,IAAI;YAAE,IAAI,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC;QACrH,IAAI,KAAK,CAAC,QAAQ,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,sBAAsB,IAAI,IAAI,EAAE,CAAC;YAC3E,IAAI,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,CAAC,gBAAgB,EAAE,CAAC,CAAC,sBAAsB,CAAC,CAAC;QAC/E,CAAC;IACH,CAAC;IAEO,QAAQ;QACd,IAAI,IAAI,CAAC,OAAO;YAAE,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC7C,IAAI,CAAC,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;YAC7B,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;YACpB,MAAM,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YAC7C,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CACpB,IAAI,IAAI,CAAC,OAAO,CAAC,EAAE,gBAAgB,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,UAAU,EAAE;gBAC5D,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACpC,CAAC,CAAC,CAAC,UAAU,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAClD,CAAC,CAAC,CAAC,sBAAsB,IAAI,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,sBAAsB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAC5E,CAAC;YACF,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAC9C,CAAC,EAAE,8BAA8B,CAAC,CAAC;IACrC,CAAC;CACF"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { HomeKitLightState } from './color/types.js';
|
|
2
|
+
export type StateChangeListener = (fixtureId: string) => void;
|
|
3
|
+
export declare class StateRegistry {
|
|
4
|
+
private states;
|
|
5
|
+
private listeners;
|
|
6
|
+
get(id: string): HomeKitLightState;
|
|
7
|
+
/** Replace a fixture's state and fire change listeners. */
|
|
8
|
+
set(id: string, state: HomeKitLightState): void;
|
|
9
|
+
/** Merge a partial update into a fixture's state, returning the new full
|
|
10
|
+
* state. Fires listeners. */
|
|
11
|
+
update(id: string, patch: Partial<HomeKitLightState>): HomeKitLightState;
|
|
12
|
+
onChange(cb: StateChangeListener): () => void;
|
|
13
|
+
}
|
|
14
|
+
/** Bucket members' values; return the value with the largest bucket. Ties
|
|
15
|
+
* break in favour of the value held by the first member in
|
|
16
|
+
* alphabetical-id order. */
|
|
17
|
+
export declare function pickMajority<T>(items: Array<{
|
|
18
|
+
id: string;
|
|
19
|
+
v: T;
|
|
20
|
+
}>): T | undefined;
|
|
21
|
+
//# sourceMappingURL=stateRegistry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stateRegistry.d.ts","sourceRoot":"","sources":["../src/stateRegistry.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD,MAAM,MAAM,mBAAmB,GAAG,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;AAI9D,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAwC;IACtD,OAAO,CAAC,SAAS,CAAkC;IAEnD,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,iBAAiB;IAIlC,2DAA2D;IAC3D,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,iBAAiB,GAAG,IAAI;IAK/C;kCAC8B;IAC9B,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,iBAAiB,CAAC,GAAG,iBAAiB;IAMxE,QAAQ,CAAC,EAAE,EAAE,mBAAmB,GAAG,MAAM,IAAI;CAI9C;AAED;;6BAE6B;AAC7B,wBAAgB,YAAY,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,CAAC,CAAA;CAAE,CAAC,GAAG,CAAC,GAAG,SAAS,CAoBjF"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// StateRegistry — central store of every fixture's HomeKit-visible state.
|
|
2
|
+
//
|
|
3
|
+
// Every StickFixture and ZoneFixture reads/writes through here. Whenever a
|
|
4
|
+
// fixture's state changes, listeners fire so zones can refresh their own
|
|
5
|
+
// HomeKit characteristics (and vice versa: setting a zone updates each
|
|
6
|
+
// member's state in the registry, which fires events, which prompt the
|
|
7
|
+
// per-fixture accessories to update their HomeKit-displayed state).
|
|
8
|
+
//
|
|
9
|
+
// Majority rule for zone state: see pickMajority() — count occurrences of
|
|
10
|
+
// each value across (alphabetically-sorted) members; largest count wins;
|
|
11
|
+
// ties are broken in favour of the value held by the alphabetically-first
|
|
12
|
+
// member.
|
|
13
|
+
const DEFAULT_STATE = { on: false, brightness: 100 };
|
|
14
|
+
export class StateRegistry {
|
|
15
|
+
states = new Map();
|
|
16
|
+
listeners = new Set();
|
|
17
|
+
get(id) {
|
|
18
|
+
return this.states.get(id) ?? { ...DEFAULT_STATE };
|
|
19
|
+
}
|
|
20
|
+
/** Replace a fixture's state and fire change listeners. */
|
|
21
|
+
set(id, state) {
|
|
22
|
+
this.states.set(id, { ...state });
|
|
23
|
+
for (const l of this.listeners)
|
|
24
|
+
l(id);
|
|
25
|
+
}
|
|
26
|
+
/** Merge a partial update into a fixture's state, returning the new full
|
|
27
|
+
* state. Fires listeners. */
|
|
28
|
+
update(id, patch) {
|
|
29
|
+
const next = { ...this.get(id), ...patch };
|
|
30
|
+
this.set(id, next);
|
|
31
|
+
return next;
|
|
32
|
+
}
|
|
33
|
+
onChange(cb) {
|
|
34
|
+
this.listeners.add(cb);
|
|
35
|
+
return () => this.listeners.delete(cb);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/** Bucket members' values; return the value with the largest bucket. Ties
|
|
39
|
+
* break in favour of the value held by the first member in
|
|
40
|
+
* alphabetical-id order. */
|
|
41
|
+
export function pickMajority(items) {
|
|
42
|
+
if (items.length === 0)
|
|
43
|
+
return undefined;
|
|
44
|
+
const sorted = items.slice().sort((a, b) => a.id.localeCompare(b.id));
|
|
45
|
+
const counts = new Map();
|
|
46
|
+
for (let i = 0; i < sorted.length; i++) {
|
|
47
|
+
const v = sorted[i].v;
|
|
48
|
+
const rec = counts.get(v);
|
|
49
|
+
if (rec)
|
|
50
|
+
rec.count++;
|
|
51
|
+
else
|
|
52
|
+
counts.set(v, { count: 1, firstIdx: i });
|
|
53
|
+
}
|
|
54
|
+
let bestV = sorted[0].v;
|
|
55
|
+
let bestRec = counts.get(bestV);
|
|
56
|
+
for (const [v, rec] of counts) {
|
|
57
|
+
if (rec.count > bestRec.count ||
|
|
58
|
+
(rec.count === bestRec.count && rec.firstIdx < bestRec.firstIdx)) {
|
|
59
|
+
bestV = v;
|
|
60
|
+
bestRec = rec;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return bestV;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=stateRegistry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stateRegistry.js","sourceRoot":"","sources":["../src/stateRegistry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { PlatformAccessory } from 'homebridge';
|
|
2
|
+
import { Fixture, Zone } from './config.js';
|
|
3
|
+
import { StickController } from './controller.js';
|
|
4
|
+
import type { DmxPlatform } from './platform.js';
|
|
5
|
+
import { StateRegistry } from './stateRegistry.js';
|
|
6
|
+
export declare class ZoneFixture {
|
|
7
|
+
private readonly platform;
|
|
8
|
+
private readonly zone;
|
|
9
|
+
private readonly controllers;
|
|
10
|
+
private readonly registry;
|
|
11
|
+
private pending;
|
|
12
|
+
private refreshPending;
|
|
13
|
+
private bulb;
|
|
14
|
+
constructor(platform: DmxPlatform, accessory: PlatformAccessory, zone: Zone, controllers: Map<string, StickController>, registry: StateRegistry);
|
|
15
|
+
/** Compute majority state across members, per characteristic. */
|
|
16
|
+
private majorityState;
|
|
17
|
+
/** A HomeKit set on the zone: build the new state from the current
|
|
18
|
+
* majority + the patch the user is applying, write it into every
|
|
19
|
+
* member, and trigger the controller after a small debounce so
|
|
20
|
+
* multi-characteristic dispatch coalesces. */
|
|
21
|
+
private applyToMembers;
|
|
22
|
+
/** Debounced controller dispatch. Sends current registry state for each
|
|
23
|
+
* member to the appropriate StickController. */
|
|
24
|
+
private scheduleDispatch;
|
|
25
|
+
/** Debounced refresh: when members change, push the new majority to
|
|
26
|
+
* the zone's HomeKit characteristics. */
|
|
27
|
+
private scheduleRefresh;
|
|
28
|
+
}
|
|
29
|
+
export type _MemberRef = Fixture;
|
|
30
|
+
//# sourceMappingURL=zoneAccessory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zoneAccessory.d.ts","sourceRoot":"","sources":["../src/zoneAccessory.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAEV,iBAAiB,EAElB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAE5C,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD,OAAO,EAAE,aAAa,EAAgB,MAAM,oBAAoB,CAAC;AAEjE,qBAAa,WAAW;IAMpB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAEzB,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAT3B,OAAO,CAAC,OAAO,CAA+B;IAC9C,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,IAAI,CAAU;gBAGH,QAAQ,EAAE,WAAW,EACtC,SAAS,EAAE,iBAAiB,EACX,IAAI,EAAE,IAAI,EACV,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,EACzC,QAAQ,EAAE,aAAa;IAmD1C,iEAAiE;IACjE,OAAO,CAAC,aAAa;IAWrB;;;mDAG+C;IAC/C,OAAO,CAAC,cAAc;IAWtB;qDACiD;IACjD,OAAO,CAAC,gBAAgB;IAuBxB;8CAC0C;IAC1C,OAAO,CAAC,eAAe;CAqBxB;AAGD,MAAM,MAAM,UAAU,GAAG,OAAO,CAAC"}
|