@ecopoesis/homebridge-dmx 0.5.2 → 0.5.3

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.
@@ -1 +1 @@
1
- {"version":3,"file":"hsvcct.d.ts","sourceRoot":"","sources":["../../src/color/hsvcct.ts"],"names":[],"mappings":"AAaA,OAAO,EAEL,UAAU,EAOX,MAAM,YAAY,CAAC;AAEpB,eAAO,MAAM,MAAM,EAAE,UAsEpB,CAAC"}
1
+ {"version":3,"file":"hsvcct.d.ts","sourceRoot":"","sources":["../../src/color/hsvcct.ts"],"names":[],"mappings":"AAaA,OAAO,EAEL,UAAU,EAOX,MAAM,YAAY,CAAC;AAEpB,eAAO,MAAM,MAAM,EAAE,UA4EpB,CAAC"}
@@ -50,7 +50,12 @@ export const hsvcct = {
50
50
  },
51
51
  /** Inverse of render, for state read-back from a live universe buffer.
52
52
  * A dark fixture parses as on:false with brightness 100 so the next
53
- * HomeKit "on" restores full rather than 0%. */
53
+ * HomeKit "on" restores full rather than 0%.
54
+ * Saturation > 0 means the fixture is in color mode and ignores its CCT
55
+ * channel, so the (stale) CCT byte is NOT reported — re-importing it made
56
+ * the accessory push ColorTemperature after Hue/Saturation on every poll,
57
+ * flipping the Home app tile into temperature-display mode (~5000 K peach)
58
+ * while the light itself was rendering the chosen color. */
54
59
  parse(bytes, channels) {
55
60
  const state = { on: false, brightness: 100 };
56
61
  let i = 0;
@@ -88,6 +93,8 @@ export const hsvcct = {
88
93
  }
89
94
  i++;
90
95
  }
96
+ if ((state.saturation ?? 0) > 0)
97
+ delete state.colorTemperatureMireds;
91
98
  return state;
92
99
  },
93
100
  };
