@homebridge-plugins/homebridge-matter 0.1.3 → 0.1.4
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/CHANGELOG.md +7 -0
- package/MATTER_API.md +1189 -182
- package/README.md +1 -1
- package/dist/devices/section-12-robotic/robotic-vacuum-cleaner.d.ts +9 -53
- package/dist/devices/section-12-robotic/robotic-vacuum-cleaner.js +12 -62
- package/dist/devices/section-12-robotic/robotic-vacuum-cleaner.js.map +1 -1
- package/dist/devices/section-4-lighting/color-temperature-light.d.ts +8 -1
- package/dist/devices/section-4-lighting/color-temperature-light.js +27 -23
- package/dist/devices/section-4-lighting/color-temperature-light.js.map +1 -1
- package/dist/devices/section-4-lighting/dimmable-light.d.ts +5 -22
- package/dist/devices/section-4-lighting/dimmable-light.js +40 -319
- package/dist/devices/section-4-lighting/dimmable-light.js.map +1 -1
- package/dist/devices/section-4-lighting/extended-color-light.d.ts +6 -25
- package/dist/devices/section-4-lighting/extended-color-light.js +33 -399
- package/dist/devices/section-4-lighting/extended-color-light.js.map +1 -1
- package/dist/devices/section-4-lighting/on-off-light.d.ts +8 -28
- package/dist/devices/section-4-lighting/on-off-light.js +64 -434
- package/dist/devices/section-4-lighting/on-off-light.js.map +1 -1
- package/dist/devices/section-5-smart-plugs/dimmable-plug-in-unit.d.ts +6 -0
- package/dist/devices/section-5-smart-plugs/dimmable-plug-in-unit.js +13 -3
- package/dist/devices/section-5-smart-plugs/dimmable-plug-in-unit.js.map +1 -1
- package/dist/devices/section-5-smart-plugs/on-off-plug-in-unit.d.ts +5 -0
- package/dist/devices/section-5-smart-plugs/on-off-plug-in-unit.js +9 -2
- package/dist/devices/section-5-smart-plugs/on-off-plug-in-unit.js.map +1 -1
- package/dist/devices/section-6-switches/on-off-light-switch.d.ts +5 -0
- package/dist/devices/section-6-switches/on-off-light-switch.js +19 -5
- package/dist/devices/section-6-switches/on-off-light-switch.js.map +1 -1
- package/dist/devices/section-7-sensors/contact-sensor.d.ts +5 -0
- package/dist/devices/section-7-sensors/contact-sensor.js +5 -0
- package/dist/devices/section-7-sensors/contact-sensor.js.map +1 -1
- package/dist/devices/section-7-sensors/humidity-sensor.d.ts +5 -0
- package/dist/devices/section-7-sensors/humidity-sensor.js +5 -0
- package/dist/devices/section-7-sensors/humidity-sensor.js.map +1 -1
- package/dist/devices/section-7-sensors/light-sensor.d.ts +5 -0
- package/dist/devices/section-7-sensors/light-sensor.js +5 -0
- package/dist/devices/section-7-sensors/light-sensor.js.map +1 -1
- package/dist/devices/section-7-sensors/occupancy-sensor.d.ts +6 -0
- package/dist/devices/section-7-sensors/occupancy-sensor.js +6 -0
- package/dist/devices/section-7-sensors/occupancy-sensor.js.map +1 -1
- package/dist/devices/section-7-sensors/smoke-co-alarm.d.ts +6 -0
- package/dist/devices/section-7-sensors/smoke-co-alarm.js +6 -0
- package/dist/devices/section-7-sensors/smoke-co-alarm.js.map +1 -1
- package/dist/devices/section-7-sensors/temperature-sensor.d.ts +5 -0
- package/dist/devices/section-7-sensors/temperature-sensor.js +5 -0
- package/dist/devices/section-7-sensors/temperature-sensor.js.map +1 -1
- package/dist/devices/section-7-sensors/water-leak-detector.d.ts +5 -0
- package/dist/devices/section-7-sensors/water-leak-detector.js +5 -0
- package/dist/devices/section-7-sensors/water-leak-detector.js.map +1 -1
- package/dist/devices/section-8-closure/door-lock.d.ts +6 -0
- package/dist/devices/section-8-closure/door-lock.js +12 -27
- package/dist/devices/section-8-closure/door-lock.js.map +1 -1
- package/dist/devices/section-8-closure/window-covering.d.ts +7 -0
- package/dist/devices/section-8-closure/window-covering.js +27 -43
- package/dist/devices/section-8-closure/window-covering.js.map +1 -1
- package/dist/devices/section-9-hvac/fan.d.ts +7 -0
- package/dist/devices/section-9-hvac/fan.js +17 -23
- package/dist/devices/section-9-hvac/fan.js.map +1 -1
- package/dist/devices/section-9-hvac/thermostat.d.ts +7 -0
- package/dist/devices/section-9-hvac/thermostat.js +21 -25
- package/dist/devices/section-9-hvac/thermostat.js.map +1 -1
- package/package.json +3 -3
|
@@ -3,29 +3,12 @@
|
|
|
3
3
|
*
|
|
4
4
|
* A lighting device with on/off and level control (brightness).
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
* ARCHITECTURE: THE TWO-WAY FLOW (applies to all Matter accessories)
|
|
8
|
-
* ═══════════════════════════════════════════════════════════════════════════════
|
|
6
|
+
* For comprehensive documentation, see: ../../../MATTER_API.md
|
|
9
7
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
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
|
-
* ═══════════════════════════════════════════════════════════════════════════════
|
|
8
|
+
* This example demonstrates:
|
|
9
|
+
* - Multiple clusters (OnOff + LevelControl)
|
|
10
|
+
* - Type-safe handlers with MatterRequests
|
|
11
|
+
* - Brightness value conversion (Matter 1-254 ↔ Percent 0-100%)
|
|
29
12
|
*/
|
|
30
13
|
export function registerDimmableLight(context) {
|
|
31
14
|
const { api, log, config } = context;
|
|
@@ -42,325 +25,63 @@ export function registerDimmableLight(context) {
|
|
|
42
25
|
model: 'DimmableLight v1',
|
|
43
26
|
clusters: {
|
|
44
27
|
onOff: {
|
|
45
|
-
onOff: false,
|
|
28
|
+
onOff: false,
|
|
46
29
|
},
|
|
47
30
|
levelControl: {
|
|
48
|
-
currentLevel: 127, //
|
|
49
|
-
minLevel: 1,
|
|
50
|
-
maxLevel: 254,
|
|
31
|
+
currentLevel: 127, // 50% brightness (range 1-254)
|
|
32
|
+
minLevel: 1,
|
|
33
|
+
maxLevel: 254,
|
|
51
34
|
},
|
|
52
35
|
},
|
|
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
|
|
58
36
|
handlers: {
|
|
59
37
|
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
|
-
*/
|
|
67
38
|
on: async () => {
|
|
68
|
-
log.info('[Dimmable Light]
|
|
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
|
-
// ─────────────────────────────────────────────────────────────────────
|
|
81
|
-
// TODO: Add your actual light control logic here
|
|
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
|
|
39
|
+
log.info('[Dimmable Light] Turning ON');
|
|
40
|
+
// TODO: await myLightAPI.turnOn()
|
|
86
41
|
},
|
|
87
|
-
/**
|
|
88
|
-
* Called when user turns the light OFF via Home app
|
|
89
|
-
*/
|
|
90
42
|
off: async () => {
|
|
91
|
-
log.info('[Dimmable Light]
|
|
92
|
-
|
|
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
|
|
43
|
+
log.info('[Dimmable Light] Turning OFF');
|
|
44
|
+
// TODO: await myLightAPI.turnOff()
|
|
100
45
|
},
|
|
101
46
|
},
|
|
102
47
|
levelControl: {
|
|
103
|
-
|
|
104
|
-
* Called when user changes brightness
|
|
105
|
-
* This handler is called for brightness changes AND can turn the light on/off
|
|
106
|
-
*/
|
|
48
|
+
// Type-safe handler with MatterRequests
|
|
107
49
|
moveToLevelWithOnOff: async (request) => {
|
|
108
|
-
const { level, transitionTime
|
|
50
|
+
const { level, transitionTime } = request;
|
|
109
51
|
// Convert Matter level (1-254) to percentage (0-100%)
|
|
110
52
|
const brightnessPercent = Math.round((level / 254) * 100);
|
|
111
|
-
log.info(`[Dimmable Light]
|
|
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
|
|
53
|
+
log.info(`[Dimmable Light] Setting brightness to ${brightnessPercent}% (level: ${level})`);
|
|
54
|
+
// TODO: await myLightAPI.setBrightness(brightnessPercent, transitionTime)
|
|
150
55
|
},
|
|
151
56
|
},
|
|
152
57
|
},
|
|
153
58
|
};
|
|
154
59
|
accessories.push(accessory);
|
|
155
|
-
//
|
|
156
|
-
//
|
|
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
|
|
60
|
+
// FLOW B: Monitor for external changes
|
|
61
|
+
// Example: MQTT listener
|
|
62
|
+
// mqttClient.on('message', (topic, message) => {
|
|
63
|
+
// const { state, brightness } = JSON.parse(message.toString())
|
|
352
64
|
//
|
|
353
|
-
//
|
|
354
|
-
//
|
|
355
|
-
//
|
|
356
|
-
//
|
|
65
|
+
// // Update on/off state
|
|
66
|
+
// const deviceIsOn = state === 'ON'
|
|
67
|
+
// if (deviceIsOn !== accessory.clusters.onOff.onOff) {
|
|
68
|
+
// api.matter.updateAccessoryState(
|
|
69
|
+
// accessory.uuid,
|
|
70
|
+
// api.matter.clusterNames.OnOff,
|
|
71
|
+
// { onOff: deviceIsOn }
|
|
72
|
+
// )
|
|
73
|
+
// }
|
|
357
74
|
//
|
|
358
|
-
//
|
|
359
|
-
//
|
|
360
|
-
//
|
|
361
|
-
//
|
|
362
|
-
//
|
|
363
|
-
//
|
|
75
|
+
// // Update brightness (convert percent to Matter level)
|
|
76
|
+
// const matterLevel = Math.max(1, Math.round((brightness / 100) * 254))
|
|
77
|
+
// if (matterLevel !== accessory.clusters.levelControl.currentLevel) {
|
|
78
|
+
// api.matter.updateAccessoryState(
|
|
79
|
+
// accessory.uuid,
|
|
80
|
+
// api.matter.clusterNames.LevelControl,
|
|
81
|
+
// { currentLevel: matterLevel }
|
|
82
|
+
// )
|
|
83
|
+
// }
|
|
84
|
+
// })
|
|
364
85
|
return accessories;
|
|
365
86
|
}
|
|
366
87
|
//# 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":"AAAA;;;;;;;;;;;GAWG;AAMH,MAAM,UAAU,qBAAqB,CAAC,OAAsB;IAC1D,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAA;IACpC,MAAM,WAAW,GAAU,EAAE,CAAA;IAE7B,IAAI,CAAC,MAAM,CAAC,mBAAmB,EAAE,CAAC;QAChC,OAAO,WAAW,CAAA;IACpB,CAAC;IAED,MAAM,SAAS,GAAG;QAChB,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,uBAAuB,CAAC;QACvD,WAAW,EAAE,gBAAgB;QAC7B,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,aAAa;QAChD,YAAY,EAAE,WAAW;QACzB,YAAY,EAAE,iBAAiB;QAC/B,KAAK,EAAE,kBAAkB;QAEzB,QAAQ,EAAE;YACR,KAAK,EAAE;gBACL,KAAK,EAAE,KAAK;aACb;YACD,YAAY,EAAE;gBACZ,YAAY,EAAE,GAAG,EAAE,+BAA+B;gBAClD,QAAQ,EAAE,CAAC;gBACX,QAAQ,EAAE,GAAG;aACd;SACF;QAED,QAAQ,EAAE;YACR,KAAK,EAAE;gBACL,EAAE,EAAE,KAAK,IAAI,EAAE;oBACb,GAAG,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAA;oBACvC,kCAAkC;gBACpC,CAAC;gBAED,GAAG,EAAE,KAAK,IAAI,EAAE;oBACd,GAAG,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAA;oBACxC,mCAAmC;gBACrC,CAAC;aACF;YAED,YAAY,EAAE;gBACZ,wCAAwC;gBACxC,oBAAoB,EAAE,KAAK,EAAE,OAAmC,EAAE,EAAE;oBAClE,MAAM,EAAE,KAAK,EAAE,cAAc,EAAE,GAAG,OAAO,CAAA;oBAEzC,sDAAsD;oBACtD,MAAM,iBAAiB,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,CAAA;oBACzD,GAAG,CAAC,IAAI,CAAC,0CAA0C,iBAAiB,aAAa,KAAK,GAAG,CAAC,CAAA;oBAE1F,0EAA0E;gBAC5E,CAAC;aACF;SACF;KACF,CAAA;IAED,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;IAE3B,uCAAuC;IACvC,yBAAyB;IACzB,iDAAiD;IACjD,iEAAiE;IACjE,EAAE;IACF,2BAA2B;IAC3B,sCAAsC;IACtC,yDAAyD;IACzD,uCAAuC;IACvC,wBAAwB;IACxB,uCAAuC;IACvC,8BAA8B;IAC9B,QAAQ;IACR,MAAM;IACN,EAAE;IACF,2DAA2D;IAC3D,0EAA0E;IAC1E,wEAAwE;IACxE,uCAAuC;IACvC,wBAAwB;IACxB,8CAA8C;IAC9C,sCAAsC;IACtC,QAAQ;IACR,MAAM;IACN,KAAK;IAEL,OAAO,WAAW,CAAA;AACpB,CAAC"}
|
|
@@ -5,32 +5,13 @@
|
|
|
5
5
|
* - Color Light (HS): Hue/Saturation only
|
|
6
6
|
* - Extended Color Light (HS+CCT): Hue/Saturation + Color Temperature
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
* cluster configurations.
|
|
8
|
+
* For comprehensive documentation, see: ../../../MATTER_API.md
|
|
10
9
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
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
|
+
* This example demonstrates:
|
|
11
|
+
* - Multiple color modes (HS, XY, Color Temperature)
|
|
12
|
+
* - Color value conversions (hue/saturation, mireds/Kelvin, XY)
|
|
13
|
+
* - Type-safe handlers with MatterRequests
|
|
14
|
+
* - Most complex lighting scenario with mode switching
|
|
34
15
|
*/
|
|
35
16
|
import type { DeviceContext } from '../types.js';
|
|
36
17
|
export declare function registerExtendedColorLight(context: DeviceContext): any[];
|