@homebridge-plugins/homebridge-matter 0.0.5 → 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.
- package/CHANGELOG.md +17 -0
- package/README.md +67 -33
- package/config.schema.json +222 -2
- package/dist/devices/index.d.ts +13 -0
- package/dist/devices/index.js +22 -0
- package/dist/devices/index.js.map +1 -0
- package/dist/devices/section-12-robotic/index.d.ts +6 -0
- package/dist/devices/section-12-robotic/index.js +7 -0
- package/dist/devices/section-12-robotic/index.js.map +1 -0
- package/dist/devices/section-12-robotic/robotic-vacuum-cleaner.d.ts +63 -0
- package/dist/devices/section-12-robotic/robotic-vacuum-cleaner.js +318 -0
- package/dist/devices/section-12-robotic/robotic-vacuum-cleaner.js.map +1 -0
- package/dist/devices/section-4-lighting/color-temperature-light.d.ts +7 -0
- package/dist/devices/section-4-lighting/color-temperature-light.js +62 -0
- package/dist/devices/section-4-lighting/color-temperature-light.js.map +1 -0
- package/dist/devices/section-4-lighting/dimmable-light.d.ts +7 -0
- package/dist/devices/section-4-lighting/dimmable-light.js +48 -0
- package/dist/devices/section-4-lighting/dimmable-light.js.map +1 -0
- package/dist/devices/section-4-lighting/extended-color-light.d.ts +12 -0
- package/dist/devices/section-4-lighting/extended-color-light.js +142 -0
- package/dist/devices/section-4-lighting/extended-color-light.js.map +1 -0
- package/dist/devices/section-4-lighting/index.d.ts +9 -0
- package/dist/devices/section-4-lighting/index.js +10 -0
- package/dist/devices/section-4-lighting/index.js.map +1 -0
- package/dist/devices/section-4-lighting/on-off-light.d.ts +7 -0
- package/dist/devices/section-4-lighting/on-off-light.js +37 -0
- package/dist/devices/section-4-lighting/on-off-light.js.map +1 -0
- package/dist/devices/section-5-smart-plugs/dimmable-plug-in-unit.d.ts +7 -0
- package/dist/devices/section-5-smart-plugs/dimmable-plug-in-unit.js +48 -0
- package/dist/devices/section-5-smart-plugs/dimmable-plug-in-unit.js.map +1 -0
- package/dist/devices/section-5-smart-plugs/index.d.ts +7 -0
- package/dist/devices/section-5-smart-plugs/index.js +8 -0
- package/dist/devices/section-5-smart-plugs/index.js.map +1 -0
- package/dist/devices/section-5-smart-plugs/on-off-plug-in-unit.d.ts +7 -0
- package/dist/devices/section-5-smart-plugs/on-off-plug-in-unit.js +37 -0
- package/dist/devices/section-5-smart-plugs/on-off-plug-in-unit.js.map +1 -0
- package/dist/devices/section-6-switches/index.d.ts +6 -0
- package/dist/devices/section-6-switches/index.js +7 -0
- package/dist/devices/section-6-switches/index.js.map +1 -0
- package/dist/devices/section-6-switches/on-off-light-switch.d.ts +7 -0
- package/dist/devices/section-6-switches/on-off-light-switch.js +30 -0
- package/dist/devices/section-6-switches/on-off-light-switch.js.map +1 -0
- package/dist/devices/section-7-sensors/contact-sensor.d.ts +7 -0
- package/dist/devices/section-7-sensors/contact-sensor.js +27 -0
- package/dist/devices/section-7-sensors/contact-sensor.js.map +1 -0
- package/dist/devices/section-7-sensors/humidity-sensor.d.ts +7 -0
- package/dist/devices/section-7-sensors/humidity-sensor.js +29 -0
- package/dist/devices/section-7-sensors/humidity-sensor.js.map +1 -0
- package/dist/devices/section-7-sensors/index.d.ts +12 -0
- package/dist/devices/section-7-sensors/index.js +13 -0
- package/dist/devices/section-7-sensors/index.js.map +1 -0
- package/dist/devices/section-7-sensors/light-sensor.d.ts +7 -0
- package/dist/devices/section-7-sensors/light-sensor.js +29 -0
- package/dist/devices/section-7-sensors/light-sensor.js.map +1 -0
- package/dist/devices/section-7-sensors/occupancy-sensor.d.ts +8 -0
- package/dist/devices/section-7-sensors/occupancy-sensor.js +33 -0
- package/dist/devices/section-7-sensors/occupancy-sensor.js.map +1 -0
- package/dist/devices/section-7-sensors/smoke-co-alarm.d.ts +7 -0
- package/dist/devices/section-7-sensors/smoke-co-alarm.js +37 -0
- package/dist/devices/section-7-sensors/smoke-co-alarm.js.map +1 -0
- package/dist/devices/section-7-sensors/temperature-sensor.d.ts +7 -0
- package/dist/devices/section-7-sensors/temperature-sensor.js +29 -0
- package/dist/devices/section-7-sensors/temperature-sensor.js.map +1 -0
- package/dist/devices/section-7-sensors/water-leak-detector.d.ts +7 -0
- package/dist/devices/section-7-sensors/water-leak-detector.js +27 -0
- package/dist/devices/section-7-sensors/water-leak-detector.js.map +1 -0
- package/dist/devices/section-8-closure/door-lock.d.ts +7 -0
- package/dist/devices/section-8-closure/door-lock.js +48 -0
- package/dist/devices/section-8-closure/door-lock.js.map +1 -0
- package/dist/devices/section-8-closure/index.d.ts +7 -0
- package/dist/devices/section-8-closure/index.js +8 -0
- package/dist/devices/section-8-closure/index.js.map +1 -0
- package/dist/devices/section-8-closure/window-covering.d.ts +9 -0
- package/dist/devices/section-8-closure/window-covering.js +154 -0
- package/dist/devices/section-8-closure/window-covering.js.map +1 -0
- package/dist/devices/section-9-hvac/fan.d.ts +7 -0
- package/dist/devices/section-9-hvac/fan.js +56 -0
- package/dist/devices/section-9-hvac/fan.js.map +1 -0
- package/dist/devices/section-9-hvac/index.d.ts +7 -0
- package/dist/devices/section-9-hvac/index.js +8 -0
- package/dist/devices/section-9-hvac/index.js.map +1 -0
- package/dist/devices/section-9-hvac/thermostat.d.ts +7 -0
- package/dist/devices/section-9-hvac/thermostat.js +61 -0
- package/dist/devices/section-9-hvac/thermostat.js.map +1 -0
- package/dist/devices/types.d.ts +16 -0
- package/dist/devices/types.js +5 -0
- package/dist/devices/types.js.map +1 -0
- package/dist/homebridge-ui/public/index.html +269 -0
- package/dist/homebridge-ui/server.js +47 -0
- package/dist/platform.d.ts +28 -20
- package/dist/platform.js +187 -973
- package/dist/platform.js.map +1 -1
- package/package.json +9 -9
- package/plugin-header.png +0 -0
- package/.claude/settings.local.json +0 -28
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Robotic Vacuum Cleaner Device (Matter Spec § 12.1)
|
|
3
|
+
*
|
|
4
|
+
* A robotic vacuum cleaner with autonomous cleaning capabilities.
|
|
5
|
+
*
|
|
6
|
+
* ✅ Apple Home Compatibility - EXTERNAL ACCESSORIES
|
|
7
|
+
* This device is published using api.matter.publishExternalAccessories() in platform.ts.
|
|
8
|
+
* RVC devices MUST be on their own dedicated Matter bridge for Apple Home compatibility.
|
|
9
|
+
*
|
|
10
|
+
* IMPORTANT: This function only CREATES the accessory configuration.
|
|
11
|
+
* The actual publishing happens in platform.ts using publishExternalAccessories().
|
|
12
|
+
*
|
|
13
|
+
* What happens when this device is published as external:
|
|
14
|
+
* ─────────────────────────────────────────────────────────────
|
|
15
|
+
* 1. Dedicated Matter Server: Gets its own MatterServer instance
|
|
16
|
+
* 2. Automatic Port Allocation: Receives a unique port (e.g., 5541)
|
|
17
|
+
* 3. Separate Commissioning: Gets its own QR code and manual pairing code
|
|
18
|
+
* 4. Isolation: Completely independent from other Matter accessories
|
|
19
|
+
* 5. Apple Home Compatible: Works properly with Apple Home's RVC requirements
|
|
20
|
+
*
|
|
21
|
+
* When you start Homebridge, you'll see logs like:
|
|
22
|
+
* ```
|
|
23
|
+
* [Matter] Publishing 1 external Matter accessory
|
|
24
|
+
* [Matter] Allocated port 5541 for external Matter accessory: Robot Vacuum
|
|
25
|
+
* [Matter] ✓ External Matter accessory published: Robot Vacuum on port 5541
|
|
26
|
+
* [Matter] 📱 Commissioning codes for Robot Vacuum:
|
|
27
|
+
* [Matter] QR Code: MT:Y.K9042C00KA0648G00
|
|
28
|
+
* [Matter] Manual Code: 3492-8840-7309-5200-911
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* Use the separate QR code to commission this device in Apple Home.
|
|
32
|
+
*
|
|
33
|
+
* For developers implementing similar devices:
|
|
34
|
+
* ──────────────────────────────────────────────
|
|
35
|
+
* If you need to create your own device that requires isolation (like cameras,
|
|
36
|
+
* doorbells, or other complex devices that Apple Home requires on separate bridges),
|
|
37
|
+
* follow this pattern:
|
|
38
|
+
*
|
|
39
|
+
* 1. Create the accessory configuration in a device file (like this one)
|
|
40
|
+
* 2. Return it from your registration function
|
|
41
|
+
* 3. In platform.ts, use api.matter.publishExternalAccessories() instead of
|
|
42
|
+
* api.matter.registerPlatformAccessories()
|
|
43
|
+
*
|
|
44
|
+
* Example in your platform.ts:
|
|
45
|
+
* ```typescript
|
|
46
|
+
* const accessories = [...registerYourDevice(context)]
|
|
47
|
+
* if (accessories.length > 0) {
|
|
48
|
+
* // Use publishExternalAccessories for devices that need isolation
|
|
49
|
+
* this.api.matter.publishExternalAccessories(PLUGIN_NAME, accessories)
|
|
50
|
+
* }
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
/**
|
|
54
|
+
* Registers a Robotic Vacuum Cleaner accessory.
|
|
55
|
+
*
|
|
56
|
+
* NOTE: This returns the accessory configuration but does NOT publish it.
|
|
57
|
+
* Publishing happens in platform.ts using api.matter.publishExternalAccessories().
|
|
58
|
+
*
|
|
59
|
+
* @param context - Device context containing API, logger, and config
|
|
60
|
+
* @returns Array of RVC accessory configurations (empty if disabled)
|
|
61
|
+
*/
|
|
62
|
+
export function registerRoboticVacuumCleaner(context) {
|
|
63
|
+
const { api, log, config } = context;
|
|
64
|
+
const accessories = [];
|
|
65
|
+
if (!config.enableRobotVacuum) {
|
|
66
|
+
return accessories;
|
|
67
|
+
}
|
|
68
|
+
// Generate UUID for this accessory - will be used for external bridge identification
|
|
69
|
+
const uuid = api.matter.uuid.generate('matter-robot-vacuum');
|
|
70
|
+
accessories.push({
|
|
71
|
+
// Unique identifier for this accessory
|
|
72
|
+
// This UUID will also be used to identify the external Matter bridge
|
|
73
|
+
uuid,
|
|
74
|
+
// Display name shown in Home apps
|
|
75
|
+
displayName: 'Robot Vacuum',
|
|
76
|
+
// Matter device type - RoboticVacuumCleaner (from Matter Spec § 12.1)
|
|
77
|
+
deviceType: api.matter.deviceTypes.RoboticVacuumCleaner,
|
|
78
|
+
// Device identification
|
|
79
|
+
serialNumber: 'VACUUM-001',
|
|
80
|
+
manufacturer: 'Matter Examples',
|
|
81
|
+
model: 'RobotVacuum v1',
|
|
82
|
+
// Matter clusters define the functionality of this device
|
|
83
|
+
// RVC devices require these three clusters: rvcRunMode, rvcOperationalState, rvcCleanMode
|
|
84
|
+
clusters: {
|
|
85
|
+
// RVC Run Mode Cluster (0x0054) - Defines operational modes
|
|
86
|
+
rvcRunMode: {
|
|
87
|
+
// Supported run modes (0=Idle, 1=Cleaning, 2=Mapping)
|
|
88
|
+
// These are the modes users can select in the Home app
|
|
89
|
+
supportedModes: [
|
|
90
|
+
{ label: 'Idle', mode: 0, modeTags: [{ value: 16384 }] }, // 16384 = Idle tag
|
|
91
|
+
{ label: 'Cleaning', mode: 1, modeTags: [{ value: 16385 }] }, // 16385 = Cleaning tag
|
|
92
|
+
{ label: 'Mapping', mode: 2, modeTags: [{ value: 16386 }] }, // 16386 = Mapping tag
|
|
93
|
+
],
|
|
94
|
+
// Current mode - initial state
|
|
95
|
+
currentMode: 0, // Start in Idle mode
|
|
96
|
+
},
|
|
97
|
+
// RVC Operational State Cluster (0x0061) - Tracks current activity
|
|
98
|
+
rvcOperationalState: {
|
|
99
|
+
// List of all possible operational states
|
|
100
|
+
// Must include at least an error state (ID 3)
|
|
101
|
+
operationalStateList: [
|
|
102
|
+
{ operationalStateId: 0 }, // Stopped
|
|
103
|
+
{ operationalStateId: 1 }, // Running
|
|
104
|
+
{ operationalStateId: 2 }, // Paused
|
|
105
|
+
{ operationalStateId: 3 }, // Error (REQUIRED by Matter spec)
|
|
106
|
+
{ operationalStateId: 64 }, // SeekingCharger
|
|
107
|
+
{ operationalStateId: 65 }, // Charging
|
|
108
|
+
{ operationalStateId: 66 }, // Docked
|
|
109
|
+
],
|
|
110
|
+
// Current operational state (just the ID number, not an object)
|
|
111
|
+
operationalState: 66, // Start in Docked state
|
|
112
|
+
// Error state - indicates if device has an error
|
|
113
|
+
operationalError: {
|
|
114
|
+
errorStateId: 0, // No error
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
// RVC Clean Mode Cluster (0x0055) - Defines cleaning method
|
|
118
|
+
rvcCleanMode: {
|
|
119
|
+
// Supported clean modes (0=Vacuum, 1=Mop, 2=Vacuum+Mop)
|
|
120
|
+
// These are the cleaning methods users can select
|
|
121
|
+
supportedModes: [
|
|
122
|
+
{ label: 'Vacuum', mode: 0, modeTags: [] },
|
|
123
|
+
{ label: 'Mop', mode: 1, modeTags: [] },
|
|
124
|
+
{ label: 'Vacuum & Mop', mode: 2, modeTags: [] },
|
|
125
|
+
],
|
|
126
|
+
// Current clean mode - initial state
|
|
127
|
+
currentMode: 0, // Start with Vacuum mode
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
// Handlers respond to commands from Home apps (Apple Home, Google Home, etc.)
|
|
131
|
+
// These are called when users interact with the device in their Home app
|
|
132
|
+
handlers: {
|
|
133
|
+
// RVC Operational State handlers - control device operation
|
|
134
|
+
rvcOperationalState: {
|
|
135
|
+
/**
|
|
136
|
+
* pause() - Called when user presses "pause" in Home app
|
|
137
|
+
*
|
|
138
|
+
* In a real implementation:
|
|
139
|
+
* - Send pause command to your actual robot vacuum
|
|
140
|
+
* - Wait for confirmation
|
|
141
|
+
* - Then update the Matter state
|
|
142
|
+
*/
|
|
143
|
+
pause: async () => {
|
|
144
|
+
log.info('[Robot Vacuum] ✓ Handler `pause` called - Pausing cleaning');
|
|
145
|
+
// TODO: Send pause command to your actual robot vacuum here
|
|
146
|
+
// Example: await yourVacuumAPI.pause()
|
|
147
|
+
// Update Matter state to reflect the change
|
|
148
|
+
// This notifies all connected Home apps of the new state
|
|
149
|
+
await api.matter.updateAccessoryState(uuid, // Use the same UUID we generated above
|
|
150
|
+
'rvcOperationalState', { operationalState: 2 });
|
|
151
|
+
},
|
|
152
|
+
/**
|
|
153
|
+
* resume() - Called when user presses "resume" or "start" in Home app
|
|
154
|
+
*
|
|
155
|
+
* In a real implementation:
|
|
156
|
+
* - Send start/resume command to your actual robot vacuum
|
|
157
|
+
* - Wait for confirmation
|
|
158
|
+
* - Then update the Matter state
|
|
159
|
+
*/
|
|
160
|
+
resume: async () => {
|
|
161
|
+
log.info('[Robot Vacuum] ✓ Handler `resume` called - Resuming cleaning');
|
|
162
|
+
// TODO: Send resume command to your actual robot vacuum here
|
|
163
|
+
// Example: await yourVacuumAPI.resume()
|
|
164
|
+
// Update Matter state to Running
|
|
165
|
+
await api.matter.updateAccessoryState(uuid, 'rvcOperationalState', { operationalState: 1 });
|
|
166
|
+
},
|
|
167
|
+
/**
|
|
168
|
+
* goHome() - Called when user sends robot to charging dock
|
|
169
|
+
*
|
|
170
|
+
* In a real implementation:
|
|
171
|
+
* - Send return-to-dock command to your actual robot vacuum
|
|
172
|
+
* - Wait for confirmation
|
|
173
|
+
* - Then update the Matter state
|
|
174
|
+
*/
|
|
175
|
+
goHome: async () => {
|
|
176
|
+
log.info('[Robot Vacuum] ✓ Handler `goHome` called - Returning to dock');
|
|
177
|
+
// TODO: Send return-to-dock command to your actual robot vacuum here
|
|
178
|
+
// Example: await yourVacuumAPI.returnToDock()
|
|
179
|
+
// Update Matter state to SeekingCharger
|
|
180
|
+
await api.matter.updateAccessoryState(uuid, 'rvcOperationalState', { operationalState: 64 });
|
|
181
|
+
// TIP: You could set up a timer or polling to detect when the vacuum
|
|
182
|
+
// actually docks, then update to state 66 (Docked) or 65 (Charging)
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
// RVC Run Mode handlers - change operational modes
|
|
186
|
+
rvcRunMode: {
|
|
187
|
+
/**
|
|
188
|
+
* changeToMode() - Called when user changes the run mode
|
|
189
|
+
*
|
|
190
|
+
* Modes: 0=Idle, 1=Cleaning, 2=Mapping
|
|
191
|
+
*
|
|
192
|
+
* In a real implementation:
|
|
193
|
+
* - Send mode change command to your actual robot vacuum
|
|
194
|
+
* - Wait for confirmation
|
|
195
|
+
* - Then update the Matter state
|
|
196
|
+
*/
|
|
197
|
+
changeToMode: async (request) => {
|
|
198
|
+
const modes = ['Idle', 'Cleaning', 'Mapping'];
|
|
199
|
+
const modeName = modes[request.newMode] || `Unknown (${request.newMode})`;
|
|
200
|
+
log.info(`[Robot Vacuum] ✓ Handler \`changeToMode\` called: ${request.newMode} (${modeName})`);
|
|
201
|
+
// TODO: Send mode change command to your actual robot vacuum here
|
|
202
|
+
// Example:
|
|
203
|
+
// if (request.newMode === 1) {
|
|
204
|
+
// await yourVacuumAPI.startCleaning()
|
|
205
|
+
// } else if (request.newMode === 2) {
|
|
206
|
+
// await yourVacuumAPI.startMapping()
|
|
207
|
+
// } else {
|
|
208
|
+
// await yourVacuumAPI.idle()
|
|
209
|
+
// }
|
|
210
|
+
// Update Matter state
|
|
211
|
+
await api.matter.updateAccessoryState(uuid, 'rvcRunMode', { currentMode: request.newMode });
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
// RVC Clean Mode handlers - change cleaning method
|
|
215
|
+
rvcCleanMode: {
|
|
216
|
+
/**
|
|
217
|
+
* changeToMode() - Called when user changes the clean mode
|
|
218
|
+
*
|
|
219
|
+
* Modes: 0=Vacuum, 1=Mop, 2=Vacuum & Mop
|
|
220
|
+
*
|
|
221
|
+
* In a real implementation:
|
|
222
|
+
* - Send clean mode change command to your actual robot vacuum
|
|
223
|
+
* - Wait for confirmation
|
|
224
|
+
* - Then update the Matter state
|
|
225
|
+
*/
|
|
226
|
+
changeToMode: async (request) => {
|
|
227
|
+
const modes = ['Vacuum', 'Mop', 'Vacuum & Mop'];
|
|
228
|
+
const modeName = modes[request.newMode] || `Unknown (${request.newMode})`;
|
|
229
|
+
log.info(`[Robot Vacuum] ✓ Handler \`changeToMode\` (clean mode) called: ${request.newMode} (${modeName})`);
|
|
230
|
+
// TODO: Send clean mode change to your actual robot vacuum here
|
|
231
|
+
// Example:
|
|
232
|
+
// if (request.newMode === 0) {
|
|
233
|
+
// await yourVacuumAPI.setMode('vacuum')
|
|
234
|
+
// } else if (request.newMode === 1) {
|
|
235
|
+
// await yourVacuumAPI.setMode('mop')
|
|
236
|
+
// } else if (request.newMode === 2) {
|
|
237
|
+
// await yourVacuumAPI.setMode('vacuum_and_mop')
|
|
238
|
+
// }
|
|
239
|
+
// Update Matter state
|
|
240
|
+
await api.matter.updateAccessoryState(uuid, 'rvcCleanMode', { currentMode: request.newMode });
|
|
241
|
+
},
|
|
242
|
+
},
|
|
243
|
+
},
|
|
244
|
+
});
|
|
245
|
+
// Log helpful information
|
|
246
|
+
log.info('[Robot Vacuum] Configuration created');
|
|
247
|
+
log.info('[Robot Vacuum] This device will be published on its own external bridge');
|
|
248
|
+
log.info('[Robot Vacuum] Look for separate commissioning codes in the logs when Homebridge starts');
|
|
249
|
+
return accessories;
|
|
250
|
+
}
|
|
251
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
252
|
+
// DEVELOPER NOTES: Implementing a Real Robot Vacuum Integration
|
|
253
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
254
|
+
//
|
|
255
|
+
// This example uses static states and logs commands. For a real integration:
|
|
256
|
+
//
|
|
257
|
+
// 1. INITIAL SETUP:
|
|
258
|
+
// - Store the robot vacuum API client in your platform instance
|
|
259
|
+
// - Authenticate with the vacuum's cloud service or local API
|
|
260
|
+
// - Set up any required polling or webhooks to receive state updates
|
|
261
|
+
//
|
|
262
|
+
// 2. STATE UPDATES FROM VACUUM:
|
|
263
|
+
// When your vacuum's state changes (via app, button, schedule, etc.):
|
|
264
|
+
// ```typescript
|
|
265
|
+
// // Listen for state changes from your vacuum
|
|
266
|
+
// vacuumAPI.on('stateChanged', (newState) => {
|
|
267
|
+
// api.matter.updateAccessoryState(uuid, 'rvcOperationalState', {
|
|
268
|
+
// operationalState: convertToMatterState(newState)
|
|
269
|
+
// })
|
|
270
|
+
// })
|
|
271
|
+
// ```
|
|
272
|
+
//
|
|
273
|
+
// 3. COMMANDS TO VACUUM:
|
|
274
|
+
// In your handlers, send actual commands to the vacuum:
|
|
275
|
+
// ```typescript
|
|
276
|
+
// pause: async () => {
|
|
277
|
+
// try {
|
|
278
|
+
// await vacuumAPI.pause()
|
|
279
|
+
// log.info('Successfully paused vacuum')
|
|
280
|
+
// await api.matter.updateAccessoryState(uuid, 'rvcOperationalState', {
|
|
281
|
+
// operationalState: 2 // Paused
|
|
282
|
+
// })
|
|
283
|
+
// } catch (error) {
|
|
284
|
+
// log.error('Failed to pause vacuum:', error)
|
|
285
|
+
// // Optionally set error state
|
|
286
|
+
// await api.matter.updateAccessoryState(uuid, 'rvcOperationalState', {
|
|
287
|
+
// operationalState: 3, // Error
|
|
288
|
+
// operationalError: { errorStateId: 1 }
|
|
289
|
+
// })
|
|
290
|
+
// }
|
|
291
|
+
// }
|
|
292
|
+
// ```
|
|
293
|
+
//
|
|
294
|
+
// 4. ERROR HANDLING:
|
|
295
|
+
// - Always wrap API calls in try/catch
|
|
296
|
+
// - Update Matter state to reflect errors
|
|
297
|
+
// - Log detailed error information for debugging
|
|
298
|
+
//
|
|
299
|
+
// 5. BATTERY LEVEL (optional):
|
|
300
|
+
// Add a PowerSource cluster to report battery:
|
|
301
|
+
// ```typescript
|
|
302
|
+
// clusters: {
|
|
303
|
+
// powerSource: {
|
|
304
|
+
// status: 1, // BatCharging
|
|
305
|
+
// batChargeLevel: 80, // 0-100%
|
|
306
|
+
// }
|
|
307
|
+
// }
|
|
308
|
+
// ```
|
|
309
|
+
//
|
|
310
|
+
// 6. TESTING:
|
|
311
|
+
// - Test with Apple Home (requires external bridge - done automatically!)
|
|
312
|
+
// - Test with Google Home
|
|
313
|
+
// - Test with Alexa (if supported)
|
|
314
|
+
// - Test all operational states and modes
|
|
315
|
+
// - Test error conditions
|
|
316
|
+
//
|
|
317
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
318
|
+
//# sourceMappingURL=robotic-vacuum-cleaner.js.map
|
|
@@ -0,0 +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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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Color Temperature Light Device (Matter Spec § 4.3)
|
|
3
|
+
*
|
|
4
|
+
* A lighting device with color temperature control.
|
|
5
|
+
*/
|
|
6
|
+
export function registerColorTemperatureLight(context) {
|
|
7
|
+
const { api, log, config } = context;
|
|
8
|
+
const accessories = [];
|
|
9
|
+
if (!config.enableColourTemperatureLight) {
|
|
10
|
+
return accessories;
|
|
11
|
+
}
|
|
12
|
+
accessories.push({
|
|
13
|
+
uuid: api.matter.uuid.generate('matter-colour-temp-light'),
|
|
14
|
+
displayName: 'Colour Temperature Light',
|
|
15
|
+
deviceType: api.matter.deviceTypes.ColorTemperatureLight,
|
|
16
|
+
serialNumber: 'LIGHT-003',
|
|
17
|
+
manufacturer: 'Matter Examples',
|
|
18
|
+
model: 'ColourTempLight v1',
|
|
19
|
+
clusters: {
|
|
20
|
+
onOff: {
|
|
21
|
+
onOff: false,
|
|
22
|
+
},
|
|
23
|
+
levelControl: {
|
|
24
|
+
currentLevel: 127,
|
|
25
|
+
minLevel: 1,
|
|
26
|
+
maxLevel: 254,
|
|
27
|
+
},
|
|
28
|
+
colorControl: {
|
|
29
|
+
colorMode: 2, // Colour temperature mode
|
|
30
|
+
colorTemperatureMireds: 250, // ~4000K
|
|
31
|
+
colorTempPhysicalMinMireds: 147, // 6800K (coolest)
|
|
32
|
+
colorTempPhysicalMaxMireds: 454, // 2200K (warmest)
|
|
33
|
+
coupleColorTempToLevelMinMireds: 147,
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
handlers: {
|
|
37
|
+
onOff: {
|
|
38
|
+
on: async () => {
|
|
39
|
+
log.info('[Colour Temp Light] ✓ Handler `on` called (user controlled via Home app)');
|
|
40
|
+
},
|
|
41
|
+
off: async () => {
|
|
42
|
+
log.info('[Colour Temp Light] ✓ Handler `off` called (user controlled via Home app)');
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
levelControl: {
|
|
46
|
+
moveToLevelWithOnOff: async (request) => {
|
|
47
|
+
const { level } = request;
|
|
48
|
+
log.info(`[Colour Temp Light] ✓ Handler \`moveToLevel\` called with ${level} (${Math.round(level / 254 * 100)}%)`);
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
colorControl: {
|
|
52
|
+
moveToColorTemperatureLogic: async (request) => {
|
|
53
|
+
const { targetMireds, transitionTime } = request;
|
|
54
|
+
const kelvin = Math.round(1000000 / targetMireds);
|
|
55
|
+
log.info(`[Colour Temp Light] ✓ Handler \`moveToColorTemperatureLogic\` called with ${targetMireds} mireds (~${kelvin}K), transition: ${transitionTime}s`);
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
return accessories;
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=color-temperature-light.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"color-temperature-light.js","sourceRoot":"","sources":["../../../src/devices/section-4-lighting/color-temperature-light.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,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;aACb;YACD,YAAY,EAAE;gBACZ,YAAY,EAAE,GAAG;gBACjB,QAAQ,EAAE,CAAC;gBACX,QAAQ,EAAE,GAAG;aACd;YACD,YAAY,EAAE;gBACZ,SAAS,EAAE,CAAC,EAAE,0BAA0B;gBACxC,sBAAsB,EAAE,GAAG,EAAE,SAAS;gBACtC,0BAA0B,EAAE,GAAG,EAAE,kBAAkB;gBACnD,0BAA0B,EAAE,GAAG,EAAE,kBAAkB;gBACnD,+BAA+B,EAAE,GAAG;aACrC;SACF;QAED,QAAQ,EAAE;YACR,KAAK,EAAE;gBACL,EAAE,EAAE,KAAK,IAAI,EAAE;oBACb,GAAG,CAAC,IAAI,CAAC,0EAA0E,CAAC,CAAA;gBACtF,CAAC;gBACD,GAAG,EAAE,KAAK,IAAI,EAAE;oBACd,GAAG,CAAC,IAAI,CAAC,2EAA2E,CAAC,CAAA;gBACvF,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;gBACpH,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;gBAC5J,CAAC;aACF;SACF;KACF,CAAC,CAAA;IAEF,OAAO,WAAW,CAAA;AACpB,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dimmable Light Device (Matter Spec § 4.2)
|
|
3
|
+
*
|
|
4
|
+
* A lighting device with on/off and level control (brightness).
|
|
5
|
+
*/
|
|
6
|
+
export function registerDimmableLight(context) {
|
|
7
|
+
const { api, log, config } = context;
|
|
8
|
+
const accessories = [];
|
|
9
|
+
if (!config.enableDimmableLight) {
|
|
10
|
+
return accessories;
|
|
11
|
+
}
|
|
12
|
+
accessories.push({
|
|
13
|
+
uuid: api.matter.uuid.generate('matter-dimmable-light'),
|
|
14
|
+
displayName: 'Dimmable Light',
|
|
15
|
+
deviceType: api.matter.deviceTypes.DimmableLight,
|
|
16
|
+
serialNumber: 'LIGHT-002',
|
|
17
|
+
manufacturer: 'Matter Examples',
|
|
18
|
+
model: 'DimmableLight v1',
|
|
19
|
+
clusters: {
|
|
20
|
+
onOff: {
|
|
21
|
+
onOff: false,
|
|
22
|
+
},
|
|
23
|
+
levelControl: {
|
|
24
|
+
currentLevel: 127,
|
|
25
|
+
minLevel: 1,
|
|
26
|
+
maxLevel: 254,
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
handlers: {
|
|
30
|
+
onOff: {
|
|
31
|
+
on: async () => {
|
|
32
|
+
log.info('[Dimmable Light] ✓ Handler `on` called (user controlled via Home app)');
|
|
33
|
+
},
|
|
34
|
+
off: async () => {
|
|
35
|
+
log.info('[Dimmable Light] ✓ Handler `off` called (user controlled via Home app)');
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
levelControl: {
|
|
39
|
+
moveToLevelWithOnOff: async (request) => {
|
|
40
|
+
const { level } = request;
|
|
41
|
+
log.info(`[Dimmable Light] ✓ Handler \`moveToLevel\` called with ${level} (${Math.round(level / 254 * 100)}%)`);
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
return accessories;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=dimmable-light.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dimmable-light.js","sourceRoot":"","sources":["../../../src/devices/section-4-lighting/dimmable-light.ts"],"names":[],"mappings":"AAAA;;;;GAIG;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,WAAW,CAAC,IAAI,CAAC;QACf,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;gBACjB,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,uEAAuE,CAAC,CAAA;gBACnF,CAAC;gBACD,GAAG,EAAE,KAAK,IAAI,EAAE;oBACd,GAAG,CAAC,IAAI,CAAC,wEAAwE,CAAC,CAAA;gBACpF,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,0DAA0D,KAAK,KAAK,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,GAAG,GAAG,CAAC,IAAI,CAAC,CAAA;gBACjH,CAAC;aACF;SACF;KACF,CAAC,CAAA;IAEF,OAAO,WAAW,CAAA;AACpB,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extended Color Light Device (Matter Spec § 4.4)
|
|
3
|
+
*
|
|
4
|
+
* Handles both variants:
|
|
5
|
+
* - Color Light (HS): Hue/Saturation only
|
|
6
|
+
* - Extended Color Light (HS+CCT): Hue/Saturation + Color Temperature
|
|
7
|
+
*
|
|
8
|
+
* Both use the same Matter device type (ExtendedColorLight) but with different
|
|
9
|
+
* cluster configurations.
|
|
10
|
+
*/
|
|
11
|
+
import type { DeviceContext } from '../types.js';
|
|
12
|
+
export declare function registerExtendedColorLight(context: DeviceContext): any[];
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extended Color Light Device (Matter Spec § 4.4)
|
|
3
|
+
*
|
|
4
|
+
* Handles both variants:
|
|
5
|
+
* - Color Light (HS): Hue/Saturation only
|
|
6
|
+
* - Extended Color Light (HS+CCT): Hue/Saturation + Color Temperature
|
|
7
|
+
*
|
|
8
|
+
* Both use the same Matter device type (ExtendedColorLight) but with different
|
|
9
|
+
* cluster configurations.
|
|
10
|
+
*/
|
|
11
|
+
export function registerExtendedColorLight(context) {
|
|
12
|
+
const { api, log, config } = context;
|
|
13
|
+
const accessories = [];
|
|
14
|
+
// Variant 1: Color Light (HS only - no CCT)
|
|
15
|
+
if (config.enableColourLight) {
|
|
16
|
+
accessories.push({
|
|
17
|
+
uuid: api.matter.uuid.generate('matter-colour-light'),
|
|
18
|
+
displayName: 'Colour Light (HS)',
|
|
19
|
+
deviceType: api.matter.deviceTypes.ExtendedColorLight,
|
|
20
|
+
serialNumber: 'LIGHT-004',
|
|
21
|
+
manufacturer: 'Matter Examples',
|
|
22
|
+
model: 'ColorLight v1',
|
|
23
|
+
clusters: {
|
|
24
|
+
onOff: {
|
|
25
|
+
onOff: false,
|
|
26
|
+
},
|
|
27
|
+
levelControl: {
|
|
28
|
+
currentLevel: 127,
|
|
29
|
+
minLevel: 1,
|
|
30
|
+
maxLevel: 254,
|
|
31
|
+
},
|
|
32
|
+
colorControl: {
|
|
33
|
+
colorMode: 0, // Hue/Saturation mode
|
|
34
|
+
currentHue: 0, // Red (0 degrees)
|
|
35
|
+
currentSaturation: 254, // Full saturation
|
|
36
|
+
currentX: 41942, // Also provide XY for compatibility
|
|
37
|
+
currentY: 21626,
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
handlers: {
|
|
41
|
+
onOff: {
|
|
42
|
+
on: async () => {
|
|
43
|
+
log.info('[Colour Light HS] ✓ Handler `on` called (user controlled via Home app)');
|
|
44
|
+
},
|
|
45
|
+
off: async () => {
|
|
46
|
+
log.info('[Colour Light HS] ✓ Handler `off` called (user controlled via Home app)');
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
levelControl: {
|
|
50
|
+
moveToLevelWithOnOff: async (request) => {
|
|
51
|
+
const { level } = request;
|
|
52
|
+
log.info(`[Colour Light HS] ✓ Handler \`moveToLevel\` called with ${level} (${Math.round(level / 254 * 100)}%)`);
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
colorControl: {
|
|
56
|
+
moveToColorLogic: async (request) => {
|
|
57
|
+
const { targetX, targetY, transitionTime } = request;
|
|
58
|
+
const xFloat = (targetX / 65535).toFixed(4);
|
|
59
|
+
const yFloat = (targetY / 65535).toFixed(4);
|
|
60
|
+
log.info(`[Colour Light HS] ✓ Handler \`moveToColorLogic\` called with x=${targetX} (~${xFloat}), y=${targetY} (~${yFloat}), transition: ${transitionTime}s`);
|
|
61
|
+
},
|
|
62
|
+
moveToHueAndSaturationLogic: async (request) => {
|
|
63
|
+
const { targetHue, targetSaturation, transitionTime } = request;
|
|
64
|
+
const hueDegrees = Math.round((targetHue / 254) * 360);
|
|
65
|
+
const saturationPercent = Math.round((targetSaturation / 254) * 100);
|
|
66
|
+
log.info(`[Colour Light HS] ✓ Handler \`moveToHueAndSaturationLogic\` called with hue=${targetHue} (~${hueDegrees}°), saturation=${targetSaturation} (~${saturationPercent}%), transition: ${transitionTime}s`);
|
|
67
|
+
},
|
|
68
|
+
// NOTE: No moveToColorTemperatureLogic handler - this variant only supports color, not CCT
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
// Variant 2: Extended Color Light (HS + CCT)
|
|
74
|
+
if (config.enableExtendedColourLight) {
|
|
75
|
+
accessories.push({
|
|
76
|
+
uuid: api.matter.uuid.generate('matter-extended-colour-light'),
|
|
77
|
+
displayName: 'Extended Colour Light (HS+CCT)',
|
|
78
|
+
deviceType: api.matter.deviceTypes.ExtendedColorLight,
|
|
79
|
+
serialNumber: 'LIGHT-005',
|
|
80
|
+
manufacturer: 'Matter Examples',
|
|
81
|
+
model: 'ExtendedColorLight v1',
|
|
82
|
+
clusters: {
|
|
83
|
+
onOff: {
|
|
84
|
+
onOff: false,
|
|
85
|
+
},
|
|
86
|
+
levelControl: {
|
|
87
|
+
currentLevel: 127,
|
|
88
|
+
minLevel: 1,
|
|
89
|
+
maxLevel: 254,
|
|
90
|
+
},
|
|
91
|
+
colorControl: {
|
|
92
|
+
colorMode: 0, // Hue/Saturation mode
|
|
93
|
+
currentHue: 0, // Red (0 degrees)
|
|
94
|
+
currentSaturation: 254, // Full saturation
|
|
95
|
+
currentX: 41942, // Also provide XY for compatibility
|
|
96
|
+
currentY: 21626,
|
|
97
|
+
colorTemperatureMireds: 250, // ~4000K (for CCT mode)
|
|
98
|
+
colorTempPhysicalMinMireds: 147, // 6800K (coolest)
|
|
99
|
+
colorTempPhysicalMaxMireds: 454, // 2200K (warmest)
|
|
100
|
+
coupleColorTempToLevelMinMireds: 147,
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
handlers: {
|
|
104
|
+
onOff: {
|
|
105
|
+
on: async () => {
|
|
106
|
+
log.info('[Extended Colour Light] ✓ Handler `on` called (user controlled via Home app)');
|
|
107
|
+
},
|
|
108
|
+
off: async () => {
|
|
109
|
+
log.info('[Extended Colour Light] ✓ Handler `off` called (user controlled via Home app)');
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
levelControl: {
|
|
113
|
+
moveToLevelWithOnOff: async (request) => {
|
|
114
|
+
const { level } = request;
|
|
115
|
+
log.info(`[Extended Colour Light] ✓ Handler \`moveToLevel\` called with ${level} (${Math.round(level / 254 * 100)}%)`);
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
colorControl: {
|
|
119
|
+
moveToColorLogic: async (request) => {
|
|
120
|
+
const { targetX, targetY, transitionTime } = request;
|
|
121
|
+
const xFloat = (targetX / 65535).toFixed(4);
|
|
122
|
+
const yFloat = (targetY / 65535).toFixed(4);
|
|
123
|
+
log.info(`[Extended Colour Light] ✓ Handler \`moveToColorLogic\` called with x=${targetX} (~${xFloat}), y=${targetY} (~${yFloat}), transition: ${transitionTime}s`);
|
|
124
|
+
},
|
|
125
|
+
moveToHueAndSaturationLogic: async (request) => {
|
|
126
|
+
const { targetHue, targetSaturation, transitionTime } = request;
|
|
127
|
+
const hueDegrees = Math.round((targetHue / 254) * 360);
|
|
128
|
+
const saturationPercent = Math.round((targetSaturation / 254) * 100);
|
|
129
|
+
log.info(`[Extended Colour Light] ✓ Handler \`moveToHueAndSaturationLogic\` called with hue=${targetHue} (~${hueDegrees}°), saturation=${targetSaturation} (~${saturationPercent}%), transition: ${transitionTime}s`);
|
|
130
|
+
},
|
|
131
|
+
moveToColorTemperatureLogic: async (request) => {
|
|
132
|
+
const { targetMireds, transitionTime } = request;
|
|
133
|
+
const kelvin = Math.round(1000000 / targetMireds);
|
|
134
|
+
log.info(`[Extended Colour Light] ✓ Handler \`moveToColorTemperatureLogic\` called with ${targetMireds} mireds (~${kelvin}K), transition: ${transitionTime}s`);
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
return accessories;
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=extended-color-light.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extended-color-light.js","sourceRoot":"","sources":["../../../src/devices/section-4-lighting/extended-color-light.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Section 4: Lighting Devices
|
|
3
|
+
*
|
|
4
|
+
* Matter Specification § 4 - Fundamental lighting device types
|
|
5
|
+
*/
|
|
6
|
+
export { registerColorTemperatureLight } from './color-temperature-light.js';
|
|
7
|
+
export { registerDimmableLight } from './dimmable-light.js';
|
|
8
|
+
export { registerExtendedColorLight } from './extended-color-light.js';
|
|
9
|
+
export { registerOnOffLight } from './on-off-light.js';
|