@ecopoesis/homebridge-dmx 0.5.5 → 0.6.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.
Files changed (58) hide show
  1. package/CLAUDE.md +1 -0
  2. package/README.md +67 -0
  3. package/config.schema.json +104 -0
  4. package/dist/config.d.ts +5 -0
  5. package/dist/config.d.ts.map +1 -1
  6. package/dist/config.js +18 -1
  7. package/dist/config.js.map +1 -1
  8. package/dist/controller.d.ts +3 -2
  9. package/dist/controller.d.ts.map +1 -1
  10. package/dist/controller.js +7 -4
  11. package/dist/controller.js.map +1 -1
  12. package/dist/dmxController.d.ts +9 -1
  13. package/dist/dmxController.d.ts.map +1 -1
  14. package/dist/platform.d.ts +1 -0
  15. package/dist/platform.d.ts.map +1 -1
  16. package/dist/platform.js +37 -2
  17. package/dist/platform.js.map +1 -1
  18. package/dist/sacn.d.ts +3 -2
  19. package/dist/sacn.d.ts.map +1 -1
  20. package/dist/sacn.js +7 -4
  21. package/dist/sacn.js.map +1 -1
  22. package/dist/settings.d.ts +13 -0
  23. package/dist/settings.d.ts.map +1 -1
  24. package/dist/settings.js +14 -0
  25. package/dist/settings.js.map +1 -1
  26. package/dist/show/colors.d.ts +25 -0
  27. package/dist/show/colors.d.ts.map +1 -0
  28. package/dist/show/colors.js +216 -0
  29. package/dist/show/colors.js.map +1 -0
  30. package/dist/show/dsl.d.ts +56 -0
  31. package/dist/show/dsl.d.ts.map +1 -0
  32. package/dist/show/dsl.js +326 -0
  33. package/dist/show/dsl.js.map +1 -0
  34. package/dist/show/engine.d.ts +50 -0
  35. package/dist/show/engine.d.ts.map +1 -0
  36. package/dist/show/engine.js +264 -0
  37. package/dist/show/engine.js.map +1 -0
  38. package/dist/showAccessory.d.ts +9 -0
  39. package/dist/showAccessory.d.ts.map +1 -0
  40. package/dist/showAccessory.js +33 -0
  41. package/dist/showAccessory.js.map +1 -0
  42. package/dist/stateRegistry.d.ts +8 -3
  43. package/dist/stateRegistry.d.ts.map +1 -1
  44. package/dist/stateRegistry.js +4 -4
  45. package/dist/stateRegistry.js.map +1 -1
  46. package/examples/dmx.yaml +76 -0
  47. package/package.json +1 -1
  48. package/src/config.ts +22 -1
  49. package/src/controller.ts +8 -5
  50. package/src/dmxController.ts +10 -1
  51. package/src/platform.ts +35 -2
  52. package/src/sacn.ts +8 -4
  53. package/src/settings.ts +19 -0
  54. package/src/show/colors.ts +224 -0
  55. package/src/show/dsl.ts +370 -0
  56. package/src/show/engine.ts +280 -0
  57. package/src/showAccessory.ts +46 -0
  58. package/src/stateRegistry.ts +11 -5
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/show/engine.ts"],"names":[],"mappings":"AAAA,gDAAgD;AAChD,EAAE;AACF,0EAA0E;AAC1E,wEAAwE;AACxE,qEAAqE;AACrE,yEAAyE;AACzE,sEAAsE;AACtE,4DAA4D;AAC5D,EAAE;AACF,SAAS;AACT,6EAA6E;AAC7E,yEAAyE;AACzE,wDAAwD;AACxD,uEAAuE;AACvE,oDAAoD;AACpD,0EAA0E;AAC1E,8DAA8D;AAQ9D,OAAO,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAC7E,OAAO,EAAa,OAAO,EAAE,MAAM,aAAa,CAAC;AAmBjD,MAAM,OAAO,UAAU;IAQF;IACA;IACA;IATX,GAAG,GAAe,IAAI,CAAC;IACvB,SAAS,GAAG,IAAI,GAAG,EAAgB,CAAC;IACpC,WAAW,GAAkB,IAAI,CAAC;IAClC,KAAK,GAAG,IAAI,GAAG,EAAgB,CAAC;IAExC,YACE,KAAa,EACI,WAAuC,EACvC,QAAuB,EACvB,GAAW;QAFX,gBAAW,GAAX,WAAW,CAA4B;QACvC,aAAQ,GAAR,QAAQ,CAAe;QACvB,QAAG,GAAH,GAAG,CAAQ;QAE5B,KAAK,MAAM,CAAC,IAAI,KAAK;YAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;QAC/C,qEAAqE;QACrE,QAAQ,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE;YAC/B,IAAI,MAAM,KAAK,SAAS,IAAI,CAAC,IAAI,CAAC,GAAG;gBAAE,OAAO;YAC9C,IAAI,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;gBAC9B,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,wBAAwB,EAAE,EAAE,CAAC,CAAC;YAChD,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,OAAO;QACL,OAAO,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC;IACnC,CAAC;IAED,QAAQ,CAAC,EAAgB;QACvB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACvB,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACzC,CAAC;IAED,KAAK,CAAC,EAAU;QACd,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChC,IAAI,CAAC,IAAI,EAAE,CAAC;YAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;YAAC,OAAO;QAAC,CAAC;QAC/D,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,EAAE,sBAAsB,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAClF,OAAO;QACT,CAAC;QACD,IAAI,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,KAAK,EAAE;YAAE,OAAO;QACrC,IAAI,IAAI,CAAC,GAAG;YAAE,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;QAEjE,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAqB,CAAC;QAC9C,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,QAAQ;YAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAEzF,qEAAqE;QACrE,sEAAsE;QACtE,kEAAkE;QAClE,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE;YAC/C,MAAM,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;YACjD,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,EAAE,eAAe,IAAI,qBAAqB,CAAC,CAAC;QACpE,CAAC,EAAE,CAAC,CAAC,IAAI,qBAAqB,CAAC;QAC/B,MAAM,GAAG,GAAQ;YACf,IAAI;YACJ,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;YACrB,KAAK,EAAE,WAAW,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,OAAO,CAAC;YAC9C,QAAQ;YACR,QAAQ,EAAE,IAAI,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;YACtD,OAAO;YACP,SAAS,EAAE,IAAI;YACf,gBAAgB,EAAE,CAAC,CAAC;YACpB,cAAc,EAAE,CAAC;SAClB,CAAC;QACF,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC;QACpB,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,CAAC,GAAG,CAAC,IAAI,CACX,SAAS,IAAI,CAAC,EAAE,cAAc,IAAI,CAAC,KAAK,CAAC,MAAM,WAAW,IAAI,CAAC,QAAQ,CAAC,MAAM,aAAa;YAC3F,SAAS,CAAC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,IAAI;YACtF,GAAG,OAAO,YAAY,CACvB,CAAC;QACF,IAAI,CAAC,IAAI,EAAE,CAAC;QACZ,IAAI,CAAC,IAAI,EAAE,CAAC;IACd,CAAC;IAED;;;mEAG+D;IAC/D,IAAI,CAAC,MAAM,GAAG,cAAc,EAAE,MAAe;QAC3C,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;IACrC,CAAC;IAED;;2CAEuC;IAC/B,OAAO,CAAC,MAAc,EAAE,MAA0B,EAAE,MAAe;QACzE,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC;QACrB,IAAI,CAAC,GAAG;YAAE,OAAO;QACjB,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACzB,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC;QAChB,sEAAsE;QACtE,kDAAkD;QAClD,MAAM,MAAM,GAAG,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC;QAClF,KAAK,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,IAAI,MAAM,EAAE,CAAC;YAChC,IAAI,EAAE,KAAK,MAAM;gBAAE,SAAS;YAC5B,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;QACtE,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,GAAG,CAAC,IAAI,CAAC,EAAE,cAAc,MAAM,GAAG,CAAC,CAAC;QAC3D,IAAI,MAAM;YAAE,IAAI,CAAC,IAAI,EAAE,CAAC;IAC1B,CAAC;IAED,QAAQ;QACN,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;YAAC,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YAAC,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC;QAAC,CAAC;IACnE,CAAC;IAED;;gCAE4B;IACpB,IAAI;QACV,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAC1B,IAAI,EAAE,KAAK,IAAI,CAAC,WAAW;YAAE,OAAO;QACpC,IAAI,CAAC,WAAW,GAAG,EAAE,CAAC;QACtB,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,SAAS;YAAE,CAAC,CAAC,EAAE,CAAC,CAAC;IACxC,CAAC;IAEO,OAAO,CAAC,GAAQ,EAAE,EAAU;QAClC,OAAO,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAE,CAAC;IAC/B,CAAC;IAEO,IAAI;QACV,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC;QACrB,IAAI,CAAC,GAAG;YAAE,OAAO;QACjB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACrC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,kEAAkE;YAClE,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;YACrB,OAAO;QACT,CAAC;QACD,KAAK,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;YACrC,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YACjC,MAAM,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;YACjD,CAAC,EAAE,UAAU,CAAC,EAAE,EAAE,OAAO,CAAC,IAAI,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9D,CAAC;QACD,GAAG,CAAC,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC;QAC5B,uEAAuE;QACvE,qEAAqE;QACrE,qEAAqE;QACrE,qEAAqE;QACrE,kDAAkD;QAClD,IAAI,GAAG,GAAG,GAAG,CAAC,cAAc,IAAI,oBAAoB,EAAE,CAAC;YACrD,GAAG,CAAC,cAAc,GAAG,GAAG,CAAC;YACzB,IAAI,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,gBAAgB,EAAE,CAAC;gBACxC,GAAG,CAAC,gBAAgB,GAAG,KAAK,CAAC,IAAI,CAAC;gBAClC,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC;gBACnD,KAAK,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,IAAI,OAAO,EAAE,CAAC;oBACjC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;gBACtE,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAEO,UAAU,CAAC,GAAQ;QACzB,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACzB,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,CAAG,4CAA4C;QAC/D,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACvD,KAAK,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACtC,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YACjC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,EAAE,UAAU,CAAC,EAAE,EAAE,OAAO,CAAC,IAAI,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YACjG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC;QACnD,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,GAAG,CAAC,IAAI,CAAC,EAAE,YAAY,CAAC,CAAC;QAChD,IAAI,CAAC,IAAI,EAAE,CAAC;IACd,CAAC;IAED;gCAC4B;IACpB,OAAO,CAAC,GAAQ,EAAE,GAAW;QACnC,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,GAAG,CAAC;QAC/B,IAAI,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,SAAS,CAAC;QAC5B,IAAI,UAAU,GAAG,IAAI,CAAC;QACtB,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACd,IAAI,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;gBAAC,UAAU,GAAG,KAAK,CAAC;gBAAC,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC;YAAC,CAAC;QACtE,CAAC;aAAM,IAAI,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAC7B,OAAO,IAAI,CAAC;QACd,CAAC;QACD,yDAAyD;QACzD,IAAI,CAAC,GAAG,CAAC,CAAC;QACV,IAAI,CAAC,GAAG,CAAC,CAAC;QACV,IAAI,GAAG,GAAG,CAAC,CAAC;QACZ,OAAO,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAClC,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YACzB,MAAM,GAAG,GAAG,EAAE,CAAC,MAAM,GAAG,EAAE,CAAC,MAAM,CAAC;YAClC,IAAI,CAAC,GAAG,GAAG,GAAG,GAAG,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACjD,MAAM,KAAK,GAAG,CAAC,GAAG,GAAG,CAAC;gBACtB,CAAC,GAAG,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBACvD,MAAM;YACR,CAAC;YACD,GAAG,IAAI,GAAG,CAAC;QACb,CAAC;QACD,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACzB,MAAM,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO;YACnC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC;QAC3E,MAAM,KAAK,GAAG,EAAE,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACvE,MAAM,KAAK,GAAG,IAAI,GAAG,EAAqB,CAAC;QAC3C,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC/B,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAE,CAAC;YACnC,MAAM,CAAC,GAAG,IAAI,EAAE,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,KAAK,CAAC;YACpC,MAAM,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,KAAK,CAAC;YACzC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;QACzC,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC;IAC5B,CAAC;CACF;AAED,8EAA8E;AAE9E,MAAM,UAAU,SAAS,CAAC,CAAoB;IAC5C,MAAM,GAAG,GAAc,EAAE,UAAU,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC/D,IAAI,CAAC,CAAC,GAAG,IAAI,IAAI;QAAE,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC;IACnC,IAAI,CAAC,CAAC,UAAU,IAAI,IAAI;QAAE,GAAG,CAAC,UAAU,GAAG,CAAC,CAAC,UAAU,CAAC;IACxD,IAAI,CAAC,CAAC,sBAAsB,IAAI,IAAI;QAAE,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,sBAAsB,CAAC;IAC5E,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;wCAKwC;AACxC,MAAM,UAAU,OAAO,CAAC,IAAe,EAAE,EAAW,EAAE,OAAO,GAAG,KAAK;IACnE,MAAM,KAAK,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC;IAC/C,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAS,EAAU,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;IAC1D,MAAM,EAAE,GAAG,IAAI,CAAC,UAAU,GAAG,GAAG,CAAC;IACjC,MAAM,CAAC,GAAsB;QAC3B,EAAE;QACF,UAAU,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG;KACvD,CAAC;IACF,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;IACjE,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,GAAG,IAAI,IAAI;QAAE,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACnE,IAAI,KAAK,CAAC,QAAQ,CAAC,YAAY,CAAC;QAAE,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,CAAC,CAAC;IACzE,IAAI,KAAK,CAAC,QAAQ,CAAC,kBAAkB,CAAC,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;QAC5E,CAAC,CAAC,sBAAsB,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC5C,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { PlatformAccessory } from 'homebridge';
2
+ import type { DmxPlatform } from './platform.js';
3
+ import { Show } from './show/dsl.js';
4
+ import { ShowEngine } from './show/engine.js';
5
+ export declare class ShowSwitch {
6
+ private sw;
7
+ constructor(platform: DmxPlatform, accessory: PlatformAccessory, show: Show, engine: ShowEngine);
8
+ }
9
+ //# sourceMappingURL=showAccessory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"showAccessory.d.ts","sourceRoot":"","sources":["../src/showAccessory.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,iBAAiB,EAAW,MAAM,YAAY,CAAC;AAE7D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,qBAAa,UAAU;IACrB,OAAO,CAAC,EAAE,CAAU;gBAGlB,QAAQ,EAAE,WAAW,EACrB,SAAS,EAAE,iBAAiB,EAC5B,IAAI,EAAE,IAAI,EACV,MAAM,EAAE,UAAU;CAwBrB"}
@@ -0,0 +1,33 @@
1
+ // ShowSwitch — one HomeKit Switch per runnable show.
2
+ //
3
+ // On → engine.start(id): whatever show was running stops (its own switch
4
+ // flips off through the engine's change listener).
5
+ // Off → engine.stop(): lights freeze on the current frame.
6
+ // The switch also flips off by itself when a one-shot show finishes or a
7
+ // user touches one of the show's lights.
8
+ export class ShowSwitch {
9
+ sw;
10
+ constructor(platform, accessory, show, engine) {
11
+ const C = platform.Characteristic;
12
+ const info = accessory.getService(platform.Service.AccessoryInformation);
13
+ info?.setCharacteristic(C.Manufacturer, 'DMX')
14
+ ?.setCharacteristic(C.Model, `Show (${show.steps.length} steps, ${show.fixtures.length} fixtures)`)
15
+ ?.setCharacteristic(C.SerialNumber, `show-${show.id}`);
16
+ this.sw =
17
+ accessory.getService(platform.Service.Switch)
18
+ ?? accessory.addService(platform.Service.Switch, show.name);
19
+ this.sw.setCharacteristic(C.Name, show.name);
20
+ this.sw.getCharacteristic(C.On)
21
+ .onGet(() => engine.running() === show.id)
22
+ .onSet((v) => {
23
+ if (v)
24
+ engine.start(show.id);
25
+ else if (engine.running() === show.id)
26
+ engine.stop();
27
+ });
28
+ engine.onChange((runningId) => {
29
+ this.sw.updateCharacteristic(C.On, runningId === show.id);
30
+ });
31
+ }
32
+ }
33
+ //# sourceMappingURL=showAccessory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"showAccessory.js","sourceRoot":"","sources":["../src/showAccessory.ts"],"names":[],"mappings":"AAAA,qDAAqD;AACrD,EAAE;AACF,0EAA0E;AAC1E,yDAAyD;AACzD,2DAA2D;AAC3D,yEAAyE;AACzE,yCAAyC;AAQzC,MAAM,OAAO,UAAU;IACb,EAAE,CAAU;IAEpB,YACE,QAAqB,EACrB,SAA4B,EAC5B,IAAU,EACV,MAAkB;QAElB,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,KAAK,CAAC;YAC1C,EAAE,iBAAiB,CAAC,CAAC,CAAC,KAAK,EAAE,SAAS,IAAI,CAAC,KAAK,CAAC,MAAM,WAAW,IAAI,CAAC,QAAQ,CAAC,MAAM,YAAY,CAAC;YACnG,EAAE,iBAAiB,CAAC,CAAC,CAAC,YAAY,EAAE,QAAQ,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;QAE3D,IAAI,CAAC,EAAE;YACL,SAAS,CAAC,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC;mBAC1C,SAAS,CAAC,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9D,IAAI,CAAC,EAAE,CAAC,iBAAiB,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QAE7C,IAAI,CAAC,EAAE,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,CAAC;aAC5B,KAAK,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;aACzC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;YACX,IAAI,CAAC;gBAAE,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;iBACxB,IAAI,MAAM,CAAC,OAAO,EAAE,KAAK,IAAI,CAAC,EAAE;gBAAE,MAAM,CAAC,IAAI,EAAE,CAAC;QACvD,CAAC,CAAC,CAAC;QAEL,MAAM,CAAC,QAAQ,CAAC,CAAC,SAAS,EAAE,EAAE;YAC5B,IAAI,CAAC,EAAE,CAAC,oBAAoB,CAAC,CAAC,CAAC,EAAE,EAAE,SAAS,KAAK,IAAI,CAAC,EAAE,CAAC,CAAC;QAC5D,CAAC,CAAC,CAAC;IACL,CAAC;CACF"}
@@ -1,14 +1,19 @@
1
1
  import { HomeKitLightState } from './color/types.js';
