@homebridge-plugins/homebridge-matter 0.1.1-beta.1 → 0.1.1-beta.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.
- package/dist/devices/section-12-robotic/robotic-vacuum-cleaner.d.ts +1 -1
- package/dist/devices/section-12-robotic/robotic-vacuum-cleaner.js +8 -8
- package/dist/devices/section-12-robotic/robotic-vacuum-cleaner.js.map +1 -1
- package/dist/devices/section-4-lighting/color-temperature-light.js +2 -1
- package/dist/devices/section-4-lighting/color-temperature-light.js.map +1 -1
- package/dist/devices/section-4-lighting/dimmable-light.d.ts +24 -0
- package/dist/devices/section-4-lighting/dimmable-light.js +323 -11
- package/dist/devices/section-4-lighting/dimmable-light.js.map +1 -1
- package/dist/devices/section-4-lighting/extended-color-light.d.ts +24 -0
- package/dist/devices/section-4-lighting/extended-color-light.js +388 -5
- package/dist/devices/section-4-lighting/extended-color-light.js.map +1 -1
- package/dist/devices/section-4-lighting/on-off-light.d.ts +29 -0
- package/dist/devices/section-4-lighting/on-off-light.js +467 -10
- package/dist/devices/section-4-lighting/on-off-light.js.map +1 -1
- package/dist/devices/section-8-closure/door-lock.js +7 -6
- package/dist/devices/section-8-closure/door-lock.js.map +1 -1
- package/dist/devices/section-8-closure/window-covering.js +7 -7
- package/dist/devices/section-8-closure/window-covering.js.map +1 -1
- package/dist/devices/section-9-hvac/fan.js +4 -3
- package/dist/devices/section-9-hvac/fan.js.map +1 -1
- package/dist/devices/section-9-hvac/thermostat.js +4 -4
- package/dist/devices/section-9-hvac/thermostat.js.map +1 -1
- package/dist/homebridge-ui/public/index.html +13 -0
- package/dist/platform.d.ts +1 -1
- package/dist/platform.js +1 -1
- package/package.json +5 -4
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* 1. Dedicated Matter Server: Gets its own MatterServer instance
|
|
16
16
|
* 2. Automatic Port Allocation: Receives a unique port (e.g., 5541)
|
|
17
17
|
* 3. Separate Commissioning: Gets its own QR code and manual pairing code
|
|
18
|
-
* 4. Isolation: Completely independent
|
|
18
|
+
* 4. Isolation: Completely independent of other Matter accessories
|
|
19
19
|
* 5. Apple Home Compatible: Works properly with Apple Home's RVC requirements
|
|
20
20
|
*
|
|
21
21
|
* When you start Homebridge, you'll see logs like:
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* 1. Dedicated Matter Server: Gets its own MatterServer instance
|
|
16
16
|
* 2. Automatic Port Allocation: Receives a unique port (e.g., 5541)
|
|
17
17
|
* 3. Separate Commissioning: Gets its own QR code and manual pairing code
|
|
18
|
-
* 4. Isolation: Completely independent
|
|
18
|
+
* 4. Isolation: Completely independent of other Matter accessories
|
|
19
19
|
* 5. Apple Home Compatible: Works properly with Apple Home's RVC requirements
|
|
20
20
|
*
|
|
21
21
|
* When you start Homebridge, you'll see logs like:
|
|
@@ -146,7 +146,7 @@ export function registerRoboticVacuumCleaner(context) {
|
|
|
146
146
|
// Example: await yourVacuumAPI.pause()
|
|
147
147
|
// Update Matter state to reflect the change
|
|
148
148
|
// This notifies all connected Home apps of the new state
|
|
149
|
-
|
|
149
|
+
return api.matter.updateAccessoryState(uuid, // Use the same UUID we generated above
|
|
150
150
|
'rvcOperationalState', { operationalState: 2 });
|
|
151
151
|
},
|
|
152
152
|
/**
|
|
@@ -162,7 +162,7 @@ export function registerRoboticVacuumCleaner(context) {
|
|
|
162
162
|
// TODO: Send resume command to your actual robot vacuum here
|
|
163
163
|
// Example: await yourVacuumAPI.resume()
|
|
164
164
|
// Update Matter state to Running
|
|
165
|
-
|
|
165
|
+
return api.matter.updateAccessoryState(uuid, 'rvcOperationalState', { operationalState: 1 });
|
|
166
166
|
},
|
|
167
167
|
/**
|
|
168
168
|
* goHome() - Called when user sends robot to charging dock
|
|
@@ -177,7 +177,7 @@ export function registerRoboticVacuumCleaner(context) {
|
|
|
177
177
|
// TODO: Send return-to-dock command to your actual robot vacuum here
|
|
178
178
|
// Example: await yourVacuumAPI.returnToDock()
|
|
179
179
|
// Update Matter state to SeekingCharger
|
|
180
|
-
|
|
180
|
+
return api.matter.updateAccessoryState(uuid, 'rvcOperationalState', { operationalState: 64 });
|
|
181
181
|
// TIP: You could set up a timer or polling to detect when the vacuum
|
|
182
182
|
// actually docks, then update to state 66 (Docked) or 65 (Charging)
|
|
183
183
|
},
|
|
@@ -208,7 +208,7 @@ export function registerRoboticVacuumCleaner(context) {
|
|
|
208
208
|
// await yourVacuumAPI.idle()
|
|
209
209
|
// }
|
|
210
210
|
// Update Matter state
|
|
211
|
-
|
|
211
|
+
return api.matter.updateAccessoryState(uuid, 'rvcRunMode', { currentMode: request.newMode });
|
|
212
212
|
},
|
|
213
213
|
},
|
|
214
214
|
// RVC Clean Mode handlers - change cleaning method
|
|
@@ -237,7 +237,7 @@ export function registerRoboticVacuumCleaner(context) {
|
|
|
237
237
|
// await yourVacuumAPI.setMode('vacuum_and_mop')
|
|
238
238
|
// }
|
|
239
239
|
// Update Matter state
|
|
240
|
-
|
|
240
|
+
return api.matter.updateAccessoryState(uuid, 'rvcCleanMode', { currentMode: request.newMode });
|
|
241
241
|
},
|
|
242
242
|
},
|
|
243
243
|
},
|
|
@@ -277,13 +277,13 @@ export function registerRoboticVacuumCleaner(context) {
|
|
|
277
277
|
// try {
|
|
278
278
|
// await vacuumAPI.pause()
|
|
279
279
|
// log.info('Successfully paused vacuum')
|
|
280
|
-
//
|
|
280
|
+
// return api.matter.updateAccessoryState(uuid, 'rvcOperationalState', {
|
|
281
281
|
// operationalState: 2 // Paused
|
|
282
282
|
// })
|
|
283
283
|
// } catch (error) {
|
|
284
284
|
// log.error('Failed to pause vacuum:', error)
|
|
285
285
|
// // Optionally set error state
|
|
286
|
-
//
|
|
286
|
+
// return api.matter.updateAccessoryState(uuid, 'rvcOperationalState', {
|
|
287
287
|
// operationalState: 3, // Error
|
|
288
288
|
// operationalError: { errorStateId: 1 }
|
|
289
289
|
// })
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"robotic-vacuum-cleaner.js","sourceRoot":"","sources":["../../../src/devices/section-12-robotic/robotic-vacuum-cleaner.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"robotic-vacuum-cleaner.js","sourceRoot":"","sources":["../../../src/devices/section-12-robotic/robotic-vacuum-cleaner.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* A lighting device with color temperature control.
|
|
5
5
|
*/
|
|
6
|
+
import { MatterTypes } from 'homebridge';
|
|
6
7
|
export function registerColorTemperatureLight(context) {
|
|
7
8
|
const { api, log, config } = context;
|
|
8
9
|
const accessories = [];
|
|
@@ -26,7 +27,7 @@ export function registerColorTemperatureLight(context) {
|
|
|
26
27
|
maxLevel: 254, // Maximum brightness
|
|
27
28
|
},
|
|
28
29
|
colorControl: {
|
|
29
|
-
colorMode:
|
|
30
|
+
colorMode: MatterTypes.ColorControl.ColorMode.ColorTemperatureMireds, // Color temperature mode
|
|
30
31
|
colorTemperatureMireds: 250, // Current color temp: ~4000K (neutral white)
|
|
31
32
|
colorTempPhysicalMinMireds: 147, // Coolest temp: 6800K (blue-ish white)
|
|
32
33
|
colorTempPhysicalMaxMireds: 454, // Warmest temp: 2200K (orange-ish warm)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"color-temperature-light.js","sourceRoot":"","sources":["../../../src/devices/section-4-lighting/color-temperature-light.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"color-temperature-light.js","sourceRoot":"","sources":["../../../src/devices/section-4-lighting/color-temperature-light.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAIxC,MAAM,UAAU,6BAA6B,CAAC,OAAsB;IAClE,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAA;IACpC,MAAM,WAAW,GAAU,EAAE,CAAA;IAE7B,IAAI,CAAC,MAAM,CAAC,4BAA4B,EAAE,CAAC;QACzC,OAAO,WAAW,CAAA;IACpB,CAAC;IAED,WAAW,CAAC,IAAI,CAAC;QACf,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,0BAA0B,CAAC;QAC1D,WAAW,EAAE,0BAA0B;QACvC,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,qBAAqB;QACxD,YAAY,EAAE,WAAW;QACzB,YAAY,EAAE,iBAAiB;QAC/B,KAAK,EAAE,oBAAoB;QAE3B,QAAQ,EAAE;YACR,KAAK,EAAE;gBACL,KAAK,EAAE,KAAK,EAAE,qBAAqB;aACpC;YACD,YAAY,EAAE;gBACZ,YAAY,EAAE,GAAG,EAAE,wCAAwC;gBAC3D,QAAQ,EAAE,CAAC,EAAE,qBAAqB;gBAClC,QAAQ,EAAE,GAAG,EAAE,qBAAqB;aACrC;YACD,YAAY,EAAE;gBACZ,SAAS,EAAE,WAAW,CAAC,YAAY,CAAC,SAAS,CAAC,sBAAsB,EAAE,yBAAyB;gBAC/F,sBAAsB,EAAE,GAAG,EAAE,6CAA6C;gBAC1E,0BAA0B,EAAE,GAAG,EAAE,uCAAuC;gBACxE,0BAA0B,EAAE,GAAG,EAAE,wCAAwC;gBACzE,+BAA+B,EAAE,GAAG,EAAE,6CAA6C;aACpF;SACF;QAED,QAAQ,EAAE;YACR,KAAK,EAAE;gBACL,EAAE,EAAE,KAAK,IAAI,EAAE;oBACb,GAAG,CAAC,IAAI,CAAC,0EAA0E,CAAC,CAAA;oBAEpF,iDAAiD;oBACjD,qCAAqC;gBACvC,CAAC;gBACD,GAAG,EAAE,KAAK,IAAI,EAAE;oBACd,GAAG,CAAC,IAAI,CAAC,2EAA2E,CAAC,CAAA;oBAErF,iDAAiD;oBACjD,sCAAsC;gBACxC,CAAC;aACF;YACD,YAAY,EAAE;gBACZ,oBAAoB,EAAE,KAAK,EAAE,OAAmC,EAAE,EAAE;oBAClE,MAAM,EAAE,KAAK,EAAE,GAAG,OAAO,CAAA;oBACzB,GAAG,CAAC,IAAI,CAAC,6DAA6D,KAAK,KAAK,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,GAAG,GAAG,CAAC,IAAI,CAAC,CAAA;oBAElH,sDAAsD;oBACtD,yEAAyE;gBAC3E,CAAC;aACF;YACD,YAAY,EAAE;gBACZ,2BAA2B,EAAE,KAAK,EAAE,OAAyD,EAAE,EAAE;oBAC/F,MAAM,EAAE,YAAY,EAAE,cAAc,EAAE,GAAG,OAAO,CAAA;oBAChD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,YAAY,CAAC,CAAA;oBACjD,GAAG,CAAC,IAAI,CAAC,6EAA6E,YAAY,aAAa,MAAM,mBAAmB,cAAc,GAAG,CAAC,CAAA;oBAE1J,6DAA6D;oBAC7D,4DAA4D;oBAC5D,wDAAwD;gBAC1D,CAAC;aACF;SACF;KACF,CAAC,CAAA;IAEF,OAAO,WAAW,CAAA;AACpB,CAAC"}
|
|
@@ -2,6 +2,30 @@
|
|
|
2
2
|
* Dimmable Light Device (Matter Spec § 4.2)
|
|
3
3
|
*
|
|
4
4
|
* A lighting device with on/off and level control (brightness).
|
|
5
|
+
*
|
|
6
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
7
|
+
* ARCHITECTURE: THE TWO-WAY FLOW (applies to all Matter accessories)
|
|
8
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
9
|
+
*
|
|
10
|
+
* FLOW A: Home App → Physical Device (AUTOMATIC - via handlers)
|
|
11
|
+
* ────────────────────────────────────────────────────────────────
|
|
12
|
+
* 1. User controls via Home App
|
|
13
|
+
* 2. Matter command → Homebridge → Your handler runs
|
|
14
|
+
* 3. You control your physical device (API, MQTT, etc.)
|
|
15
|
+
* 4. Homebridge AUTOMATICALLY updates Matter state (calls super methods)
|
|
16
|
+
* 5. All controllers are notified
|
|
17
|
+
* ✅ No manual state update needed!
|
|
18
|
+
*
|
|
19
|
+
* FLOW B: Physical Device → Home App (MANUAL - you must update state)
|
|
20
|
+
* ────────────────────────────────────────────────────────────────
|
|
21
|
+
* 1. Physical device changes (button press, cloud app, automation)
|
|
22
|
+
* 2. ❌ Homebridge has NO IDEA this happened!
|
|
23
|
+
* 3. You MUST monitor device (events/polling) and detect change
|
|
24
|
+
* 4. You MUST call api.matter.updateAccessoryState() to update Matter
|
|
25
|
+
* 5. Then all controllers are notified
|
|
26
|
+
*
|
|
27
|
+
* This example demonstrates BOTH flows with multiple clusters (on/off + brightness).
|
|
28
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
5
29
|
*/
|
|
6
30
|
import type { DeviceContext } from '../types.js';
|
|
7
31
|
export declare function registerDimmableLight(context: DeviceContext): any[];
|
|
@@ -2,6 +2,30 @@
|
|
|
2
2
|
* Dimmable Light Device (Matter Spec § 4.2)
|
|
3
3
|
*
|
|
4
4
|
* A lighting device with on/off and level control (brightness).
|
|
5
|
+
*
|
|
6
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
7
|
+
* ARCHITECTURE: THE TWO-WAY FLOW (applies to all Matter accessories)
|
|
8
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
9
|
+
*
|
|
10
|
+
* FLOW A: Home App → Physical Device (AUTOMATIC - via handlers)
|
|
11
|
+
* ────────────────────────────────────────────────────────────────
|
|
12
|
+
* 1. User controls via Home App
|
|
13
|
+
* 2. Matter command → Homebridge → Your handler runs
|
|
14
|
+
* 3. You control your physical device (API, MQTT, etc.)
|
|
15
|
+
* 4. Homebridge AUTOMATICALLY updates Matter state (calls super methods)
|
|
16
|
+
* 5. All controllers are notified
|
|
17
|
+
* ✅ No manual state update needed!
|
|
18
|
+
*
|
|
19
|
+
* FLOW B: Physical Device → Home App (MANUAL - you must update state)
|
|
20
|
+
* ────────────────────────────────────────────────────────────────
|
|
21
|
+
* 1. Physical device changes (button press, cloud app, automation)
|
|
22
|
+
* 2. ❌ Homebridge has NO IDEA this happened!
|
|
23
|
+
* 3. You MUST monitor device (events/polling) and detect change
|
|
24
|
+
* 4. You MUST call api.matter.updateAccessoryState() to update Matter
|
|
25
|
+
* 5. Then all controllers are notified
|
|
26
|
+
*
|
|
27
|
+
* This example demonstrates BOTH flows with multiple clusters (on/off + brightness).
|
|
28
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
5
29
|
*/
|
|
6
30
|
export function registerDimmableLight(context) {
|
|
7
31
|
const { api, log, config } = context;
|
|
@@ -9,7 +33,7 @@ export function registerDimmableLight(context) {
|
|
|
9
33
|
if (!config.enableDimmableLight) {
|
|
10
34
|
return accessories;
|
|
11
35
|
}
|
|
12
|
-
|
|
36
|
+
const accessory = {
|
|
13
37
|
uuid: api.matter.uuid.generate('matter-dimmable-light'),
|
|
14
38
|
displayName: 'Dimmable Light',
|
|
15
39
|
deviceType: api.matter.deviceTypes.DimmableLight,
|
|
@@ -26,29 +50,317 @@ export function registerDimmableLight(context) {
|
|
|
26
50
|
maxLevel: 254, // Maximum brightness (Matter spec maximum, 0 is reserved for "off")
|
|
27
51
|
},
|
|
28
52
|
},
|
|
53
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
54
|
+
// FLOW A: HOME APP → PHYSICAL DEVICE
|
|
55
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
56
|
+
// These handlers are called when users control via Home app
|
|
57
|
+
// After your handler runs, Homebridge AUTOMATICALLY updates Matter state
|
|
29
58
|
handlers: {
|
|
30
59
|
onOff: {
|
|
60
|
+
/**
|
|
61
|
+
* Called when user turns the light ON via Home app
|
|
62
|
+
*
|
|
63
|
+
* IMPORTANT: After this handler completes, Homebridge AUTOMATICALLY
|
|
64
|
+
* updates the Matter onOff state and notifies all controllers.
|
|
65
|
+
* You do NOT need to call api.matter.updateAccessoryState() here!
|
|
66
|
+
*/
|
|
31
67
|
on: async () => {
|
|
32
|
-
log.info('[Dimmable Light] ✓ Handler `on` called (
|
|
68
|
+
log.info('[Dimmable Light] ✓ Handler `on` called (Home app → Physical device)');
|
|
69
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
70
|
+
// OPTIONAL: Read current state
|
|
71
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
72
|
+
const isOn = accessory.clusters.onOff.onOff;
|
|
73
|
+
const brightness = accessory.clusters.levelControl.currentLevel;
|
|
74
|
+
const brightnessPercent = Math.round((brightness / 254) * 100);
|
|
75
|
+
log.info(`[Dimmable Light] Current Matter state: ${isOn ? 'ON' : 'OFF'} at ${brightnessPercent}%`);
|
|
76
|
+
// When turning on, the brightness stays at its last value
|
|
77
|
+
// Example: If light was at 80% when turned off, it turns back on at 80%
|
|
78
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
79
|
+
// YOUR JOB: Control your physical device
|
|
80
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
33
81
|
// TODO: Add your actual light control logic here
|
|
34
|
-
//
|
|
82
|
+
// await myLightAPI.turnOn()
|
|
83
|
+
// Note: brightness is already set, just need to turn on
|
|
84
|
+
log.info('[Dimmable Light] Physical device turned ON');
|
|
85
|
+
// Homebridge automatically updates Matter state after this handler
|
|
35
86
|
},
|
|
87
|
+
/**
|
|
88
|
+
* Called when user turns the light OFF via Home app
|
|
89
|
+
*/
|
|
36
90
|
off: async () => {
|
|
37
|
-
log.info('[Dimmable Light] ✓ Handler `off` called (
|
|
38
|
-
|
|
39
|
-
|
|
91
|
+
log.info('[Dimmable Light] ✓ Handler `off` called (Home app → Physical device)');
|
|
92
|
+
const brightness = accessory.clusters.levelControl.currentLevel;
|
|
93
|
+
const brightnessPercent = Math.round((brightness / 254) * 100);
|
|
94
|
+
log.info(`[Dimmable Light] Turning off (brightness will remain at ${brightnessPercent}% for next on)`);
|
|
95
|
+
// TODO: Control your physical device
|
|
96
|
+
// await myLightAPI.turnOff()
|
|
97
|
+
// Note: Don't change the brightness value, it's preserved for next "on"
|
|
98
|
+
log.info('[Dimmable Light] Physical device turned OFF');
|
|
99
|
+
// Homebridge automatically updates Matter state to OFF after this handler
|
|
40
100
|
},
|
|
41
101
|
},
|
|
42
102
|
levelControl: {
|
|
103
|
+
/**
|
|
104
|
+
* Called when user changes brightness
|
|
105
|
+
* This handler is called for brightness changes AND can turn the light on/off
|
|
106
|
+
*/
|
|
43
107
|
moveToLevelWithOnOff: async (request) => {
|
|
44
|
-
const { level } = request;
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
108
|
+
const { level, transitionTime, optionsMask, optionsOverride } = request;
|
|
109
|
+
// Convert Matter level (1-254) to percentage (0-100%)
|
|
110
|
+
const brightnessPercent = Math.round((level / 254) * 100);
|
|
111
|
+
log.info(`[Dimmable Light] ✓ Handler \`moveToLevel\` called with level=${level} (${brightnessPercent}%)`);
|
|
112
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
113
|
+
// READING STATE: Check current state before applying change
|
|
114
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
115
|
+
const wasOn = accessory.clusters.onOff.onOff;
|
|
116
|
+
const oldLevel = accessory.clusters.levelControl.currentLevel;
|
|
117
|
+
const oldPercent = Math.round((oldLevel / 254) * 100);
|
|
118
|
+
log.info(`[Dimmable Light] Changing from ${oldPercent}% to ${brightnessPercent}% (was ${wasOn ? 'ON' : 'OFF'})`);
|
|
119
|
+
// Important note about transitionTime:
|
|
120
|
+
// - transitionTime is in 1/10 second units (tenths of a second)
|
|
121
|
+
// - transitionTime: 10 = 1 second, 50 = 5 seconds
|
|
122
|
+
// - If your device API supports fade/transition, use this value
|
|
123
|
+
if (transitionTime !== undefined && transitionTime !== null) {
|
|
124
|
+
const seconds = transitionTime / 10;
|
|
125
|
+
log.info(`[Dimmable Light] Transition time: ${seconds}s`);
|
|
126
|
+
}
|
|
127
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
128
|
+
// CONTROL YOUR DEVICE: Send brightness command
|
|
129
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
130
|
+
// TODO: Replace with your actual device control logic
|
|
131
|
+
//
|
|
132
|
+
// Example 1: API that accepts percentage
|
|
133
|
+
// await myLightAPI.setBrightness(brightnessPercent)
|
|
134
|
+
//
|
|
135
|
+
// Example 2: API that accepts 0-255 range
|
|
136
|
+
// await myLightAPI.setBrightness(level)
|
|
137
|
+
//
|
|
138
|
+
// Example 3: With transition/fade support
|
|
139
|
+
// await myLightAPI.setBrightness(brightnessPercent, transitionTime / 10)
|
|
140
|
+
//
|
|
141
|
+
// Example 4: Cloud API
|
|
142
|
+
// await fetch('https://api.mysmartlight.com/devices/light-002/brightness', {
|
|
143
|
+
// method: 'PUT',
|
|
144
|
+
// body: JSON.stringify({ brightness: brightnessPercent })
|
|
145
|
+
// })
|
|
146
|
+
// IMPORTANT: moveToLevelWithOnOff can also turn the light on/off!
|
|
147
|
+
// - If level > 0: Light turns ON at that brightness
|
|
148
|
+
// - If level = 0: Light turns OFF (but some implementations may not allow 0)
|
|
149
|
+
// HomeKit automatically updates both onOff and levelControl clusters after this handler
|
|
48
150
|
},
|
|
49
151
|
},
|
|
50
152
|
},
|
|
51
|
-
}
|
|
153
|
+
};
|
|
154
|
+
accessories.push(accessory);
|
|
155
|
+
// ═════════════════════════════════════════════════════════════════════════════
|
|
156
|
+
// FLOW B: PHYSICAL DEVICE → HOME APP
|
|
157
|
+
// ═════════════════════════════════════════════════════════════════════════════
|
|
158
|
+
//
|
|
159
|
+
// For a dimmable light, you need to monitor TWO properties:
|
|
160
|
+
// 1. On/Off state (onOff cluster)
|
|
161
|
+
// 2. Brightness level (levelControl cluster)
|
|
162
|
+
//
|
|
163
|
+
// When your physical device changes externally, you may need to update one or both.
|
|
164
|
+
//
|
|
165
|
+
// THE KEY API: api.matter.updateAccessoryState(uuid, cluster, attributes)
|
|
166
|
+
// This updates Matter state AND notifies all controllers.
|
|
167
|
+
/**
|
|
168
|
+
* Example: Polling for state changes (checking both on/off and brightness)
|
|
169
|
+
*/
|
|
170
|
+
const startPollingExample = () => {
|
|
171
|
+
setInterval(async () => {
|
|
172
|
+
try {
|
|
173
|
+
// TODO: Fetch state from your device
|
|
174
|
+
// const state = await myLightAPI.getState(accessory.context.deviceId)
|
|
175
|
+
// const deviceIsOn = state.power === 'on'
|
|
176
|
+
// const deviceBrightness = state.brightness // Assuming this is 0-100
|
|
177
|
+
// For this example, simulate fetching device state:
|
|
178
|
+
// const deviceIsOn = true
|
|
179
|
+
// const deviceBrightness = 75 // 75%
|
|
180
|
+
// ──────────────────────────────────────────────────────────────────────
|
|
181
|
+
// READING CURRENT MATTER STATE
|
|
182
|
+
// ──────────────────────────────────────────────────────────────────────
|
|
183
|
+
const currentMatterIsOn = accessory.clusters.onOff.onOff;
|
|
184
|
+
const currentMatterLevel = accessory.clusters.levelControl.currentLevel;
|
|
185
|
+
const currentMatterPercent = Math.round((currentMatterLevel / 254) * 100);
|
|
186
|
+
// ──────────────────────────────────────────────────────────────────────
|
|
187
|
+
// SCENARIO 1: Only on/off changed (brightness stayed the same)
|
|
188
|
+
// ──────────────────────────────────────────────────────────────────────
|
|
189
|
+
// if (deviceIsOn !== currentMatterIsOn) {
|
|
190
|
+
// log.info(`[Dimmable Light] Physical device power changed: ${deviceIsOn ? 'ON' : 'OFF'}`)
|
|
191
|
+
//
|
|
192
|
+
// // Update Matter state using Homebridge API
|
|
193
|
+
// api.matter.updateAccessoryState(
|
|
194
|
+
// accessory.uuid,
|
|
195
|
+
// api.matter.clusterNames.OnOff,
|
|
196
|
+
// { onOff: deviceIsOn },
|
|
197
|
+
// )
|
|
198
|
+
//
|
|
199
|
+
// log.info(`[Dimmable Light] ✓ Matter state updated (Physical device → Home app)`)
|
|
200
|
+
// }
|
|
201
|
+
// ──────────────────────────────────────────────────────────────────────
|
|
202
|
+
// SCENARIO 2: Only brightness changed (on/off stayed the same)
|
|
203
|
+
// ──────────────────────────────────────────────────────────────────────
|
|
204
|
+
// if (deviceBrightness !== currentMatterPercent) {
|
|
205
|
+
// log.info(`[Dimmable Light] Physical device brightness changed: ${deviceBrightness}%`)
|
|
206
|
+
//
|
|
207
|
+
// // Convert percentage (0-100) to Matter level (1-254)
|
|
208
|
+
// const newLevel = Math.max(1, Math.round((deviceBrightness / 100) * 254))
|
|
209
|
+
//
|
|
210
|
+
// // Update Matter state using Homebridge API
|
|
211
|
+
// api.matter.updateAccessoryState(
|
|
212
|
+
// accessory.uuid,
|
|
213
|
+
// api.matter.clusterNames.LevelControl,
|
|
214
|
+
// { currentLevel: newLevel },
|
|
215
|
+
// )
|
|
216
|
+
//
|
|
217
|
+
// log.info(`[Dimmable Light] ✓ Matter state updated: ${deviceBrightness}% (level ${newLevel})`)
|
|
218
|
+
// }
|
|
219
|
+
// ──────────────────────────────────────────────────────────────────────
|
|
220
|
+
// SCENARIO 3: Both on/off AND brightness changed
|
|
221
|
+
// ──────────────────────────────────────────────────────────────────────
|
|
222
|
+
// Update each cluster separately with api.matter.updateAccessoryState()
|
|
223
|
+
// const brightnessChanged = deviceBrightness !== currentMatterPercent
|
|
224
|
+
// const powerChanged = deviceIsOn !== currentMatterIsOn
|
|
225
|
+
//
|
|
226
|
+
// if (powerChanged || brightnessChanged) {
|
|
227
|
+
// log.info(`[Dimmable Light] Physical device changed - Power: ${deviceIsOn ? 'ON' : 'OFF'}, Brightness: ${deviceBrightness}%`)
|
|
228
|
+
//
|
|
229
|
+
// // Update on/off if changed
|
|
230
|
+
// if (powerChanged) {
|
|
231
|
+
// api.matter.updateAccessoryState(
|
|
232
|
+
// accessory.uuid,
|
|
233
|
+
// api.matter.clusterNames.OnOff,
|
|
234
|
+
// { onOff: deviceIsOn },
|
|
235
|
+
// )
|
|
236
|
+
// }
|
|
237
|
+
//
|
|
238
|
+
// // Update brightness if changed
|
|
239
|
+
// if (brightnessChanged) {
|
|
240
|
+
// const newLevel = Math.max(1, Math.round((deviceBrightness / 100) * 254))
|
|
241
|
+
// api.matter.updateAccessoryState(
|
|
242
|
+
// accessory.uuid,
|
|
243
|
+
// api.matter.clusterNames.LevelControl,
|
|
244
|
+
// { currentLevel: newLevel },
|
|
245
|
+
// )
|
|
246
|
+
// }
|
|
247
|
+
//
|
|
248
|
+
// log.info(`[Dimmable Light] ✓ Matter state updated (Physical device → Home app)`)
|
|
249
|
+
// }
|
|
250
|
+
}
|
|
251
|
+
catch (error) {
|
|
252
|
+
log.error(`[Dimmable Light] Error polling device state: ${error}`);
|
|
253
|
+
}
|
|
254
|
+
}, 5000); // Poll every 5 seconds
|
|
255
|
+
};
|
|
256
|
+
// Uncomment to enable polling:
|
|
257
|
+
// startPollingExample()
|
|
258
|
+
/**
|
|
259
|
+
* RECOMMENDED: Event-based updates with multiple properties
|
|
260
|
+
*
|
|
261
|
+
* ⚡ This is the BEST approach - instant updates when device changes
|
|
262
|
+
*/
|
|
263
|
+
const startEventListenerExample = () => {
|
|
264
|
+
// Example: MQTT listener for a dimmable light
|
|
265
|
+
// import mqtt from 'mqtt'
|
|
266
|
+
// const mqttClient = mqtt.connect('mqtt://your-broker-url')
|
|
267
|
+
//
|
|
268
|
+
// mqttClient.subscribe('home/dimmable-light/status')
|
|
269
|
+
// mqttClient.on('message', (topic, message) => {
|
|
270
|
+
// if (topic === 'home/dimmable-light/status') {
|
|
271
|
+
// const deviceState = JSON.parse(message.toString())
|
|
272
|
+
// // Example payload: { "state": "ON", "brightness": 75 }
|
|
273
|
+
//
|
|
274
|
+
// const deviceIsOn = deviceState.state === 'ON'
|
|
275
|
+
// const deviceBrightness = deviceState.brightness // 0-100
|
|
276
|
+
//
|
|
277
|
+
// // Check what changed compared to current Matter state
|
|
278
|
+
// const currentMatterIsOn = accessory.clusters.onOff.onOff
|
|
279
|
+
// const currentMatterPercent = Math.round((accessory.clusters.levelControl.currentLevel / 254) * 100)
|
|
280
|
+
// const powerChanged = deviceIsOn !== currentMatterIsOn
|
|
281
|
+
// const brightnessChanged = deviceBrightness !== currentMatterPercent
|
|
282
|
+
//
|
|
283
|
+
// if (powerChanged || brightnessChanged) {
|
|
284
|
+
// log.info(`[Dimmable Light] Physical device changed (MQTT): ${deviceIsOn ? 'ON' : 'OFF'} at ${deviceBrightness}%`)
|
|
285
|
+
//
|
|
286
|
+
// // Update on/off if changed
|
|
287
|
+
// if (powerChanged) {
|
|
288
|
+
// api.matter.updateAccessoryState(
|
|
289
|
+
// accessory.uuid,
|
|
290
|
+
// api.matter.clusterNames.OnOff,
|
|
291
|
+
// { onOff: deviceIsOn },
|
|
292
|
+
// )
|
|
293
|
+
// }
|
|
294
|
+
//
|
|
295
|
+
// // Update brightness if changed
|
|
296
|
+
// if (brightnessChanged) {
|
|
297
|
+
// const newLevel = Math.max(1, Math.round((deviceBrightness / 100) * 254))
|
|
298
|
+
// api.matter.updateAccessoryState(
|
|
299
|
+
// accessory.uuid,
|
|
300
|
+
// api.matter.clusterNames.LevelControl,
|
|
301
|
+
// { currentLevel: newLevel },
|
|
302
|
+
// )
|
|
303
|
+
// }
|
|
304
|
+
//
|
|
305
|
+
// log.info(`[Dimmable Light] ✓ Matter state updated (Physical device → Home app)`)
|
|
306
|
+
// }
|
|
307
|
+
// }
|
|
308
|
+
// })
|
|
309
|
+
};
|
|
310
|
+
// Uncomment to enable event listeners:
|
|
311
|
+
// startEventListenerExample()
|
|
312
|
+
// ═════════════════════════════════════════════════════════════════════════════
|
|
313
|
+
// KEY TAKEAWAYS FOR MULTI-CLUSTER DEVICES:
|
|
314
|
+
// ═════════════════════════════════════════════════════════════════════════════
|
|
315
|
+
//
|
|
316
|
+
// 1. TWO SEPARATE FLOWS:
|
|
317
|
+
// FLOW A (Home App → Physical Device):
|
|
318
|
+
// - Handlers run when user controls via Home app
|
|
319
|
+
// - You control the physical device
|
|
320
|
+
// - Homebridge AUTOMATICALLY updates Matter state after handler
|
|
321
|
+
// - DO NOT call api.matter.updateAccessoryState() in handlers!
|
|
322
|
+
//
|
|
323
|
+
// FLOW B (Physical Device → Home App):
|
|
324
|
+
// - Physical device changes externally (button, cloud, automation)
|
|
325
|
+
// - You MUST monitor device (events/polling) and detect changes
|
|
326
|
+
// - You MUST call api.matter.updateAccessoryState() for each cluster
|
|
327
|
+
// - Then all controllers are notified
|
|
328
|
+
//
|
|
329
|
+
// 2. READING MULTIPLE PROPERTIES:
|
|
330
|
+
// - On/Off: accessory.clusters.onOff.onOff
|
|
331
|
+
// - Brightness: accessory.clusters.levelControl.currentLevel
|
|
332
|
+
// - Convert level to %: Math.round((level / 254) * 100)
|
|
333
|
+
//
|
|
334
|
+
// 3. UPDATING MULTIPLE PROPERTIES (Physical Device → Home App):
|
|
335
|
+
// - Update each cluster separately:
|
|
336
|
+
// api.matter.updateAccessoryState(uuid, api.matter.clusterNames.OnOff, { onOff: value })
|
|
337
|
+
// api.matter.updateAccessoryState(uuid, api.matter.clusterNames.LevelControl, { currentLevel: level })
|
|
338
|
+
// - You can update one or both depending on what changed
|
|
339
|
+
// - ONLY use this for FLOW B (external changes), NOT in handlers!
|
|
340
|
+
//
|
|
341
|
+
// 4. BRIGHTNESS CONVERSION:
|
|
342
|
+
// - Matter uses 1-254 range (0 is reserved, means "off")
|
|
343
|
+
// - Your device API probably uses 0-100 percentage
|
|
344
|
+
// - Convert TO Matter: Math.max(1, Math.round((percent / 100) * 254))
|
|
345
|
+
// - Convert FROM Matter: Math.round((level / 254) * 100)
|
|
346
|
+
//
|
|
347
|
+
// 5. HANDLER BEHAVIOR (FLOW A):
|
|
348
|
+
// - on/off handlers: Only change power state, brightness is preserved
|
|
349
|
+
// - moveToLevelWithOnOff: Can change BOTH brightness and power state
|
|
350
|
+
// - If user sets brightness to 0, light may turn off (implementation dependent)
|
|
351
|
+
// - Homebridge automatically updates Matter state after handlers complete
|
|
352
|
+
//
|
|
353
|
+
// 6. TRANSITION TIME:
|
|
354
|
+
// - Provided in 1/10 second units (10 = 1 second)
|
|
355
|
+
// - Use this if your device supports fade/transition effects
|
|
356
|
+
// - Example: await myLightAPI.setBrightness(level, transitionTime / 10)
|
|
357
|
+
//
|
|
358
|
+
// 7. BEST PRACTICES:
|
|
359
|
+
// - Always compare states before calling updateAccessoryState() (avoid unnecessary updates)
|
|
360
|
+
// - Use events (MQTT, WebSocket, webhooks) whenever possible
|
|
361
|
+
// - Update only the clusters that actually changed
|
|
362
|
+
// - Log clearly: "Physical device → Home app" vs "Home app → Physical device"
|
|
363
|
+
// ═════════════════════════════════════════════════════════════════════════════
|
|
52
364
|
return accessories;
|
|
53
365
|
}
|
|
54
366
|
//# sourceMappingURL=dimmable-light.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dimmable-light.js","sourceRoot":"","sources":["../../../src/devices/section-4-lighting/dimmable-light.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"dimmable-light.js","sourceRoot":"","sources":["../../../src/devices/section-4-lighting/dimmable-light.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,6 +7,30 @@
|
|
|
7
7
|
*
|
|
8
8
|
* Both use the same Matter device type (ExtendedColorLight) but with different
|
|
9
9
|
* cluster configurations.
|
|
10
|
+
*
|
|
11
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
12
|
+
* ARCHITECTURE: THE TWO-WAY FLOW (applies to all Matter accessories)
|
|
13
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
14
|
+
*
|
|
15
|
+
* FLOW A: Home App → Physical Device (AUTOMATIC - via handlers)
|
|
16
|
+
* ────────────────────────────────────────────────────────────────
|
|
17
|
+
* 1. User controls via Home App
|
|
18
|
+
* 2. Matter command → Homebridge → Your handler runs
|
|
19
|
+
* 3. You control your physical device (API, MQTT, etc.)
|
|
20
|
+
* 4. Homebridge AUTOMATICALLY updates Matter state
|
|
21
|
+
* 5. All controllers are notified
|
|
22
|
+
* ✅ No manual state update needed!
|
|
23
|
+
*
|
|
24
|
+
* FLOW B: Physical Device → Home App (MANUAL - you must update state)
|
|
25
|
+
* ────────────────────────────────────────────────────────────────
|
|
26
|
+
* 1. Physical device changes (button, cloud app, automation)
|
|
27
|
+
* 2. ❌ Homebridge has NO IDEA this happened!
|
|
28
|
+
* 3. You MUST monitor device and detect changes
|
|
29
|
+
* 4. You MUST call api.matter.updateAccessoryState() for changed clusters
|
|
30
|
+
* 5. Then all controllers are notified
|
|
31
|
+
*
|
|
32
|
+
* This demonstrates the MOST COMPLEX case with multiple color modes and clusters.
|
|
33
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
10
34
|
*/
|
|
11
35
|
import type { DeviceContext } from '../types.js';
|
|
12
36
|
export declare function registerExtendedColorLight(context: DeviceContext): any[];
|