@homebridge-plugins/homebridge-matter 0.0.6 → 0.1.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 (95) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/README.md +67 -33
  3. package/config.schema.json +73 -77
  4. package/dist/devices/index.d.ts +13 -0
  5. package/dist/devices/index.js +22 -0
  6. package/dist/devices/index.js.map +1 -0
  7. package/dist/devices/section-12-robotic/index.d.ts +6 -0
  8. package/dist/devices/section-12-robotic/index.js +7 -0
  9. package/dist/devices/section-12-robotic/index.js.map +1 -0
  10. package/dist/devices/section-12-robotic/robotic-vacuum-cleaner.d.ts +63 -0
  11. package/dist/devices/section-12-robotic/robotic-vacuum-cleaner.js +318 -0
  12. package/dist/devices/section-12-robotic/robotic-vacuum-cleaner.js.map +1 -0
  13. package/dist/devices/section-4-lighting/color-temperature-light.d.ts +7 -0
  14. package/dist/devices/section-4-lighting/color-temperature-light.js +62 -0
  15. package/dist/devices/section-4-lighting/color-temperature-light.js.map +1 -0
  16. package/dist/devices/section-4-lighting/dimmable-light.d.ts +7 -0
  17. package/dist/devices/section-4-lighting/dimmable-light.js +48 -0
  18. package/dist/devices/section-4-lighting/dimmable-light.js.map +1 -0
  19. package/dist/devices/section-4-lighting/extended-color-light.d.ts +12 -0
  20. package/dist/devices/section-4-lighting/extended-color-light.js +142 -0
  21. package/dist/devices/section-4-lighting/extended-color-light.js.map +1 -0
  22. package/dist/devices/section-4-lighting/index.d.ts +9 -0
  23. package/dist/devices/section-4-lighting/index.js +10 -0
  24. package/dist/devices/section-4-lighting/index.js.map +1 -0
  25. package/dist/devices/section-4-lighting/on-off-light.d.ts +7 -0
  26. package/dist/devices/section-4-lighting/on-off-light.js +37 -0
  27. package/dist/devices/section-4-lighting/on-off-light.js.map +1 -0
  28. package/dist/devices/section-5-smart-plugs/dimmable-plug-in-unit.d.ts +7 -0
  29. package/dist/devices/section-5-smart-plugs/dimmable-plug-in-unit.js +48 -0
  30. package/dist/devices/section-5-smart-plugs/dimmable-plug-in-unit.js.map +1 -0
  31. package/dist/devices/section-5-smart-plugs/index.d.ts +7 -0
  32. package/dist/devices/section-5-smart-plugs/index.js +8 -0
  33. package/dist/devices/section-5-smart-plugs/index.js.map +1 -0
  34. package/dist/devices/section-5-smart-plugs/on-off-plug-in-unit.d.ts +7 -0
  35. package/dist/devices/section-5-smart-plugs/on-off-plug-in-unit.js +37 -0
  36. package/dist/devices/section-5-smart-plugs/on-off-plug-in-unit.js.map +1 -0
  37. package/dist/devices/section-6-switches/index.d.ts +6 -0
  38. package/dist/devices/section-6-switches/index.js +7 -0
  39. package/dist/devices/section-6-switches/index.js.map +1 -0
  40. package/dist/devices/section-6-switches/on-off-light-switch.d.ts +7 -0
  41. package/dist/devices/section-6-switches/on-off-light-switch.js +30 -0
  42. package/dist/devices/section-6-switches/on-off-light-switch.js.map +1 -0
  43. package/dist/devices/section-7-sensors/contact-sensor.d.ts +7 -0
  44. package/dist/devices/section-7-sensors/contact-sensor.js +27 -0
  45. package/dist/devices/section-7-sensors/contact-sensor.js.map +1 -0
  46. package/dist/devices/section-7-sensors/humidity-sensor.d.ts +7 -0
  47. package/dist/devices/section-7-sensors/humidity-sensor.js +29 -0
  48. package/dist/devices/section-7-sensors/humidity-sensor.js.map +1 -0
  49. package/dist/devices/section-7-sensors/index.d.ts +12 -0
  50. package/dist/devices/section-7-sensors/index.js +13 -0
  51. package/dist/devices/section-7-sensors/index.js.map +1 -0
  52. package/dist/devices/section-7-sensors/light-sensor.d.ts +7 -0
  53. package/dist/devices/section-7-sensors/light-sensor.js +29 -0
  54. package/dist/devices/section-7-sensors/light-sensor.js.map +1 -0
  55. package/dist/devices/section-7-sensors/occupancy-sensor.d.ts +8 -0
  56. package/dist/devices/section-7-sensors/occupancy-sensor.js +33 -0
  57. package/dist/devices/section-7-sensors/occupancy-sensor.js.map +1 -0
  58. package/dist/devices/section-7-sensors/smoke-co-alarm.d.ts +7 -0
  59. package/dist/devices/section-7-sensors/smoke-co-alarm.js +37 -0
  60. package/dist/devices/section-7-sensors/smoke-co-alarm.js.map +1 -0
  61. package/dist/devices/section-7-sensors/temperature-sensor.d.ts +7 -0
  62. package/dist/devices/section-7-sensors/temperature-sensor.js +29 -0
  63. package/dist/devices/section-7-sensors/temperature-sensor.js.map +1 -0
  64. package/dist/devices/section-7-sensors/water-leak-detector.d.ts +7 -0
  65. package/dist/devices/section-7-sensors/water-leak-detector.js +27 -0
  66. package/dist/devices/section-7-sensors/water-leak-detector.js.map +1 -0
  67. package/dist/devices/section-8-closure/door-lock.d.ts +7 -0
  68. package/dist/devices/section-8-closure/door-lock.js +48 -0
  69. package/dist/devices/section-8-closure/door-lock.js.map +1 -0
  70. package/dist/devices/section-8-closure/index.d.ts +7 -0
  71. package/dist/devices/section-8-closure/index.js +8 -0
  72. package/dist/devices/section-8-closure/index.js.map +1 -0
  73. package/dist/devices/section-8-closure/window-covering.d.ts +9 -0
  74. package/dist/devices/section-8-closure/window-covering.js +154 -0
  75. package/dist/devices/section-8-closure/window-covering.js.map +1 -0
  76. package/dist/devices/section-9-hvac/fan.d.ts +7 -0
  77. package/dist/devices/section-9-hvac/fan.js +56 -0
  78. package/dist/devices/section-9-hvac/fan.js.map +1 -0
  79. package/dist/devices/section-9-hvac/index.d.ts +7 -0
  80. package/dist/devices/section-9-hvac/index.js +8 -0
  81. package/dist/devices/section-9-hvac/index.js.map +1 -0
  82. package/dist/devices/section-9-hvac/thermostat.d.ts +7 -0
  83. package/dist/devices/section-9-hvac/thermostat.js +61 -0
  84. package/dist/devices/section-9-hvac/thermostat.js.map +1 -0
  85. package/dist/devices/types.d.ts +16 -0
  86. package/dist/devices/types.js +5 -0
  87. package/dist/devices/types.js.map +1 -0
  88. package/dist/homebridge-ui/public/index.html +269 -0
  89. package/dist/homebridge-ui/server.js +47 -0
  90. package/dist/platform.d.ts +25 -21
  91. package/dist/platform.js +133 -1023
  92. package/dist/platform.js.map +1 -1
  93. package/package.json +9 -9
  94. package/plugin-header.png +0 -0
  95. package/.claude/settings.local.json +0 -28
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Door Lock Device (Matter Spec § 8.1)
3
+ *
4
+ * A lock that can be locked and unlocked remotely.
5
+ */
6
+ export function registerDoorLock(context) {
7
+ const { api, log, config } = context;
8
+ const accessories = [];
9
+ if (!config.enableDoorLock) {
10
+ return accessories;
11
+ }
12
+ accessories.push({
13
+ uuid: api.matter.uuid.generate('matter-door-lock'),
14
+ displayName: 'Door Lock',
15
+ deviceType: api.matter.deviceTypes.DoorLock,
16
+ serialNumber: 'LOCK-001',
17
+ manufacturer: 'Matter Examples',
18
+ model: 'DoorLock v1',
19
+ clusters: {
20
+ doorLock: {
21
+ // Lock state: 0=NotFullyLocked, 1=Locked, 2=Unlocked
22
+ lockState: 2, // Unlocked
23
+ // Lock type: 0=Deadbolt, 1=Magnetic, 2=Other, etc.
24
+ lockType: 0, // Deadbolt
25
+ // Actuator enabled (can be locked/unlocked)
26
+ actuatorEnabled: true,
27
+ },
28
+ },
29
+ handlers: {
30
+ doorLock: {
31
+ // Called when user locks the door
32
+ lockDoor: async () => {
33
+ log.info('[Door Lock] ✓ Handler `lockDoor` called - Locking door');
34
+ // Update the lock state to "Locked" (1)
35
+ await api.matter.updateAccessoryState(api.matter.uuid.generate('matter-door-lock'), 'doorLock', { lockState: 1 });
36
+ },
37
+ // Called when user unlocks the door
38
+ unlockDoor: async () => {
39
+ log.info('[Door Lock] ✓ Handler `unlockDoor` called - Unlocking door');
40
+ // Update the lock state to "Unlocked" (2)
41
+ await api.matter.updateAccessoryState(api.matter.uuid.generate('matter-door-lock'), 'doorLock', { lockState: 2 });
42
+ },
43
+ },
44
+ },
45
+ });
46
+ return accessories;
47
+ }
48
+ //# sourceMappingURL=door-lock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"door-lock.js","sourceRoot":"","sources":["../../../src/devices/section-8-closure/door-lock.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,MAAM,UAAU,gBAAgB,CAAC,OAAsB;IACrD,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAA;IACpC,MAAM,WAAW,GAAU,EAAE,CAAA;IAE7B,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;QAC3B,OAAO,WAAW,CAAA;IACpB,CAAC;IAED,WAAW,CAAC,IAAI,CAAC;QACf,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,kBAAkB,CAAC;QAClD,WAAW,EAAE,WAAW;QACxB,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,QAAQ;QAC3C,YAAY,EAAE,UAAU;QACxB,YAAY,EAAE,iBAAiB;QAC/B,KAAK,EAAE,aAAa;QAEpB,QAAQ,EAAE;YACR,QAAQ,EAAE;gBACR,qDAAqD;gBACrD,SAAS,EAAE,CAAC,EAAE,WAAW;gBAEzB,mDAAmD;gBACnD,QAAQ,EAAE,CAAC,EAAE,WAAW;gBAExB,4CAA4C;gBAC5C,eAAe,EAAE,IAAI;aACtB;SACF;QAED,QAAQ,EAAE;YACR,QAAQ,EAAE;gBACR,kCAAkC;gBAClC,QAAQ,EAAE,KAAK,IAAI,EAAE;oBACnB,GAAG,CAAC,IAAI,CAAC,wDAAwD,CAAC,CAAA;oBAElE,wCAAwC;oBACxC,MAAM,GAAG,CAAC,MAAM,CAAC,oBAAoB,CACnC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EAC5C,UAAU,EACV,EAAE,SAAS,EAAE,CAAC,EAAE,CACjB,CAAA;gBACH,CAAC;gBAED,oCAAoC;gBACpC,UAAU,EAAE,KAAK,IAAI,EAAE;oBACrB,GAAG,CAAC,IAAI,CAAC,4DAA4D,CAAC,CAAA;oBAEtE,0CAA0C;oBAC1C,MAAM,GAAG,CAAC,MAAM,CAAC,oBAAoB,CACnC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EAC5C,UAAU,EACV,EAAE,SAAS,EAAE,CAAC,EAAE,CACjB,CAAA;gBACH,CAAC;aACF;SACF;KACF,CAAC,CAAA;IAEF,OAAO,WAAW,CAAA;AACpB,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Section 8: Closure Devices
3
+ *
4
+ * Matter Specification § 8 - Locks and window coverings
5
+ */
6
+ export { registerDoorLock } from './door-lock.js';
7
+ export { registerWindowCovering } from './window-covering.js';
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Section 8: Closure Devices
3
+ *
4
+ * Matter Specification § 8 - Locks and window coverings
5
+ */
6
+ export { registerDoorLock } from './door-lock.js';
7
+ export { registerWindowCovering } from './window-covering.js';
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/devices/section-8-closure/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AACjD,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAA"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Window Covering Device (Matter Spec § 8.3)
3
+ *
4
+ * Handles multiple variants:
5
+ * - Window Blind: Standard lift-only window covering
6
+ * - Venetian Blind: Window covering with both lift and tilt control
7
+ */
8
+ import type { DeviceContext } from '../types.js';
9
+ export declare function registerWindowCovering(context: DeviceContext): any[];
@@ -0,0 +1,154 @@
1
+ /**
2
+ * Window Covering Device (Matter Spec § 8.3)
3
+ *
4
+ * Handles multiple variants:
5
+ * - Window Blind: Standard lift-only window covering
6
+ * - Venetian Blind: Window covering with both lift and tilt control
7
+ */
8
+ export function registerWindowCovering(context) {
9
+ const { api, log, config } = context;
10
+ const accessories = [];
11
+ // Variant 1: Window Blind (lift only)
12
+ if (config.enableWindowBlind) {
13
+ accessories.push({
14
+ uuid: api.matter.uuid.generate('matter-window-blind'),
15
+ displayName: 'Window Blind',
16
+ deviceType: api.matter.deviceTypes.WindowCovering,
17
+ serialNumber: 'BLIND-001',
18
+ manufacturer: 'Matter Examples',
19
+ model: 'WindowBlind v1',
20
+ clusters: {
21
+ windowCovering: {
22
+ // Target position (0 = fully closed, 10000 = fully open, in hundredths of percent)
23
+ targetPositionLiftPercent100ths: 5000, // 50% open
24
+ currentPositionLiftPercent100ths: 5000, // 50% open
25
+ // Operational status
26
+ operationalStatus: {
27
+ global: 0, // Not moving
28
+ lift: 0,
29
+ tilt: 0,
30
+ },
31
+ // End product type
32
+ endProductType: 0, // Rollershade
33
+ // Configuration
34
+ configStatus: {
35
+ operational: true,
36
+ onlineReserved: true,
37
+ liftMovementReversed: false,
38
+ liftPositionAware: true,
39
+ tiltPositionAware: false,
40
+ liftEncoderControlled: true,
41
+ tiltEncoderControlled: false,
42
+ },
43
+ },
44
+ },
45
+ handlers: {
46
+ windowCovering: {
47
+ goToLiftPercentage: async (request) => {
48
+ const percent = (request.targetPercent / 100).toFixed(0);
49
+ log.info(`[Window Blind] ✓ Handler \`goToLiftPercentage\` called: ${request.targetPercent} (${percent}% open)`);
50
+ await api.matter.updateAccessoryState(api.matter.uuid.generate('matter-window-blind'), 'windowCovering', {
51
+ currentPositionLiftPercent100ths: request.targetPercent,
52
+ targetPositionLiftPercent100ths: request.targetPercent,
53
+ });
54
+ },
55
+ upOrOpen: async () => {
56
+ log.info('[Window Blind] ✓ Handler `upOrOpen` called - Opening blind');
57
+ await api.matter.updateAccessoryState(api.matter.uuid.generate('matter-window-blind'), 'windowCovering', {
58
+ currentPositionLiftPercent100ths: 10000, // Fully open
59
+ targetPositionLiftPercent100ths: 10000,
60
+ });
61
+ },
62
+ downOrClose: async () => {
63
+ log.info('[Window Blind] ✓ Handler `downOrClose` called - Closing blind');
64
+ await api.matter.updateAccessoryState(api.matter.uuid.generate('matter-window-blind'), 'windowCovering', {
65
+ currentPositionLiftPercent100ths: 0, // Fully closed
66
+ targetPositionLiftPercent100ths: 0,
67
+ });
68
+ },
69
+ stopMotion: async () => {
70
+ log.info('[Window Blind] ✓ Handler `stopMotion` called - Stopping blind');
71
+ },
72
+ },
73
+ },
74
+ });
75
+ }
76
+ // Variant 2: Venetian Blind (lift + tilt)
77
+ if (config.enableVenetianBlind) {
78
+ accessories.push({
79
+ uuid: api.matter.uuid.generate('matter-venetian-blind'),
80
+ displayName: 'Venetian Blind (Tilt)',
81
+ deviceType: api.matter.deviceTypes.WindowCovering,
82
+ serialNumber: 'BLIND-002',
83
+ manufacturer: 'Matter Examples',
84
+ model: 'VenetianBlind v1',
85
+ clusters: {
86
+ windowCovering: {
87
+ // Lift position (vertical position)
88
+ targetPositionLiftPercent100ths: 5000, // 50% open
89
+ currentPositionLiftPercent100ths: 5000,
90
+ // Tilt position (slat angle: 0 = closed, 10000 = fully open)
91
+ targetPositionTiltPercent100ths: 5000, // 50% tilted
92
+ currentPositionTiltPercent100ths: 5000,
93
+ // Operational status
94
+ operationalStatus: {
95
+ global: 0,
96
+ lift: 0,
97
+ tilt: 0,
98
+ },
99
+ // End product type
100
+ endProductType: 8, // Venetian blind
101
+ // Configuration: supports both lift and tilt
102
+ configStatus: {
103
+ operational: true,
104
+ onlineReserved: true,
105
+ liftMovementReversed: false,
106
+ liftPositionAware: true,
107
+ tiltPositionAware: true,
108
+ liftEncoderControlled: true,
109
+ tiltEncoderControlled: true,
110
+ },
111
+ },
112
+ },
113
+ handlers: {
114
+ windowCovering: {
115
+ goToLiftPercentage: async (request) => {
116
+ const percent = (request.targetPercent / 100).toFixed(0);
117
+ log.info(`[Venetian Blind] ✓ Handler \`goToLiftPercentage\` called: ${request.targetPercent} (${percent}% open)`);
118
+ await api.matter.updateAccessoryState(api.matter.uuid.generate('matter-venetian-blind'), 'windowCovering', {
119
+ currentPositionLiftPercent100ths: request.targetPercent,
120
+ targetPositionLiftPercent100ths: request.targetPercent,
121
+ });
122
+ },
123
+ goToTiltPercentage: async (request) => {
124
+ const percent = (request.targetPercent / 100).toFixed(0);
125
+ log.info(`[Venetian Blind] ✓ Handler \`goToTiltPercentage\` called: ${request.targetPercent} (${percent}% tilted)`);
126
+ await api.matter.updateAccessoryState(api.matter.uuid.generate('matter-venetian-blind'), 'windowCovering', {
127
+ currentPositionTiltPercent100ths: request.targetPercent,
128
+ targetPositionTiltPercent100ths: request.targetPercent,
129
+ });
130
+ },
131
+ upOrOpen: async () => {
132
+ log.info('[Venetian Blind] ✓ Handler `upOrOpen` called - Opening blind');
133
+ await api.matter.updateAccessoryState(api.matter.uuid.generate('matter-venetian-blind'), 'windowCovering', {
134
+ currentPositionLiftPercent100ths: 10000, // Fully open
135
+ targetPositionLiftPercent100ths: 10000,
136
+ });
137
+ },
138
+ downOrClose: async () => {
139
+ log.info('[Venetian Blind] ✓ Handler `downOrClose` called - Closing blind');
140
+ await api.matter.updateAccessoryState(api.matter.uuid.generate('matter-venetian-blind'), 'windowCovering', {
141
+ currentPositionLiftPercent100ths: 0, // Fully closed
142
+ targetPositionLiftPercent100ths: 0,
143
+ });
144
+ },
145
+ stopMotion: async () => {
146
+ log.info('[Venetian Blind] ✓ Handler `stopMotion` called - Stopping blind');
147
+ },
148
+ },
149
+ },
150
+ });
151
+ }
152
+ return accessories;
153
+ }
154
+ //# sourceMappingURL=window-covering.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"window-covering.js","sourceRoot":"","sources":["../../../src/devices/section-8-closure/window-covering.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,UAAU,sBAAsB,CAAC,OAAsB;IAC3D,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAA;IACpC,MAAM,WAAW,GAAU,EAAE,CAAA;IAE7B,sCAAsC;IACtC,IAAI,MAAM,CAAC,iBAAiB,EAAE,CAAC;QAC7B,WAAW,CAAC,IAAI,CAAC;YACf,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,qBAAqB,CAAC;YACrD,WAAW,EAAE,cAAc;YAC3B,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,cAAc;YACjD,YAAY,EAAE,WAAW;YACzB,YAAY,EAAE,iBAAiB;YAC/B,KAAK,EAAE,gBAAgB;YAEvB,QAAQ,EAAE;gBACR,cAAc,EAAE;oBACd,mFAAmF;oBACnF,+BAA+B,EAAE,IAAI,EAAE,WAAW;oBAClD,gCAAgC,EAAE,IAAI,EAAE,WAAW;oBAEnD,qBAAqB;oBACrB,iBAAiB,EAAE;wBACjB,MAAM,EAAE,CAAC,EAAE,aAAa;wBACxB,IAAI,EAAE,CAAC;wBACP,IAAI,EAAE,CAAC;qBACR;oBAED,mBAAmB;oBACnB,cAAc,EAAE,CAAC,EAAE,cAAc;oBAEjC,gBAAgB;oBAChB,YAAY,EAAE;wBACZ,WAAW,EAAE,IAAI;wBACjB,cAAc,EAAE,IAAI;wBACpB,oBAAoB,EAAE,KAAK;wBAC3B,iBAAiB,EAAE,IAAI;wBACvB,iBAAiB,EAAE,KAAK;wBACxB,qBAAqB,EAAE,IAAI;wBAC3B,qBAAqB,EAAE,KAAK;qBAC7B;iBACF;aACF;YAED,QAAQ,EAAE;gBACR,cAAc,EAAE;oBACd,kBAAkB,EAAE,KAAK,EAAE,OAAkC,EAAE,EAAE;wBAC/D,MAAM,OAAO,GAAG,CAAC,OAAO,CAAC,aAAa,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;wBACxD,GAAG,CAAC,IAAI,CAAC,2DAA2D,OAAO,CAAC,aAAa,KAAK,OAAO,SAAS,CAAC,CAAA;wBAE/G,MAAM,GAAG,CAAC,MAAM,CAAC,oBAAoB,CACnC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,qBAAqB,CAAC,EAC/C,gBAAgB,EAChB;4BACE,gCAAgC,EAAE,OAAO,CAAC,aAAa;4BACvD,+BAA+B,EAAE,OAAO,CAAC,aAAa;yBACvD,CACF,CAAA;oBACH,CAAC;oBAED,QAAQ,EAAE,KAAK,IAAI,EAAE;wBACnB,GAAG,CAAC,IAAI,CAAC,4DAA4D,CAAC,CAAA;wBAEtE,MAAM,GAAG,CAAC,MAAM,CAAC,oBAAoB,CACnC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,qBAAqB,CAAC,EAC/C,gBAAgB,EAChB;4BACE,gCAAgC,EAAE,KAAK,EAAE,aAAa;4BACtD,+BAA+B,EAAE,KAAK;yBACvC,CACF,CAAA;oBACH,CAAC;oBAED,WAAW,EAAE,KAAK,IAAI,EAAE;wBACtB,GAAG,CAAC,IAAI,CAAC,+DAA+D,CAAC,CAAA;wBAEzE,MAAM,GAAG,CAAC,MAAM,CAAC,oBAAoB,CACnC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,qBAAqB,CAAC,EAC/C,gBAAgB,EAChB;4BACE,gCAAgC,EAAE,CAAC,EAAE,eAAe;4BACpD,+BAA+B,EAAE,CAAC;yBACnC,CACF,CAAA;oBACH,CAAC;oBAED,UAAU,EAAE,KAAK,IAAI,EAAE;wBACrB,GAAG,CAAC,IAAI,CAAC,+DAA+D,CAAC,CAAA;oBAC3E,CAAC;iBACF;aACF;SACF,CAAC,CAAA;IACJ,CAAC;IAED,0CAA0C;IAC1C,IAAI,MAAM,CAAC,mBAAmB,EAAE,CAAC;QAC/B,WAAW,CAAC,IAAI,CAAC;YACf,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,uBAAuB,CAAC;YACvD,WAAW,EAAE,uBAAuB;YACpC,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,cAAc;YACjD,YAAY,EAAE,WAAW;YACzB,YAAY,EAAE,iBAAiB;YAC/B,KAAK,EAAE,kBAAkB;YAEzB,QAAQ,EAAE;gBACR,cAAc,EAAE;oBACd,oCAAoC;oBACpC,+BAA+B,EAAE,IAAI,EAAE,WAAW;oBAClD,gCAAgC,EAAE,IAAI;oBAEtC,6DAA6D;oBAC7D,+BAA+B,EAAE,IAAI,EAAE,aAAa;oBACpD,gCAAgC,EAAE,IAAI;oBAEtC,qBAAqB;oBACrB,iBAAiB,EAAE;wBACjB,MAAM,EAAE,CAAC;wBACT,IAAI,EAAE,CAAC;wBACP,IAAI,EAAE,CAAC;qBACR;oBAED,mBAAmB;oBACnB,cAAc,EAAE,CAAC,EAAE,iBAAiB;oBAEpC,6CAA6C;oBAC7C,YAAY,EAAE;wBACZ,WAAW,EAAE,IAAI;wBACjB,cAAc,EAAE,IAAI;wBACpB,oBAAoB,EAAE,KAAK;wBAC3B,iBAAiB,EAAE,IAAI;wBACvB,iBAAiB,EAAE,IAAI;wBACvB,qBAAqB,EAAE,IAAI;wBAC3B,qBAAqB,EAAE,IAAI;qBAC5B;iBACF;aACF;YAED,QAAQ,EAAE;gBACR,cAAc,EAAE;oBACd,kBAAkB,EAAE,KAAK,EAAE,OAAkC,EAAE,EAAE;wBAC/D,MAAM,OAAO,GAAG,CAAC,OAAO,CAAC,aAAa,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;wBACxD,GAAG,CAAC,IAAI,CAAC,6DAA6D,OAAO,CAAC,aAAa,KAAK,OAAO,SAAS,CAAC,CAAA;wBAEjH,MAAM,GAAG,CAAC,MAAM,CAAC,oBAAoB,CACnC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,uBAAuB,CAAC,EACjD,gBAAgB,EAChB;4BACE,gCAAgC,EAAE,OAAO,CAAC,aAAa;4BACvD,+BAA+B,EAAE,OAAO,CAAC,aAAa;yBACvD,CACF,CAAA;oBACH,CAAC;oBAED,kBAAkB,EAAE,KAAK,EAAE,OAAkC,EAAE,EAAE;wBAC/D,MAAM,OAAO,GAAG,CAAC,OAAO,CAAC,aAAa,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;wBACxD,GAAG,CAAC,IAAI,CAAC,6DAA6D,OAAO,CAAC,aAAa,KAAK,OAAO,WAAW,CAAC,CAAA;wBAEnH,MAAM,GAAG,CAAC,MAAM,CAAC,oBAAoB,CACnC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,uBAAuB,CAAC,EACjD,gBAAgB,EAChB;4BACE,gCAAgC,EAAE,OAAO,CAAC,aAAa;4BACvD,+BAA+B,EAAE,OAAO,CAAC,aAAa;yBACvD,CACF,CAAA;oBACH,CAAC;oBAED,QAAQ,EAAE,KAAK,IAAI,EAAE;wBACnB,GAAG,CAAC,IAAI,CAAC,8DAA8D,CAAC,CAAA;wBAExE,MAAM,GAAG,CAAC,MAAM,CAAC,oBAAoB,CACnC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,uBAAuB,CAAC,EACjD,gBAAgB,EAChB;4BACE,gCAAgC,EAAE,KAAK,EAAE,aAAa;4BACtD,+BAA+B,EAAE,KAAK;yBACvC,CACF,CAAA;oBACH,CAAC;oBAED,WAAW,EAAE,KAAK,IAAI,EAAE;wBACtB,GAAG,CAAC,IAAI,CAAC,iEAAiE,CAAC,CAAA;wBAE3E,MAAM,GAAG,CAAC,MAAM,CAAC,oBAAoB,CACnC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,uBAAuB,CAAC,EACjD,gBAAgB,EAChB;4BACE,gCAAgC,EAAE,CAAC,EAAE,eAAe;4BACpD,+BAA+B,EAAE,CAAC;yBACnC,CACF,CAAA;oBACH,CAAC;oBAED,UAAU,EAAE,KAAK,IAAI,EAAE;wBACrB,GAAG,CAAC,IAAI,CAAC,iEAAiE,CAAC,CAAA;oBAC7E,CAAC;iBACF;aACF;SACF,CAAC,CAAA;IACJ,CAAC;IAED,OAAO,WAAW,CAAA;AACpB,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Fan Device (Matter Spec § 9.2)
3
+ *
4
+ * A fan with speed control and mode selection.
5
+ */
6
+ import type { DeviceContext } from '../types.js';
7
+ export declare function registerFan(context: DeviceContext): any[];
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Fan Device (Matter Spec § 9.2)
3
+ *
4
+ * A fan with speed control and mode selection.
5
+ */
6
+ export function registerFan(context) {
7
+ const { api, log, config } = context;
8
+ const accessories = [];
9
+ if (!config.enableFan) {
10
+ return accessories;
11
+ }
12
+ accessories.push({
13
+ uuid: api.matter.uuid.generate('matter-fan'),
14
+ displayName: 'Fan',
15
+ deviceType: api.matter.deviceTypes.Fan,
16
+ serialNumber: 'FAN-001',
17
+ manufacturer: 'Matter Examples',
18
+ model: 'Fan v1',
19
+ clusters: {
20
+ fanControl: {
21
+ // Fan mode: 0=Off, 1=Low, 2=Medium, 3=High, 4=On, 5=Auto, 6=Smart
22
+ fanMode: 0, // Off
23
+ // Fan mode sequence: indicates which modes are supported
24
+ // 0=OffLowMedHigh, 1=OffLowHigh, 2=OffLowMedHighAuto, 3=OffLowHighAuto, 4=OffOnAuto, 5=OffOn
25
+ fanModeSequence: 0, // OffLowMedHigh
26
+ // Percent setting (0-100)
27
+ percentSetting: 0,
28
+ percentCurrent: 0,
29
+ // Speed setting (0-100, some fans use this instead of percent)
30
+ speedSetting: 0,
31
+ speedCurrent: 0,
32
+ },
33
+ },
34
+ handlers: {
35
+ fanControl: {
36
+ // Called when user changes fan speed via percent slider
37
+ setPercentSetting: async (request) => {
38
+ log.info(`[Fan] ✓ Handler \`setPercentSetting\` called: ${request.percentSetting}%`);
39
+ },
40
+ // Called when user changes fan mode
41
+ setFanMode: async (request) => {
42
+ const modes = ['Off', 'Low', 'Medium', 'High', 'On', 'Auto', 'Smart'];
43
+ const modeName = modes[request.fanMode] || `Unknown (${request.fanMode})`;
44
+ log.info(`[Fan] ✓ Handler \`setFanMode\` called: ${request.fanMode} (${modeName})`);
45
+ },
46
+ // Called when user presses up/down buttons to adjust speed
47
+ step: async (request) => {
48
+ const dir = request.direction === 0 ? 'Up' : 'Down';
49
+ log.info(`[Fan] ✓ Handler \`step\` called: direction=${dir}, wrap=${request.wrap}, lowestOff=${request.lowestOff}`);
50
+ },
51
+ },
52
+ },
53
+ });
54
+ return accessories;
55
+ }
56
+ //# sourceMappingURL=fan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fan.js","sourceRoot":"","sources":["../../../src/devices/section-9-hvac/fan.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,MAAM,UAAU,WAAW,CAAC,OAAsB;IAChD,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAA;IACpC,MAAM,WAAW,GAAU,EAAE,CAAA;IAE7B,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;QACtB,OAAO,WAAW,CAAA;IACpB,CAAC;IAED,WAAW,CAAC,IAAI,CAAC;QACf,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC;QAC5C,WAAW,EAAE,KAAK;QAClB,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,GAAG;QACtC,YAAY,EAAE,SAAS;QACvB,YAAY,EAAE,iBAAiB;QAC/B,KAAK,EAAE,QAAQ;QAEf,QAAQ,EAAE;YACR,UAAU,EAAE;gBACV,kEAAkE;gBAClE,OAAO,EAAE,CAAC,EAAE,MAAM;gBAElB,yDAAyD;gBACzD,6FAA6F;gBAC7F,eAAe,EAAE,CAAC,EAAE,gBAAgB;gBAEpC,0BAA0B;gBAC1B,cAAc,EAAE,CAAC;gBACjB,cAAc,EAAE,CAAC;gBAEjB,+DAA+D;gBAC/D,YAAY,EAAE,CAAC;gBACf,YAAY,EAAE,CAAC;aAChB;SACF;QAED,QAAQ,EAAE;YACR,UAAU,EAAE;gBACV,wDAAwD;gBACxD,iBAAiB,EAAE,KAAK,EAAE,OAAmC,EAAE,EAAE;oBAC/D,GAAG,CAAC,IAAI,CAAC,iDAAiD,OAAO,CAAC,cAAc,GAAG,CAAC,CAAA;gBACtF,CAAC;gBAED,oCAAoC;gBACpC,UAAU,EAAE,KAAK,EAAE,OAA4B,EAAE,EAAE;oBACjD,MAAM,KAAK,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,CAAA;oBACrE,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,YAAY,OAAO,CAAC,OAAO,GAAG,CAAA;oBACzE,GAAG,CAAC,IAAI,CAAC,0CAA0C,OAAO,CAAC,OAAO,KAAK,QAAQ,GAAG,CAAC,CAAA;gBACrF,CAAC;gBAED,2DAA2D;gBAC3D,IAAI,EAAE,KAAK,EAAE,OAAiE,EAAE,EAAE;oBAChF,MAAM,GAAG,GAAG,OAAO,CAAC,SAAS,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAA;oBACnD,GAAG,CAAC,IAAI,CAAC,8CAA8C,GAAG,UAAU,OAAO,CAAC,IAAI,eAAe,OAAO,CAAC,SAAS,EAAE,CAAC,CAAA;gBACrH,CAAC;aACF;SACF;KACF,CAAC,CAAA;IAEF,OAAO,WAAW,CAAA;AACpB,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Section 9: HVAC
3
+ *
4
+ * Matter Specification § 9 - Heating, ventilation, and air conditioning
5
+ */
6
+ export { registerFan } from './fan.js';
7
+ export { registerThermostat } from './thermostat.js';
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Section 9: HVAC
3
+ *
4
+ * Matter Specification § 9 - Heating, ventilation, and air conditioning
5
+ */
6
+ export { registerFan } from './fan.js';
7
+ export { registerThermostat } from './thermostat.js';
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/devices/section-9-hvac/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AACtC,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Thermostat Device (Matter Spec § 9.1)
3
+ *
4
+ * A device for controlling heating and cooling systems.
5
+ */
6
+ import type { DeviceContext } from '../types.js';
7
+ export declare function registerThermostat(context: DeviceContext): any[];
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Thermostat Device (Matter Spec § 9.1)
3
+ *
4
+ * A device for controlling heating and cooling systems.
5
+ */
6
+ export function registerThermostat(context) {
7
+ const { api, log, config } = context;
8
+ const accessories = [];
9
+ if (!config.enableThermostat) {
10
+ return accessories;
11
+ }
12
+ accessories.push({
13
+ uuid: api.matter.uuid.generate('matter-thermostat'),
14
+ displayName: 'Thermostat',
15
+ deviceType: api.matter.deviceTypes.Thermostat,
16
+ serialNumber: 'THERMO-001',
17
+ manufacturer: 'Matter Examples',
18
+ model: 'Thermostat v1',
19
+ clusters: {
20
+ thermostat: {
21
+ // Current temperature (in hundredths of degrees Celsius)
22
+ localTemperature: 2100, // 21.00°C
23
+ // Heating setpoint (target temperature in heat mode)
24
+ occupiedHeatingSetpoint: 2000, // 20.00°C
25
+ minHeatSetpointLimit: 700, // 7°C minimum
26
+ maxHeatSetpointLimit: 3000, // 30°C maximum
27
+ // Cooling setpoint (target temperature in cool mode)
28
+ occupiedCoolingSetpoint: 2400, // 24.00°C
29
+ minCoolSetpointLimit: 1600, // 16°C minimum
30
+ maxCoolSetpointLimit: 3200, // 32°C maximum
31
+ // System mode: 0=Off, 1=Auto, 3=Cool, 4=Heat
32
+ systemMode: 4, // Heat mode
33
+ // Control sequence: what modes are available (mandatory field)
34
+ // 4 = CoolingAndHeating (correct value when both Heating & Cooling features are present)
35
+ controlSequenceOfOperation: 4,
36
+ },
37
+ },
38
+ handlers: {
39
+ thermostat: {
40
+ // Called when user changes heating setpoint
41
+ setOccupiedHeatingSetpoint: async (request) => {
42
+ const tempC = (request.targetSetpoint / 100).toFixed(1);
43
+ log.info(`[Thermostat] ✓ Handler \`setOccupiedHeatingSetpoint\` called: ${request.targetSetpoint} (${tempC}°C)`);
44
+ },
45
+ // Called when user changes cooling setpoint
46
+ setOccupiedCoolingSetpoint: async (request) => {
47
+ const tempC = (request.targetSetpoint / 100).toFixed(1);
48
+ log.info(`[Thermostat] ✓ Handler \`setOccupiedCoolingSetpoint\` called: ${request.targetSetpoint} (${tempC}°C)`);
49
+ },
50
+ // Called when user changes mode (Off, Auto, Cool, Heat)
51
+ setSystemMode: async (request) => {
52
+ const modes = ['Off', 'Auto', 'Reserved', 'Cool', 'Heat', 'Emergency Heating', 'Precooling', 'Fan Only'];
53
+ const modeName = modes[request.systemMode] || `Unknown (${request.systemMode})`;
54
+ log.info(`[Thermostat] ✓ Handler \`setSystemMode\` called: ${request.systemMode} (${modeName})`);
55
+ },
56
+ },
57
+ },
58
+ });
59
+ return accessories;
60
+ }
61
+ //# sourceMappingURL=thermostat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thermostat.js","sourceRoot":"","sources":["../../../src/devices/section-9-hvac/thermostat.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,MAAM,UAAU,kBAAkB,CAAC,OAAsB;IACvD,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAA;IACpC,MAAM,WAAW,GAAU,EAAE,CAAA;IAE7B,IAAI,CAAC,MAAM,CAAC,gBAAgB,EAAE,CAAC;QAC7B,OAAO,WAAW,CAAA;IACpB,CAAC;IAED,WAAW,CAAC,IAAI,CAAC;QACf,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,mBAAmB,CAAC;QACnD,WAAW,EAAE,YAAY;QACzB,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,UAAU;QAC7C,YAAY,EAAE,YAAY;QAC1B,YAAY,EAAE,iBAAiB;QAC/B,KAAK,EAAE,eAAe;QAEtB,QAAQ,EAAE;YACR,UAAU,EAAE;gBACV,yDAAyD;gBACzD,gBAAgB,EAAE,IAAI,EAAE,UAAU;gBAElC,qDAAqD;gBACrD,uBAAuB,EAAE,IAAI,EAAE,UAAU;gBACzC,oBAAoB,EAAE,GAAG,EAAE,cAAc;gBACzC,oBAAoB,EAAE,IAAI,EAAE,eAAe;gBAE3C,qDAAqD;gBACrD,uBAAuB,EAAE,IAAI,EAAE,UAAU;gBACzC,oBAAoB,EAAE,IAAI,EAAE,eAAe;gBAC3C,oBAAoB,EAAE,IAAI,EAAE,eAAe;gBAE3C,6CAA6C;gBAC7C,UAAU,EAAE,CAAC,EAAE,YAAY;gBAE3B,+DAA+D;gBAC/D,yFAAyF;gBACzF,0BAA0B,EAAE,CAAC;aAC9B;SACF;QAED,QAAQ,EAAE;YACR,UAAU,EAAE;gBACV,4CAA4C;gBAC5C,0BAA0B,EAAE,KAAK,EAAE,OAAmC,EAAE,EAAE;oBACxE,MAAM,KAAK,GAAG,CAAC,OAAO,CAAC,cAAc,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;oBACvD,GAAG,CAAC,IAAI,CAAC,iEAAiE,OAAO,CAAC,cAAc,KAAK,KAAK,KAAK,CAAC,CAAA;gBAClH,CAAC;gBAED,4CAA4C;gBAC5C,0BAA0B,EAAE,KAAK,EAAE,OAAmC,EAAE,EAAE;oBACxE,MAAM,KAAK,GAAG,CAAC,OAAO,CAAC,cAAc,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;oBACvD,GAAG,CAAC,IAAI,CAAC,iEAAiE,OAAO,CAAC,cAAc,KAAK,KAAK,KAAK,CAAC,CAAA;gBAClH,CAAC;gBAED,wDAAwD;gBACxD,aAAa,EAAE,KAAK,EAAE,OAA+B,EAAE,EAAE;oBACvD,MAAM,KAAK,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,mBAAmB,EAAE,YAAY,EAAE,UAAU,CAAC,CAAA;oBACxG,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,YAAY,OAAO,CAAC,UAAU,GAAG,CAAA;oBAC/E,GAAG,CAAC,IAAI,CAAC,oDAAoD,OAAO,CAAC,UAAU,KAAK,QAAQ,GAAG,CAAC,CAAA;gBAClG,CAAC;aACF;SACF;KACF,CAAC,CAAA;IAEF,OAAO,WAAW,CAAA;AACpB,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Common types for Matter device implementations
3
+ */
4
+ import type { API, Logging, PlatformConfig } from 'homebridge';
5
+ /**
6
+ * Device registration function signature
7
+ */
8
+ export type DeviceRegistrar = (api: API, log: Logging, config: PlatformConfig) => any[];
9
+ /**
10
+ * Base context passed to all device registrars
11
+ */
12
+ export interface DeviceContext {
13
+ api: API;
14
+ log: Logging;
15
+ config: PlatformConfig;
16
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Common types for Matter device implementations
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/devices/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}