2
- export type StateChangeListener = (fixtureId: string) => void;
2
+ /** Who made a change. Accessories write as 'homekit' (the default);
3
+ * the gateway read-back writes 'sync'; the show engine writes 'show'.
4
+ * The engine uses this to end a show when a user touches one of its
5
+ * lights without reacting to its own keyframes or to read-back. */
6
+ export type StateSource = 'homekit' | 'sync' | 'show';
7
+ export type StateChangeListener = (fixtureId: string, source: StateSource) => void;
3
8
  export declare class StateRegistry {
4
9
  private states;
5
10
  private listeners;
6
11
  get(id: string): HomeKitLightState;
7
12
  /** Replace a fixture's state and fire change listeners. */
8
- set(id: string, state: HomeKitLightState): void;
13
+ set(id: string, state: HomeKitLightState, source?: StateSource): void;
9
14
  /** Merge a partial update into a fixture's state, returning the new full
10
15
  * state. Fires listeners. */
11
- update(id: string, patch: Partial<HomeKitLightState>): HomeKitLightState;
16
+ update(id: string, patch: Partial<HomeKitLightState>, source?: StateSource): HomeKitLightState;
12
17
  onChange(cb: StateChangeListener): () => void;
13
18
  }
14
19
  /** Bucket members' values; return the value with the largest bucket. Ties
@@ -1 +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"}
1
+ {"version":3,"file":"stateRegistry.d.ts","sourceRoot":"","sources":["../src/stateRegistry.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD;;;oEAGoE;AACpE,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,CAAC;AAEtD,MAAM,MAAM,mBAAmB,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,KAAK,IAAI,CAAC;AAInF,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,EAAE,MAAM,GAAE,WAAuB,GAAG,IAAI;IAKhF;kCAC8B;IAC9B,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,iBAAiB,CAAC,EAAE,MAAM,GAAE,WAAuB,GAAG,iBAAiB;IAMzG,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"}
@@ -18,16 +18,16 @@ export class StateRegistry {
18
18
  return this.states.get(id) ?? { ...DEFAULT_STATE };
19
19
  }
20
20
  /** Replace a fixture's state and fire change listeners. */