@@ -1 +1 @@
1
- {"version":3,"file":"hsvcct.js","sourceRoot":"","sources":["../../src/color/hsvcct.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,EAAE;AACF,4EAA4E;AAC5E,oEAAoE;AACpE,uEAAuE;AACvE,EAAE;AACF,2DAA2D;AAC3D,0DAA0D;AAC1D,gCAAgC;AAChC,8CAA8C;AAC9C,yCAAyC;AACzC,+DAA+D;AAE/D,OAAO,EAIL,YAAY,EACZ,KAAK,EACL,MAAM,EACN,YAAY,EACZ,YAAY,GACb,MAAM,YAAY,CAAC;AAEpB,MAAM,CAAC,MAAM,MAAM,GAAe;IAChC,EAAE,EAAE,QAAQ;IACZ,eAAe,EAAE,CAAC,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE,kBAAkB,CAAC;IAC9E,QAAQ,CAAC,QAAQ;QACf,YAAY,CAAC,QAAQ,EAAE,CAAC,WAAW,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,CAAC,CAAC,CAAC;QAClE,MAAM,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC;QACnD,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,IAAI,IAAI,CAAC,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC;YAC3C,MAAM,IAAI,KAAK,CAAC,+DAA+D,CAAC,CAAC;QACnF,CAAC;IACH,CAAC;IACD,MAAM,CAAC,KAAwB,EAAE,QAAsB;QACrD,MAAM,GAAG,GAAG,IAAI,UAAU,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC5C,IAAI,CAAC,GAAG,CAAC,CAAC;QACV,OAAO,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC;YAC3B,MAAM,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;YACvB,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC;gBAAC,CAAC,EAAE,CAAC;gBAAC,SAAS;YAAC,CAAC;YAC/B,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC;gBAChB,KAAK,WAAW;oBACd,CAAC,GAAG,YAAY,CAAC,GAAG,EAAE,QAAQ,EAAE,CAAC,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;oBACxD,SAAS;gBACX,KAAK,KAAK;oBACR,GAAG,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,sBAAsB,EAAE,EAAE,CAAC,IAAK,EAAE,EAAE,CAAC,IAAK,CAAC,CAAC;oBAClE,MAAM;gBACR,KAAK,YAAY;oBACf,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,IAAI,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC;oBACjE,MAAM;gBACR,KAAK,KAAK;oBACR,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC;oBAC5D,MAAM;YACV,CAAC;YACD,CAAC,EAAE,CAAC;QACN,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IACD;;qDAEiD;IACjD,KAAK,CAAC,KAAiB,EAAE,QAAsB;QAC7C,MAAM,KAAK,GAAsB,EAAE,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC;QAChE,IAAI,CAAC,GAAG,CAAC,CAAC;QACV,OAAO,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC;YAC3B,MAAM,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;YACvB,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC;gBAAC,CAAC,EAAE,CAAC;gBAAC,SAAS;YAAC,CAAC;YAC/B,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC;gBAChB,KAAK,WAAW,CAAC,CAAC,CAAC;oBACjB,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,IAAI,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC;oBAC9E,MAAM,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC;oBACtE,IAAI,GAAG,GAAG,CAAC,EAAE,CAAC;wBACZ,KAAK,CAAC,EAAE,GAAG,IAAI,CAAC;wBAChB,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;oBAClE,CAAC;oBACD,IAAI,OAAO,EAAE,CAAC;wBAAC,CAAC,IAAI,CAAC,CAAC;wBAAC,SAAS;oBAAC,CAAC;oBAClC,MAAM;gBACR,CAAC;gBACD,KAAK,KAAK,CAAC,CAAC,CAAC;oBACX,MAAM,CAAC,GAAG,EAAE,CAAC,IAAK,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAK,GAAG,EAAE,CAAC,IAAK,CAAC,CAAC;oBAC9D,KAAK,CAAC,sBAAsB,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC;oBACzE,MAAM;gBACR,CAAC;gBACD,KAAK,YAAY;oBACf,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;oBAC9D,MAAM;gBACR,KAAK,KAAK;oBACR,KAAK,CAAC,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;oBACrD,MAAM;YACV,CAAC;YACD,CAAC,EAAE,CAAC;QACN,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;CACF,CAAC"}
1
+ {"version":3,"file":"hsvcct.js","sourceRoot":"","sources":["../../src/color/hsvcct.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
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,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,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,aAAa,EACzB,QAAQ,EAAE,aAAa;IAoE1C,OAAO,CAAC,gBAAgB;IAaxB,OAAO,CAAC,QAAQ;CAcjB"}
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,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,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,aAAa,EACzB,QAAQ,EAAE,aAAa;IAoE1C,OAAO,CAAC,gBAAgB;IAkBxB,OAAO,CAAC,QAAQ;CAcjB"}
@@ -89,7 +89,12 @@ export class StickFixture {
89
89
  this.bulb.updateCharacteristic(C.Hue, s.hue);
90
90
  if (chars.includes('Saturation') && s.saturation != null)
91
91
  this.bulb.updateCharacteristic(C.Saturation, s.saturation);
92
- if (chars.includes('ColorTemperature') && s.colorTemperatureMireds != null) {
92
+ // The Home app displays whichever mode was updated last (color vs
93
+ // temperature). Only push ColorTemperature when the fixture is actually
94
+ // in white mode (sat 0), so a color-mode update leaves Hue/Saturation as
95
+ // the winning (displayed) pair.
96
+ if (chars.includes('ColorTemperature') && s.colorTemperatureMireds != null
97
+ && (s.saturation ?? 0) === 0) {
93
98
  this.bulb.updateCharacteristic(C.ColorTemperature, s.colorTemperatureMireds);
94
99
  }
95
100
  }
@@ -1 +1 @@
1
- {"version":3,"file":"platformAccessory.js","sourceRoot":"","sources":["../src/platformAccessory.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"platformAccessory.js","sourceRoot":"","sources":["../src/platformAccessory.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ecopoesis/homebridge-dmx",
3
3
  "displayName": "DMX",
4
- "version": "0.5.2",
4
+ "version": "0.5.3",
5
5
  "description": "Homebridge platform for DMX controllers (currently Nicolaudie Stick-DE3)",
6
6
  "license": "Apache-2.0",
7
7
  "type": "module",
@@ -58,7 +58,12 @@ export const hsvcct: ColorModel = {
58
58
  },
59
59
  /** Inverse of render, for state read-back from a live universe buffer.
60
60
  * A dark fixture parses as on:false with brightness 100 so the next
61
- * HomeKit "on" restores full rather than 0%. */
61
+ * HomeKit "on" restores full rather than 0%.
62
+ * Saturation > 0 means the fixture is in color mode and ignores its CCT
63
+ * channel, so the (stale) CCT byte is NOT reported — re-importing it made
64
+ * the accessory push ColorTemperature after Hue/Saturation on every poll,
65
+ * flipping the Home app tile into temperature-display mode (~5000 K peach)
66
+ * while the light itself was rendering the chosen color. */
62
67
  parse(bytes: Uint8Array, channels: ChannelDef[]): HomeKitLightState {
63
68
  const state: HomeKitLightState = { on: false, brightness: 100 };
64
69
  let i = 0;
@@ -90,6 +95,7 @@ export const hsvcct: ColorModel = {
90
95
  }
91
96
  i++;
92
97
  }
98
+ if ((state.saturation ?? 0) > 0) delete state.colorTemperatureMireds;
93
99
  return state;
94
100
  },
95
101
  };
@@ -102,7 +102,12 @@ export class StickFixture {
102
102
  if (chars.includes('Brightness')) this.bulb.updateCharacteristic(C.Brightness, s.brightness);
103
103
  if (chars.includes('Hue') && s.hue != null) this.bulb.updateCharacteristic(C.Hue, s.hue);
104
104
  if (chars.includes('Saturation') && s.saturation != null) this.bulb.updateCharacteristic(C.Saturation, s.saturation);
105
- if (chars.includes('ColorTemperature') && s.colorTemperatureMireds != null) {
105
+ // The Home app displays whichever mode was updated last (color vs
106
+ // temperature). Only push ColorTemperature when the fixture is actually
107
+ // in white mode (sat 0), so a color-mode update leaves Hue/Saturation as
108
+ // the winning (displayed) pair.
109
+ if (chars.includes('ColorTemperature') && s.colorTemperatureMireds != null
110
+ && (s.saturation ?? 0) === 0) {
106
111
  this.bulb.updateCharacteristic(C.ColorTemperature, s.colorTemperatureMireds);
107
112
  }
108
113
  }
package/tools/rdm.mjs ADDED
@@ -0,0 +1,310 @@
1
+ #!/usr/bin/env node
2
+ // Art-RDM (Art-Net RDM) client for the ENTTEC DIN Ethergate Mk2.
3
+ //
4
+ // node tools/rdm.mjs discover [--ip 192.168.96.3]
5
+ // ArtTodControl flush + ArtTodRequest; prints the UID table, then GETs
6
+ // DEVICE_INFO from every UID (start address, personality, footprint).
7
+ // node tools/rdm.mjs info <uid>
8
+ // GET DEVICE_INFO + DMX_PERSONALITY_DESCRIPTION for each personality.
9
+ // node tools/rdm.mjs set-personality <uid> <n>
10
+ // SET DMX_PERSONALITY, then re-GET DEVICE_INFO to verify.
11
+ // node tools/rdm.mjs set-address <uid> <dmx>
12
+ // SET DMX_START_ADDRESS, then re-GET DEVICE_INFO to verify.
13
+ // node tools/rdm.mjs identify <uid> <0|1>
14
+ // SET IDENTIFY_DEVICE (makes the fixture flash so you can find it).
15
+ //
16
+ // UIDs print as mmmm:dddddddd hex (WAC manufacturer id = 0776).
17
+
18
+ import dgram from 'node:dgram';
19
+
20
+ const ARTNET_PORT = 6454;
21
+ const OP_POLL = 0x2000;
22
+ const OP_POLL_REPLY = 0x2100;
23
+ const OP_TOD_REQUEST = 0x8000;
24
+ const OP_TOD_DATA = 0x8100;
25
+ const OP_TOD_CONTROL = 0x8200;
26
+ const OP_RDM = 0x8300;
27
+
28
+ const PID_DEVICE_INFO = 0x0060;
29
+ const PID_PERSONALITY = 0x00e0;
30
+ const PID_PERSONALITY_DESC = 0x00e1;
31
+ const PID_START_ADDRESS = 0x00f0;
32
+ const PID_IDENTIFY = 0x1000;
33
+
34
+ const CC_GET = 0x20;
35
+ const CC_SET = 0x30;
36
+
37
+ const SRC_UID = Buffer.from([0x7f, 0xf0, 0x00, 0x00, 0x00, 0x01]);
38
+
39
+ const args = process.argv.slice(2);
40
+ const ipIdx = args.indexOf('--ip');
41
+ const ip = ipIdx >= 0 ? args.splice(ipIdx, 2)[1] : '192.168.96.3';
42
+ const addrIdx = args.indexOf('--address');
43
+ const portAddress = addrIdx >= 0 ? Number(args.splice(addrIdx, 2)[1]) : 1;
44
+ const [cmd, ...rest] = args;
45
+
46
+ function header(opcode) {
47
+ const b = Buffer.alloc(12);
48
+ b.write('Art-Net\0', 0, 'latin1');
49
+ b.writeUInt16LE(opcode, 8);
50
+ b[10] = 0; b[11] = 14; // ProtVer
51
+ return b;
52
+ }
53
+
54
+ function artTodControl(address) {
55
+ // ID(8) op(2) ProtVer(2) Filler(2) Spare(7) Net(1) Command(1) Address(1)
56
+ const b = Buffer.concat([header(OP_TOD_CONTROL), Buffer.alloc(12)]);
57
+ b[22] = 0x01; // AtcFlush -> full discovery
58
+ b[23] = address;
59
+ return b;
60
+ }
61
+
62
+ function artTodRequest(address) {
63
+ // ID(8) op(2) ProtVer(2) Filler(2) Spare(7) Net(1) Command(1) AddCount(1) Address[]
64
+ const b = Buffer.concat([header(OP_TOD_REQUEST), Buffer.alloc(13)]);
65
+ b[23] = 1; // AddCount
66
+ b[24] = address;
67
+ return b;
68
+ }
69
+
70
+ function rdmFrame(dstUid, cc, pid, pd = Buffer.alloc(0), tn = 0) {
71
+ const len = 24 + pd.length; // message length: start code .. before checksum
72
+ const f = Buffer.alloc(len + 2);
73
+ f[0] = 0xcc; f[1] = 0x01; f[2] = len;
74
+ dstUid.copy(f, 3);
75
+ SRC_UID.copy(f, 9);
76
+ f[15] = tn & 0xff;
77
+ f[16] = 0x01; // port id
78
+ f[17] = 0x00; // message count
79
+ f.writeUInt16BE(0, 18); // sub-device
80
+ f[20] = cc;
81
+ f.writeUInt16BE(pid, 21);
82
+ f[23] = pd.length;
83
+ pd.copy(f, 24);
84
+ let sum = 0;
85
+ for (let i = 0; i < len; i++) sum = (sum + f[i]) & 0xffff;
86
+ f.writeUInt16BE(sum, len);
87
+ return f;
88
+ }
89
+
90
+ function artRdm(address, rdm) {
91
+ // ID(8) op(2) ProtVer(2) RdmVer(1) Filler(1) Spare(7) Net(1) Command(1) Address(1) RdmPacket
92
+ const b = Buffer.concat([header(OP_RDM), Buffer.alloc(12), rdm.subarray(1)]);
93
+ b[12] = 0x01; // RdmVer
94
+ b[22] = 0x00; // ArProcess
95
+ b[23] = address;
96
+ return b;
97
+ }
98
+
99
+ const fmtUid = (u) => `${u.subarray(0, 2).toString('hex')}:${u.subarray(2).toString('hex')}`;
100
+ const parseUid = (s) => {
101
+ const hex = s.replace(/[:.]/g, '');
102
+ if (!/^[0-9a-fA-F]{12}$/.test(hex)) throw new Error(`bad UID: ${s}`);
103
+ return Buffer.from(hex, 'hex');
104
+ };
105
+
106
+ const sock = dgram.createSocket('udp4');
107
+ const inbox = [];
108
+ const waiters = [];
109
+ sock.on('message', (msg, rinfo) => {
110
+ if (msg.length < 12 || msg.toString('latin1', 0, 8) !== 'Art-Net\0') return;
111
+ const pkt = { op: msg.readUInt16LE(8), msg, rinfo };
112
+ const w = waiters.shift();
113
+ if (w) w(pkt); else inbox.push(pkt);
114
+ });
115
+
116
+ function nextPacket(timeoutMs) {
117
+ const queued = inbox.shift();
118
+ if (queued) return Promise.resolve(queued);
119
+ return new Promise((resolve) => {
120
+ const t = setTimeout(() => {
121
+ const i = waiters.indexOf(resolve);
122
+ if (i >= 0) waiters.splice(i, 1);
123
+ resolve(null);
124
+ }, timeoutMs);
125
+ waiters.push((pkt) => { clearTimeout(t); resolve(pkt); });
126
+ });
127
+ }
128
+
129
+ function send(buf) {
130
+ return new Promise((resolve, reject) =>
131
+ sock.send(buf, ARTNET_PORT, ip, (e) => (e ? reject(e) : resolve())));
132
+ }
133
+
134
+ async function collect(op, totalMs) {
135
+ const out = [];
136
+ const deadline = Date.now() + totalMs;
137
+ for (;;) {
138
+ const left = deadline - Date.now();
139
+ if (left <= 0) break;
140
+ const pkt = await nextPacket(left);
141
+ if (!pkt) break;
142
+ if (pkt.op === op) out.push(pkt);
143
+ }
144
+ return out;
145
+ }
146
+
147
+ function parseTodData(msg) {
148
+ const port = msg[13];
149
+ const address = msg[23];
150
+ const uidTotal = msg.readUInt16BE(24);
151
+ const uidCount = msg[27];
152
+ const uids = [];
153
+ for (let i = 0; i < uidCount; i++) uids.push(Buffer.from(msg.subarray(28 + i * 6, 34 + i * 6)));
154
+ return { port, address, uidTotal, uids };
155
+ }
156
+
157
+ let tn = 0;
158
+ async function rdmRequest(address, dstUid, cc, pid, pd, { timeoutMs = 1500, tries = 3 } = {}) {
159
+ for (let attempt = 0; attempt < tries; attempt++) {
160
+ const myTn = tn = (tn + 1) & 0xff;
161
+ await send(artRdm(address, rdmFrame(dstUid, cc, pid, pd, myTn)));
162
+ const deadline = Date.now() + timeoutMs;
163
+ for (;;) {
164
+ const left = deadline - Date.now();
165
+ if (left <= 0) break;
166
+ const pkt = await nextPacket(left);
167
+ if (!pkt || pkt.op !== OP_RDM) continue;
168
+ // RDM packet starts at offset 24, without the 0xCC start code (but some
169
+ // firmware includes it — tolerate both):
170
+ // [0]=0x01 sub-start, [1]=len, [2..7]=dst, [8..13]=src, [14]=tn, [15]=respType,
171
+ // [16]=msgCount, [17..18]=subdev, [19]=cc, [20..21]=pid, [22]=pdl, [23..]=pd
172
+ let r = pkt.msg.subarray(24);
173
+ if (r[0] === 0xcc) r = r.subarray(1);
174
+ if (process.env.DEBUG_RDM) console.error('rx ArtRdm:', pkt.msg.subarray(24).toString('hex'));
175
+ if (r.length < 23 || r[0] !== 0x01) continue;
176
+ if (!r.subarray(8, 14).equals(dstUid)) continue;
177
+ if (r[14] !== myTn && r[14] !== 0) continue;
178
+ const respType = r[15];
179
+ const pdl = r[22];
180
+ const pd = Buffer.from(r.subarray(23, 23 + pdl));
181
+ if (respType === 0x01) { // ACK_TIMER: wait and re-poll with GET QUEUED_MESSAGE-ish retry
182
+ await new Promise((res) => setTimeout(res, pd.readUInt16BE(0) * 100 || 200));
183
+ break; // retry the request
184
+ }
185
+ return { respType, cc: r[19], pid: r.readUInt16BE(20), pd };
186
+ }
187
+ }
188
+ return null;
189
+ }
190
+
191
+ function parseDeviceInfo(pd) {
192
+ return {
193
+ protocolVersion: pd.readUInt16BE(0),
194
+ model: pd.readUInt16BE(2),
195
+ category: pd.readUInt16BE(4),
196
+ swVersion: pd.readUInt32BE(6),
197
+ footprint: pd.readUInt16BE(10),
198
+ personality: pd[12],
199
+ personalityCount: pd[13],
200
+ startAddress: pd.readUInt16BE(14),
201
+ subDevices: pd.readUInt16BE(16),
202
+ sensors: pd[18],
203
+ };
204
+ }
205
+
206
+ async function discoverTod(addresses = [0, 1], flush = false) {
207
+ // AtcFlush restarts wire discovery (slow, and RDM passthrough stalls while it
208
+ // runs) — only do it when asked; a plain ArtTodRequest returns the cached TOD.
209
+ if (flush) {
210
+ for (const addr of addresses) await send(artTodControl(addr));
211
+ await new Promise((res) => setTimeout(res, 4000));
212
+ }
213
+ for (const addr of addresses) await send(artTodRequest(addr));
214
+ const pkts = await collect(OP_TOD_DATA, 3000);
215
+ const byAddr = new Map();
216
+ for (const p of pkts) {
217
+ const tod = parseTodData(p.msg);
218
+ const prev = byAddr.get(tod.address);
219
+ if (!prev || tod.uids.length >= prev.uids.length) byAddr.set(tod.address, tod);
220
+ }
221
+ return byAddr;
222
+ }
223
+
224
+ async function deviceInfoLine(address, uid) {
225
+ const resp = await rdmRequest(address, uid, CC_GET, PID_DEVICE_INFO);
226
+ if (!resp) return `${fmtUid(uid)} (no response)`;
227
+ if (resp.respType !== 0x00) return `${fmtUid(uid)} (resp type ${resp.respType})`;
228
+ const d = parseDeviceInfo(resp.pd);
229
+ return `${fmtUid(uid)} dmx=${String(d.startAddress).padStart(3)} ` +
230
+ `personality=${d.personality}/${d.personalityCount} footprint=${d.footprint} ` +
231
+ `model=0x${d.model.toString(16).padStart(4, '0')} sw=0x${d.swVersion.toString(16)}`;
232
+ }
233
+
234
+ async function main() {
235
+ // Many Art-Net nodes reply to <sender-ip>:6454 regardless of source port.
236
+ await new Promise((res, rej) => {
237
+ sock.once('error', (e) => {
238
+ if (e.code !== 'EADDRINUSE') return rej(e);
239
+ console.error('port 6454 busy, falling back to ephemeral (replies may be lost)');
240
+ sock.bind(0, res);
241
+ });
242
+ sock.bind(ARTNET_PORT, res);
243
+ });
244
+
245
+ if (cmd === 'discover' || cmd === undefined) {
246
+ await send(Buffer.concat([header(OP_POLL), Buffer.from([0, 0])])); // + Flags, Priority
247
+ const polls = await collect(OP_POLL_REPLY, 1500);
248
+ const addrs = new Set([0, 1]);
249
+ for (const p of polls) {
250
+ const m = p.msg;
251
+ const name = m.toString('latin1', 26, 44).replace(/\0.*$/, '');
252
+ const net = m[18], sub = m[19];
253
+ const swOut = [...m.subarray(190, 194)];
254
+ const bindIndex = m[211];
255
+ console.log(`node: ${name} @ ${p.rinfo.address} net=${net} sub=${sub} swOut=${swOut.join(',')} bindIndex=${bindIndex}`);
256
+ for (const u of swOut) addrs.add(((sub & 0x0f) << 4) | (u & 0x0f));
257
+ }
258
+ const byAddr = await discoverTod([...addrs], rest.includes('--flush'));
259
+ await new Promise((res) => setTimeout(res, 1000));
260
+ if (byAddr.size === 0) {
261
+ console.log('no ArtTodData received — check dmx_mode is "DMX OUT (RDM)" and routing to UDP/6454');
262
+ return;
263
+ }
264
+ for (const [address, tod] of byAddr) {
265
+ console.log(`\nport-address ${address}: ${tod.uidTotal} UIDs`);
266
+ for (const uid of tod.uids) console.log(' ' + await deviceInfoLine(address, uid));
267
+ }
268
+ } else if (cmd === 'info') {
269
+ const uid = parseUid(rest[0]);
270
+ console.log(await deviceInfoLine(portAddress, uid));
271
+ const cur = await rdmRequest(portAddress, uid, CC_GET, PID_PERSONALITY);
272
+ if (cur?.respType === 0x00) {
273
+ const [current, count] = cur.pd;
274
+ for (let i = 1; i <= count; i++) {
275
+ const d = await rdmRequest(portAddress, uid, CC_GET, PID_PERSONALITY_DESC, Buffer.from([i]));
276
+ if (d?.respType === 0x00) {
277
+ const slots = d.pd.readUInt16BE(1);
278
+ const desc = d.pd.toString('latin1', 3).replace(/\0.*$/, '');
279
+ console.log(` personality ${i}${i === current ? ' *' : ' '} ${slots}ch ${desc}`);
280
+ }
281
+ }
282
+ }
283
+ } else if (cmd === 'set-personality') {
284
+ const uid = parseUid(rest[0]);
285
+ const n = Number(rest[1]);
286
+ if (!(n >= 1 && n <= 255)) throw new Error('personality must be 1..255');
287
+ const resp = await rdmRequest(portAddress, uid, CC_SET, PID_PERSONALITY, Buffer.from([n]));
288
+ console.log(resp ? `set-personality resp type ${resp.respType} (0=ACK)` : 'no response');
289
+ console.log(await deviceInfoLine(portAddress, uid));
290
+ } else if (cmd === 'set-address') {
291
+ const uid = parseUid(rest[0]);
292
+ const n = Number(rest[1]);
293
+ if (!(n >= 1 && n <= 512)) throw new Error('address must be 1..512');
294
+ const pd = Buffer.alloc(2);
295
+ pd.writeUInt16BE(n, 0);
296
+ const resp = await rdmRequest(portAddress, uid, CC_SET, PID_START_ADDRESS, pd);
297
+ console.log(resp ? `set-address resp type ${resp.respType} (0=ACK)` : 'no response');
298
+ console.log(await deviceInfoLine(portAddress, uid));
299
+ } else if (cmd === 'identify') {
300
+ const uid = parseUid(rest[0]);
301
+ const on = rest[1] === '1' ? 1 : 0;
302
+ const resp = await rdmRequest(portAddress, uid, CC_SET, PID_IDENTIFY, Buffer.from([on]));
303
+ console.log(resp ? `identify resp type ${resp.respType} (0=ACK)` : 'no response');
304
+ } else {
305
+ console.error('usage: rdm.mjs [--ip x.x.x.x] discover | info <uid> | set-personality <uid> <n> | set-address <uid> <dmx> | identify <uid> <0|1>');
306
+ process.exit(2);
307
+ }
308
+ }
309
+
310
+ main().then(() => sock.close(), (e) => { console.error(e); sock.close(); process.exit(1); });