21
- set(id, state) {
21
+ set(id, state, source = 'homekit') {
22
22
  this.states.set(id, { ...state });
23
23
  for (const l of this.listeners)
24
- l(id);
24
+ l(id, source);
25
25
  }
26
26
  /** Merge a partial update into a fixture's state, returning the new full
27
27
  * state. Fires listeners. */
28
- update(id, patch) {
28
+ update(id, patch, source = 'homekit') {
29
29
  const next = { ...this.get(id), ...patch };
30
- this.set(id, next);
30
+ this.set(id, next, source);
31
31
  return next;
32
32
  }
33
33
  onChange(cb) {
@@ -1 +1 @@
1
- {"version":3,"file":"stateRegistry.js","sourceRoot":"","sources":["../src/stateRegistry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"stateRegistry.js","sourceRoot":"","sources":["../src/stateRegistry.ts"],"names":[],"mappings":"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"}
package/examples/dmx.yaml CHANGED
@@ -74,3 +74,79 @@ patch:
74
74
  type: Dimmer
75
75
  controller: main
76
76
  start: 200
77
+
78
+ zones:
79
+ # Virtual multi-member Lightbulbs. Also handy as show targets.
80
+ - id: up
81
+ name: Up Lights
82
+ members: [a_down] # list every "up" fixture here
83
+
84
+ groups:
85
+ # Named fixture sets for show looks. Unlike zones they create no HomeKit
86
+ # tile. Members may be fixture ids or zone ids.
87
+ odd: [a_down, shed_dimmer]
88
+ even: [post_light]
89
+
90
+ palette:
91
+ # Optional color names for shows. Any CSS color name already works
92
+ # (indigo, hotpink, orange, ...); add gel names or brand colors here.
93
+ # Names match ignoring case, spaces, dashes and underscores.
94
+ surprise pink: "#f2a1ff"
95
+ boat teal: "hsv(180, 80, 100)"
96
+
97
+ shows:
98
+ # Timed light shows. Each runnable show is a HomeKit Switch; only one
99
+ # show runs at a time (starting one stops the other); shows loop unless
100
+ # `loop: false`; turning the switch off freezes the lights where they
101
+ # are; touching one of a show's lights from HomeKit stops the show.
102
+ #
103
+ # A show is a list of STEPS. Each step has a LOOK (target → color), a
104
+ # FADE time to crossfade into it, and a HOLD time to sit on it. Targets
105
+ # unmentioned in a step keep their previous value (tracking). Targets
106
+ # are fixture ids, zone ids, group ids or `all`. Times are seconds or
107
+ # "500ms".
108
+ #
109
+ # Colors: CSS names, palette names, "#hex", "3000K", "hsv(h, s, v)",
110
+ # "off"; append "@ 60%" to set brightness (CSS colors otherwise take
111
+ # their own value, so "indigo" is dimmer than "blue").
112
+
113
+ # A parameterized template. Params with `~` (null) have no default, so
114
+ # this show is a template only — no switch until something binds them.
115
+ - id: crossfade
116
+ params: { a: ~, b: ~, secs: 10 }
117
+ steps:
118
+ - look: { odd: $a, even: $b }
119
+ fade: $secs
120
+ - look: { odd: $b, even: $a }
121
+ fade: $secs
122
+
123
+ # Instances bind the params. Each becomes its own switch.
124
+ - id: texture
125
+ name: Texture
126
+ extends: crossfade
127
+ params: { a: indigo, b: surprise pink, secs: 20 }
128
+
129
+ - id: halloween
130
+ name: Halloween
131
+ extends: crossfade
132
+ params: { a: orange @ 100%, b: darkviolet, secs: 6 }
133
+
134
+ # A plain chase: no fades, quarter-second steps.
135
+ - id: chase
136
+ name: Chase
137
+ fade: 0
138
+ hold: 250ms
139
+ steps:
140
+ - look: { a_down: red, post_light: off }
141
+ - look: { a_down: off, post_light: red }
142
+
143
+ # A one-shot: runs once, then the switch turns itself off.
144
+ - id: sunrise
145
+ name: Sunrise
146
+ loop: false
147
+ ease: sine
148
+ steps:
149
+ - look: { all: "2000K @ 5%" }
150
+ fade: 2
151
+ - look: { all: "4000K @ 100%" }
152
+ fade: 5m
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ecopoesis/homebridge-dmx",
3
3
  "displayName": "DMX",
4
- "version": "0.5.5",
4
+ "version": "0.6.0",
5
5
  "description": "Homebridge platform for DMX controllers (currently Nicolaudie Stick-DE3)",
6
6
  "license": "Apache-2.0",
7
7
  "type": "module",
package/src/config.ts CHANGED
@@ -22,7 +22,11 @@
22
22
  // "patch": [
23
23
  // { "id": "a_down", "name": "A Down", "type": "WAC",
24
24
  // "controller": "main", "universe": "A", "start": 6 }
25
- // ]
25
+ // ],
26
+ // "zones": [ { "id": "up", "name": "Up Lights", "members": ["b_up", ...] } ],
27
+ // "groups": { "odd": ["b_up", ...] },
28
+ // "palette": { "surprise pink": "#f2a1ff" },
29
+ // "shows": [ ...see show/dsl.ts... ]
26
30
  // }
27
31
  //
28
32
  // Output: a normalized `LoadedConfig` the platform consumes. Validates:
@@ -41,6 +45,7 @@ import { ChannelDef, ColorModel, HKCharacteristic } from './color/types.js';
41
45
  import { REFRESH_MINUTES_DEFAULT, SACN_PRIORITY_DEFAULT } from './settings.js';
42
46
  import { getColorModel } from './color/index.js';
43
47
  import { parseChannelName } from './color/parsers.js';
48
+ import { Show, ShowSpec, loadShows, parseGroups, parsePalette } from './show/dsl.js';
44
49
 
45
50
  export interface ControllerSpec {
46
51
  id: string; // unique handle, referenced from patch entries
@@ -79,6 +84,9 @@ export interface RawConfig {
79
84
  profiles?: ProfileSpec[];
80
85
  patch?: PatchSpec[];
81
86
  zones?: ZoneSpec[];
87
+ groups?: Record<string, string[]>; // show targets: group id → fixture/zone ids (no HomeKit tile)
88
+ palette?: Record<string, unknown>; // show color names → specs (see show/colors.ts)
89
+ shows?: ShowSpec[]; // see show/dsl.ts
82
90
  }
83
91
 
84
92
  export interface Profile {
@@ -124,6 +132,7 @@ export interface LoadedConfig {
124
132
  controllers: Controller[];
125
133
  fixtures: Fixture[];
126
134
  zones: Zone[];
135
+ shows: Show[];
127
136
  }
128
137
 
129
138
  export const DEFAULT_PLATFORM_NAME = 'DMX';
@@ -323,10 +332,22 @@ export function loadConfig(rawJson: RawConfig, cwd?: string): LoadedConfig {
323
332
  });
324
333
  }
325
334
 
335
+ // Shows — parameterized step lists, each runnable one a HomeKit Switch.
336
+ const showSpecs = raw.shows ?? [];
337
+ if (!Array.isArray(showSpecs)) throw new Error('shows: must be an array');
338
+ const groups = parseGroups(raw.groups, fixtures, zones);
339
+ const shows = loadShows(showSpecs, fixtures, zones, groups, parsePalette(raw.palette));
340
+ for (const s of shows) {
341
+ if (fixturesById.has(s.id) || seenZoneIds.has(s.id) || groups.has(s.id)) {
342
+ throw new Error(`show id "${s.id}" collides with a fixture, zone or group id`);
343
+ }
344
+ }
345
+
326
346
  return {
327
347
  name: raw.name ?? DEFAULT_PLATFORM_NAME,
328
348
  controllers: [...controllersById.values()],
329
349
  fixtures,
330
350
  zones,
351
+ shows,
331
352
  };
332
353
  }
package/src/controller.ts CHANGED
@@ -15,8 +15,8 @@ import path from 'node:path';
15
15
 
16
16
  import { Fixture } from './config.js';
17
17
  import { HomeKitLightState } from './color/types.js';
18
- import { DmxController } from './dmxController.js';
19
- import { DEBOUNCE_MS, REFRESH_CHECK_MS } from './settings.js';
18
+ import { DmxController, SetOptions } from './dmxController.js';
19
+ import { DEBOUNCE_MS, REFRESH_CHECK_MS, STICK_FRAME_MS } from './settings.js';
20
20
  import { sleep } from './stick/protocol.js';
21
21
 
22
22
  const __filename = fileURLToPath(import.meta.url);
@@ -35,6 +35,7 @@ export class StickController implements DmxController {
35
35
  * we can't detect in-band) the probe is required to (re-)register
36
36
  * the client. Subsequent subprocesses can skip it. */
37
37
  private needsProbe = true;
38
+ readonly frameIntervalMs = STICK_FRAME_MS;
38
39
 
39
40
  constructor(
40
41
  private readonly ip: string,
@@ -68,15 +69,17 @@ export class StickController implements DmxController {
68
69
 
69
70
  /** Stage a fixture's bytes into the universe target buffer and ensure
70
71
  * the streaming loop is running. */
71
- setFixture(fixture: Fixture, state: HomeKitLightState): void {
72
+ setFixture(fixture: Fixture, state: HomeKitLightState, opts?: SetOptions): void {
72
73
  const arr = this.universeBuf(fixture.universe);
73
74
  const bytes = fixture.profile.model.render(state, fixture.profile.channels);
74
75
  for (let i = 0; i < bytes.length; i++) {
75
76
  arr[fixture.startCh - 1 + i] = bytes[i];
76
77
  }
77
78
  this.lastChangeAt = Date.now();
78
- const hex = Array.from(bytes).map((b) => b.toString(16).padStart(2, '0')).join('');
79
- this.log.info(`setFixture ${fixture.id}@DMX${fixture.startCh}=${hex} streaming=${this.streaming}`);
79
+ if (!opts?.quiet) {
80
+ const hex = Array.from(bytes).map((b) => b.toString(16).padStart(2, '0')).join('');
81
+ this.log.info(`setFixture ${fixture.id}@DMX${fixture.startCh}=${hex} streaming=${this.streaming}`);
82
+ }
80
83
  if (!this.streaming) {
81
84
  this.streaming = true;
82
85
  this.run().catch((e) => {
@@ -4,11 +4,20 @@
4
4
  import { Fixture } from './config.js';
5
5
  import { HomeKitLightState } from './color/types.js';
6
6
 
7
+ export interface SetOptions {
8
+ /** Skip per-call info logging (the show engine calls at frame rate). */
9
+ quiet?: boolean;
10
+ }
11
+
7
12
  export interface DmxController {
8
13
  /** Render `state` through the fixture's color model into the universe
9
14
  * buffer and (eventually) put it on the wire. Must be safe to call at
10
15
  * HomeKit interaction rates. */
11
- setFixture(fixture: Fixture, state: HomeKitLightState): void;
16
+ setFixture(fixture: Fixture, state: HomeKitLightState, opts?: SetOptions): void;
17
+ /** How often a show may push a new frame through this controller.
18
+ * Streaming transports (sACN) take 25 Hz; the Stick's subprocess
19
+ * transaction costs seconds, so shows on it step coarsely. */
20
+ readonly frameIntervalMs: number;
12
21
  /** Homebridge shutdown hook: stop timers, close sockets. */
13
22
  shutdown(): void;
14
23
  }
package/src/platform.ts CHANGED
@@ -20,6 +20,8 @@ import { DmxController } from './dmxController.js';
20
20
  import { readEthergateUniverse } from './ethergate.js';
21
21
  import { SacnController } from './sacn.js';
22
22
  import { StickFixture } from './platformAccessory.js';
23
+ import { ShowEngine } from './show/engine.js';
24
+ import { ShowSwitch } from './showAccessory.js';
23
25
  import { StateRegistry } from './stateRegistry.js';
24
26
  import { ZoneFixture } from './zoneAccessory.js';
25
27
  import { DEBOUNCE_MS, PLATFORM_NAME, PLUGIN_NAME } from './settings.js';
@@ -32,6 +34,7 @@ export class DmxPlatform implements DynamicPlatformPlugin {
32
34
  private cfg: LoadedConfig | null = null;
33
35
  private controllers = new Map<string, DmxController>();
34
36
  private registry = new StateRegistry();
37
+ private engine: ShowEngine | null = null;
35
38
  private statePollTimers: NodeJS.Timeout[] = [];
36
39
 
37
40
  constructor(
@@ -60,8 +63,16 @@ export class DmxPlatform implements DynamicPlatformPlugin {
60
63
  `DMX platform configured: ${this.cfg.controllers.length} controller` +
61
64
  `${this.cfg.controllers.length === 1 ? '' : 's'}, ` +
62
65
  `${this.cfg.fixtures.length} fixture${this.cfg.fixtures.length === 1 ? '' : 's'}, ` +
63
- `${this.cfg.zones.length} zone${this.cfg.zones.length === 1 ? '' : 's'}`,
66
+ `${this.cfg.zones.length} zone${this.cfg.zones.length === 1 ? '' : 's'}, ` +
67
+ `${this.cfg.shows.length} show${this.cfg.shows.length === 1 ? '' : 's'}`,
64
68
  );
69
+ for (const s of this.cfg.shows) {
70
+ if (!s.runnable) {
71
+ this.log.info(`show "${s.id}": template only (unset params: ${s.unboundParams.join(', ')})`);
72
+ } else if (!s.exposeSwitch) {
73
+ this.log.info(`show "${s.id}": hidden (switch: false)`);
74
+ }
75
+ }
65
76
 
66
77
  this.api.on('didFinishLaunching', () => {
67
78
  this.discoverDevices();
@@ -69,6 +80,7 @@ export class DmxPlatform implements DynamicPlatformPlugin {
69
80
  });
70
81
  this.api.on('shutdown', () => {
71
82
  for (const t of this.statePollTimers) clearInterval(t);
83
+ this.engine?.shutdown();
72
84
  for (const c of this.controllers.values()) c.shutdown();
73
85
  });
74
86
  }
@@ -121,7 +133,7 @@ export class DmxPlatform implements DynamicPlatformPlugin {
121
133
  const state = fx.profile.model.parse!(bytes, fx.profile.channels);
122
134
  const cur = this.registry.get(fx.id);
123
135
  if (JSON.stringify(cur) !== JSON.stringify(state)) {
124
- this.registry.set(fx.id, state);
136
+ this.registry.set(fx.id, state, 'sync');
125
137
  }
126
138
  }
127
139
 
@@ -190,6 +202,27 @@ export class DmxPlatform implements DynamicPlatformPlugin {
190
202
  }
191
203
  }
192
204
 
205
+ // Shows — one Switch per runnable show; the engine enforces "one at a time".
206
+ this.engine = new ShowEngine(this.cfg.shows, this.controllers, this.registry, this.log);
207
+ for (const show of this.cfg.shows) {
208
+ if (!show.exposeSwitch) continue;
209
+ const uuid = this.api.hap.uuid.generate(`dmx-show:${show.id}`);
210
+ wantUuids.add(uuid);
211
+ const existing = this.accessories.find((a) => a.UUID === uuid);
212
+ if (existing) {
213
+ this.log.debug(`wiring cached show ${show.id}`);
214
+ existing.context.show = { id: show.id };
215
+ new ShowSwitch(this, existing, show, this.engine);
216
+ } else {
217
+ this.log.info(`registering new show: ${show.name} (${show.id}, ${show.steps.length} steps)`);
218
+ const accessory = new this.api.platformAccessory(show.name, uuid);
219
+ accessory.context.show = { id: show.id };
220
+ new ShowSwitch(this, accessory, show, this.engine);
221
+ this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
222
+ this.accessories.push(accessory);
223
+ }
224
+ }
225
+
193
226
  const stale = this.accessories.filter((a) => !wantUuids.has(a.UUID));
194
227
  if (stale.length) {
195
228
  this.log.info(`unregistering ${stale.length} stale accessor${stale.length === 1 ? 'y' : 'ies'}`);
package/src/sacn.ts CHANGED
@@ -23,9 +23,10 @@ import { randomBytes } from 'node:crypto';
23
23
 
24
24
  import { Fixture } from './config.js';
25
25
  import { HomeKitLightState } from './color/types.js';
26
- import { DmxController } from './dmxController.js';
26
+ import { DmxController, SetOptions } from './dmxController.js';
27
27
  import {
28
28
  SACN_COALESCE_MS,
29
+ SACN_FRAME_MS,
29
30
  SACN_KEEPALIVE_MS,
30
31
  SACN_PORT,
31
32
  SACN_PRIORITY_DEFAULT,
@@ -45,6 +46,7 @@ export class SacnController implements DmxController {
45
46
  * Read by the platform's state-poll guard so a read-back never clobbers
46
47
  * an in-flight HomeKit change. */
47
48
  public lastChangeAt = 0;
49
+ readonly frameIntervalMs = SACN_FRAME_MS;
48
50
  private readonly socket: dgram.Socket;
49
51
  private readonly cid = randomBytes(16);
50
52
  private closed = false;
@@ -58,7 +60,7 @@ export class SacnController implements DmxController {
58
60
  this.socket.on('error', (e) => this.log.error('sACN socket error:', e.message));
59
61
  }
60
62
 
61
- setFixture(fixture: Fixture, state: HomeKitLightState): void {
63
+ setFixture(fixture: Fixture, state: HomeKitLightState, opts?: SetOptions): void {
62
64
  const arr = this.universeBuf(fixture.universe);
63
65
  const bytes = fixture.profile.model.render(state, fixture.profile.channels);
64
66
  for (let i = 0; i < bytes.length; i++) {
@@ -66,8 +68,10 @@ export class SacnController implements DmxController {
66
68
  }
67
69
  this.dirty.add(fixture.universe);
68
70
  this.lastChangeAt = Date.now();
69
- const hex = Array.from(bytes).map((b) => b.toString(16).padStart(2, '0')).join('');
70
- this.log.info(`setFixture ${fixture.id}@DMX${fixture.startCh}/U${fixture.universe + 1}=${hex}`);
71
+ if (!opts?.quiet) {
72
+ const hex = Array.from(bytes).map((b) => b.toString(16).padStart(2, '0')).join('');
73
+ this.log.info(`setFixture ${fixture.id}@DMX${fixture.startCh}/U${fixture.universe + 1}=${hex}`);
74
+ }
71
75
  this.scheduleSend();
72
76
  if (!this.keepaliveTimer) {
73
77
  this.keepaliveTimer = setInterval(() => this.sendAll(), SACN_KEEPALIVE_MS);
package/src/settings.ts CHANGED
@@ -48,3 +48,22 @@ export const SACN_PRIORITY_DEFAULT = 100;
48
48
 
49
49
  /** Source name advertised in every E1.31 framing layer (max 63 chars). */
50
50
  export const SACN_SOURCE_NAME = 'homebridge-dmx';
51
+
52
+ /** Show frame interval on sACN: 25 Hz, the same cadence the Nicolaudie
53
+ * tools stream at and well inside what a gateway accepts. */
54
+ export const SACN_FRAME_MS = 40;
55
+
56
+ // ── Shows ──────────────────────────────────────────────────────────────────
57
+
58
+ /** Show frame interval on the Stick-DE3. Each frame becomes a full
59
+ * subprocess transaction (~2 s) after the 750 ms debounce, so fades on
60
+ * the Stick are a slow staircase rather than a glide. */
61
+ export const STICK_FRAME_MS = 3000;
62
+
63
+ /** Fallback frame interval for a controller that doesn't declare one. */
64
+ export const SHOW_FRAME_MS_DEFAULT = 40;
65
+
66
+ /** Minimum spacing between the registry keyframes a running show writes
67
+ * (each one fans out into HomeKit characteristic events for every
68
+ * fixture and zone involved). */
69
+ export const SHOW_KEYFRAME_MIN_MS = 1000;