@homebridge-plugins/homebridge-matter 0.1.4-beta.0 → 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 CHANGED
@@ -2,6 +2,13 @@
2
2
 
3
3
  All notable changes to `@homebridge-plugins/homebridge-matter` will be documented in this file.
4
4
 
5
+ ## v0.1.4 (2025-10-23)
6
+
7
+ ### Changes
8
+
9
+ - consolidate device code comments in docs
10
+ - fix switch device implementation example
11
+
5
12
  ## v0.1.3 (2025-10-22)
6
13
 
7
14
  ### Changes
package/MATTER_API.md CHANGED
@@ -13,7 +13,8 @@ This document serves as a comprehensive guide for integrating Matter devices int
13
13
  5. [Monitoring External Changes](#monitoring-external-changes)
14
14
  6. [Using Matter Types](#using-matter-types)
15
15
  7. [Best Practices](#best-practices)
16
- 8. [Device Reference](#device-reference)
16
+ 8. [API Reference](#api-reference)
17
+ 9. [Device Reference](#device-reference)
17
18
 
18
19
  ---
19
20
 
@@ -172,46 +173,46 @@ handlers: {
172
173
 
173
174
  #### Level Control
174
175
  ```typescript
175
- MatterRequests.MoveToLevel // { level, transitionTime?, optionsMask?, optionsOverride? }
176
- MatterRequests.Move // { moveMode, rate?, optionsMask?, optionsOverride? }
177
- MatterRequests.Step // { stepMode, stepSize, transitionTime?, ... }
178
- MatterRequests.Stop // { optionsMask?, optionsOverride? }
176
+ MatterRequests.MoveToLevel // { level, transitionTime?, optionsMask?, optionsOverride? }
177
+ MatterRequests.Move // { moveMode, rate?, optionsMask?, optionsOverride? }
178
+ MatterRequests.Step // { stepMode, stepSize, transitionTime?, ... }
179
+ MatterRequests.Stop // { optionsMask?, optionsOverride? }
179
180
  ```
180
181
 
181
182
  #### Color Control
182
183
  ```typescript
183
- MatterRequests.MoveToHue // { hue, direction, transitionTime?, ... }
184
- MatterRequests.MoveToSaturation // { saturation, transitionTime?, ... }
185
- MatterRequests.MoveToHueAndSaturation // { hue, saturation, transitionTime?, ... }
186
- MatterRequests.MoveToColorTemperature // { colorTemperatureMireds, transitionTime?, ... }
187
- MatterRequests.MoveHue // { moveMode, rate?, ... }
188
- MatterRequests.MoveSaturation // { moveMode, rate?, ... }
189
- MatterRequests.MoveColorTemperature // { moveMode, rate?, ... }
190
- MatterRequests.StepHue // { stepMode, stepSize, transitionTime?, ... }
191
- MatterRequests.StepSaturation // { stepMode, stepSize, transitionTime?, ... }
192
- MatterRequests.StepColorTemperature // { stepMode, stepSize, transitionTime?, ... }
184
+ MatterRequests.MoveToHue // { hue, direction, transitionTime?, ... }
185
+ MatterRequests.MoveToSaturation // { saturation, transitionTime?, ... }
186
+ MatterRequests.MoveToHueAndSaturation // { hue, saturation, transitionTime?, ... }
187
+ MatterRequests.MoveToColorTemperature // { colorTemperatureMireds, transitionTime?, ... }
188
+ MatterRequests.MoveHue // { moveMode, rate?, ... }
189
+ MatterRequests.MoveSaturation // { moveMode, rate?, ... }
190
+ MatterRequests.MoveColorTemperature // { moveMode, rate?, ... }
191
+ MatterRequests.StepHue // { stepMode, stepSize, transitionTime?, ... }
192
+ MatterRequests.StepSaturation // { stepMode, stepSize, transitionTime?, ... }
193
+ MatterRequests.StepColorTemperature // { stepMode, stepSize, transitionTime?, ... }
193
194
  ```
194
195
 
195
196
  #### Door Lock
196
197
  ```typescript
197
- MatterRequests.LockDoor // { pinCode? }
198
- MatterRequests.UnlockDoor // { pinCode? }
198
+ MatterRequests.LockDoor // { pinCode? }
199
+ MatterRequests.UnlockDoor // { pinCode? }
199
200
  ```
200
201
 
201
202
  #### Window Covering
202
203
  ```typescript
203
- MatterRequests.GoToLiftPercentage // { liftPercent100thsValue }
204
- MatterRequests.GoToTiltPercentage // { tiltPercent100thsValue }
204
+ MatterRequests.GoToLiftPercentage // { liftPercent100thsValue }
205
+ MatterRequests.GoToTiltPercentage // { tiltPercent100thsValue }
205
206
  ```
206
207
 
207
208
  #### Thermostat
208
209
  ```typescript
209
- MatterRequests.SetpointRaiseLower // { mode, amount }
210
+ MatterRequests.SetpointRaiseLower // { mode, amount }
210
211
  ```
211
212
 
212
213
  #### Fan Control
213
214
  ```typescript
214
- MatterRequests.FanStep // { direction, wrap?, lowestOff? }
215
+ MatterRequests.FanStep // { direction, wrap?, lowestOff? }
215
216
  ```
216
217
 
217
218
  </details>
@@ -276,7 +277,7 @@ const accessory = {
276
277
 
277
278
  // These are CLUSTERS within the endpoint
278
279
  clusters: {
279
- onOff: { onOff: false }, // OnOff cluster
280
+ onOff: { onOff: false }, // OnOff cluster
280
281
  levelControl: { currentLevel: 127 }, // LevelControl cluster
281
282
  },
282
283
  }
@@ -581,15 +582,15 @@ Access cluster attributes directly from the accessory object:
581
582
 
582
583
  ```typescript
583
584
  // Read power state
584
- const isOn = accessory.clusters.onOff.onOff // boolean
585
+ const isOn = accessory.clusters.onOff.onOff // boolean
585
586
 
586
587
  // Read brightness
587
- const level = accessory.clusters.levelControl.currentLevel // 1-254
588
- const percent = Math.round((level / 254) * 100) // Convert to percentage
588
+ const level = accessory.clusters.levelControl.currentLevel // 1-254
589
+ const percent = Math.round((level / 254) * 100) // Convert to percentage
589
590
 
590
591
  // Read color
591
- const hue = accessory.clusters.colorControl.currentHue // 0-254
592
- const saturation = accessory.clusters.colorControl.currentSaturation // 0-254
592
+ const hue = accessory.clusters.colorControl.currentHue // 0-254
593
+ const saturation = accessory.clusters.colorControl.currentSaturation // 0-254
593
594
  ```
594
595
 
595
596
  **When to use**: This is the recommended approach in most cases when you have a reference to the accessory object.
@@ -608,13 +609,13 @@ Use the API method when you don't have a reference to the accessory object:
608
609
  // Read state by UUID
609
610
  const state = api.matter.getAccessoryState(uuid, api.matter.clusterNames.OnOff)
610
611
  if (state) {
611
- const isOn = state.onOff // boolean
612
+ const isOn = state.onOff // boolean
612
613
  }
613
614
 
614
615
  // Read brightness
615
616
  const levelState = api.matter.getAccessoryState(uuid, api.matter.clusterNames.LevelControl)
616
617
  if (levelState) {
617
- const level = levelState.currentLevel // 1-254
618
+ const level = levelState.currentLevel // 1-254
618
619
  }
619
620
  ```
620
621
 
@@ -632,9 +633,9 @@ Use `updateAccessoryState()` to manually update cluster attributes:
632
633
 
633
634
  ```typescript
634
635
  api.matter.updateAccessoryState(
635
- accessory.uuid, // UUID of the accessory
636
- api.matter.clusterNames.OnOff, // Cluster name (use constants!)
637
- { onOff: true } // New attribute values
636
+ accessory.uuid, // UUID of the accessory
637
+ api.matter.clusterNames.OnOff, // Cluster name (use constants!)
638
+ { onOff: true } // New attribute values
638
639
  )
639
640
  ```
640
641
 
@@ -910,7 +911,7 @@ setInterval(async () => {
910
911
  } catch (error) {
911
912
  log.error(`Error polling device: ${error}`)
912
913
  }
913
- }, 5000) // Poll every 5 seconds
914
+ }, 5000) // Poll every 5 seconds
914
915
  ```
915
916
 
916
917
  ---
@@ -1099,123 +1100,478 @@ api.matter.updateAccessoryState(uuid, 'onOff', {...})
1099
1100
 
1100
1101
  ---
1101
1102
 
1102
- ## Device Reference
1103
+ ## API Reference
1103
1104
 
1104
- This section documents all available Matter device types with their clusters, attributes, handlers, and usage examples.
1105
+ Complete reference for all Matter API methods and properties available in Homebridge.
1105
1106
 
1106
- ### On/Off Light
1107
+ ### Platform API Methods
1107
1108
 
1108
- **Device Type**: `api.matter.deviceTypes.OnOffLight`
1109
+ #### `api.isMatterAvailable(): boolean`
1109
1110
 
1110
- **Description**: A lighting device capable of being switched on or off.
1111
+ Check if Matter is available in the current version of Homebridge.
1111
1112
 
1112
- **Matter Specification**: § 4.1
1113
+ **Returns:** `true` if Homebridge version is >= 2.0.0-alpha.0
1113
1114
 
1114
- #### Required Clusters
1115
+ **Usage:**
1116
+ ```typescript
1117
+ if (api.isMatterAvailable()) {
1118
+ log.info('Matter is available in this Homebridge version')
1119
+ } else {
1120
+ log.warn('Matter requires Homebridge >= 2.0.0-alpha.0')
1121
+ }
1122
+ ```
1115
1123
 
1116
- ##### OnOff Cluster
1124
+ **When to use:**
1125
+ - Plugin compatibility checks
1126
+ - Conditional feature loading
1127
+ - Version-specific functionality
1117
1128
 
1118
- Controls the power state of the light.
1129
+ ---
1119
1130
 
1120
- **Attributes**:
1131
+ #### `api.isMatterEnabled(): boolean`
1121
1132
 
1122
- | Attribute | Type | Range/Values | Description |
1123
- |-----------|---------|-----------------|----------------------------------|
1124
- | `onOff` | boolean | `true`, `false` | Power state (true=on, false=off) |
1133
+ Check if Matter is enabled for this bridge instance.
1134
+
1135
+ **Returns:** `true` if Matter is enabled in the bridge configuration
1125
1136
 
1126
- **Handlers**:
1137
+ **Configuration:**
1138
+ - For main bridge: Set `bridge.matter = true` in config.json
1139
+ - For child bridge: Set `_bridge.matter = true` in platform config
1127
1140
 
1141
+ **Usage:**
1128
1142
  ```typescript
1129
- handlers: {
1130
- onOff: {
1131
- /**
1132
- * Called when user turns light ON via Home app
1133
- */
1134
- on: async () => {
1135
- // Control your physical device
1136
- await myLightAPI.turnOn()
1137
- // State automatically updated by Homebridge
1138
- },
1143
+ if (api.isMatterEnabled()) {
1144
+ // Register Matter accessories
1145
+ api.matter.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, accessories)
1146
+ } else {
1147
+ log.info('Matter is not enabled for this bridge')
1148
+ }
1149
+ ```
1139
1150
 
1140
- /**
1141
- * Called when user turns light OFF via Home app
1142
- */
1143
- off: async () => {
1144
- // Control your physical device
1145
- await myLightAPI.turnOff()
1146
- // State automatically updated by Homebridge
1147
- },
1148
- },
1151
+ **When to use:**
1152
+ - Runtime checks before registering Matter accessories
1153
+ - Conditional accessory registration
1154
+ - User feedback about Matter status
1155
+
1156
+ ---
1157
+
1158
+ ### Matter API Properties
1159
+
1160
+ All properties are accessed via `api.matter.*`
1161
+
1162
+ #### `api.matter.uuid`
1163
+
1164
+ UUID generator for creating unique accessory identifiers (alias of `api.hap.uuid`).
1165
+
1166
+ **Type:** `HAP['uuid']`
1167
+
1168
+ **Methods:**
1169
+ - `generate(data: string): string` - Generate deterministic UUID from string
1170
+ - `isValid(uuid: string): boolean` - Validate UUID format
1171
+
1172
+ **Usage:**
1173
+ ```typescript
1174
+ const uuid = api.matter.uuid.generate('my-light-123')
1175
+ // Output: 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX'
1176
+
1177
+ if (api.matter.uuid.isValid(uuid)) {
1178
+ // UUID is valid
1149
1179
  }
1150
1180
  ```
1151
1181
 
1152
- #### Optional Clusters
1182
+ **Important:**
1183
+ - UUIDs must be deterministic (same input = same output)
1184
+ - Use unique identifiers (device ID, MAC address, etc.)
1185
+ - UUIDs persist across restarts for state restoration
1186
+
1187
+ ---
1188
+
1189
+ #### `api.matter.deviceTypes`
1190
+
1191
+ Available Matter device types for creating accessories.
1153
1192
 
1154
- - **LevelControl**: Adds brightness control (see Dimmable Light)
1155
- - **ScenesManagement**: Enables scene support
1156
- - **Groups**: Enables grouping with other devices
1157
- - **OccupancySensing**: Can respond to occupancy sensors
1193
+ **Type:** `typeof deviceTypes` (from Matter.js)
1158
1194
 
1159
- #### Complete Example
1195
+ **Common Device Types:**
1196
+ - Lighting: `OnOffLight`, `DimmableLight`, `ColorTemperatureLight`, `ExtendedColorLight`
1197
+ - Switches & Outlets: `OnOffSwitch`, `OnOffOutlet`, `DimmableOutlet`
1198
+ - Sensors: `ContactSensor`, `TemperatureSensor`, `HumiditySensor`, `OccupancySensor`, etc.
1199
+ - HVAC: `Thermostat`, `Fan`
1200
+ - Closure: `DoorLock`, `WindowCovering`
1201
+ - Robotic: `RoboticVacuumCleaner`
1160
1202
 
1203
+ **Usage:**
1161
1204
  ```typescript
1162
1205
  const accessory = {
1163
- uuid: api.matter.uuid.generate('onoff-light-001'),
1164
- displayName: 'On/Off Light',
1165
- deviceType: api.matter.deviceTypes.OnOffLight,
1166
- serialNumber: 'LIGHT-001',
1167
- manufacturer: 'My Company',
1168
- model: 'OnOffLight v1',
1206
+ uuid: api.matter.uuid.generate('my-light'),
1207
+ displayName: 'Living Room Light',
1208
+ deviceType: api.matter.deviceTypes.DimmableLight,
1209
+ // ...
1210
+ }
1211
+ ```
1169
1212
 
1170
- clusters: {
1171
- onOff: {
1172
- onOff: false, // Initial state: off
1173
- },
1174
- },
1213
+ **See:** [Available Device Types](#available-device-types) for complete list
1175
1214
 
1176
- handlers: {
1177
- onOff: {
1178
- on: async () => {
1179
- log.info('[Light] Turning ON')
1180
- await myLightAPI.turnOn()
1181
- },
1182
- off: async () => {
1183
- log.info('[Light] Turning OFF')
1184
- await myLightAPI.turnOff()
1185
- },
1186
- },
1187
- },
1215
+ ---
1216
+
1217
+ #### `api.matter.clusters`
1218
+
1219
+ Direct access to Matter.js cluster definitions for advanced use cases.
1220
+
1221
+ **Type:** `typeof clusters` (from Matter.js)
1222
+
1223
+ **Usage:**
1224
+ ```typescript
1225
+ // Access cluster attributes programmatically
1226
+ const onOffAttrs = api.matter.clusters.OnOffCluster.attributes
1227
+ console.log(Object.keys(onOffAttrs))
1228
+ // Output: ['onOff', 'clusterRevision', 'featureMap', ...]
1229
+
1230
+ // Check if cluster supports specific features
1231
+ const levelControlFeatures = api.matter.clusters.LevelControlCluster.features
1232
+ ```
1233
+
1234
+ **When to use:**
1235
+ - Advanced cluster introspection
1236
+ - Dynamic attribute discovery
1237
+ - Custom cluster implementations
1238
+
1239
+ **Note:** Most plugins should use the higher-level APIs instead.
1240
+
1241
+ ---
1242
+
1243
+ #### `api.matter.clusterNames`
1244
+
1245
+ Cluster name constants for type safety and autocomplete with state methods.
1246
+
1247
+ **Type:** `typeof clusterNames`
1248
+
1249
+ **Available Names:**
1250
+ - `OnOff`, `LevelControl`, `ColorControl`
1251
+ - `DoorLock`, `WindowCovering`
1252
+ - `Thermostat`, `FanControl`
1253
+ - `TemperatureMeasurement`, `RelativeHumidityMeasurement`
1254
+ - And many more...
1255
+
1256
+ **Usage:**
1257
+ ```typescript
1258
+ // Type-safe cluster references
1259
+ api.matter.updateAccessoryState(
1260
+ uuid,
1261
+ api.matter.clusterNames.OnOff, // Autocomplete available!
1262
+ { onOff: true }
1263
+ )
1264
+
1265
+ const state = api.matter.getAccessoryState(
1266
+ uuid,
1267
+ api.matter.clusterNames.LevelControl
1268
+ )
1269
+ ```
1270
+
1271
+ **Benefits:**
1272
+ - Autocomplete in IDEs
1273
+ - Compile-time error checking
1274
+ - Prevents typos in cluster names
1275
+
1276
+ ---
1277
+
1278
+ #### `api.matter.types`
1279
+
1280
+ Type-safe enum values for cluster attributes (modes, states, etc.).
1281
+
1282
+ **Type:** `typeof MatterTypes` (from Homebridge)
1283
+
1284
+ **Common Types:**
1285
+ - `DoorLock.LockState` - Lock states (Locked, Unlocked, etc.)
1286
+ - `DoorLock.LockType` - Lock types (DeadBolt, Magnetic, etc.)
1287
+ - `FanControl.FanMode` - Fan modes (Off, Low, Medium, High, Auto, etc.)
1288
+ - `FanControl.FanModeSequence` - Supported mode sequences
1289
+ - `Thermostat.SystemMode` - HVAC modes (Off, Heat, Cool, Auto, etc.)
1290
+ - `ColorControl.ColorMode` - Color modes (HS, XY, ColorTemperature)
1291
+ - `RvcRunMode.ModeTag` - Vacuum run mode tags (Idle, Cleaning, Mapping)
1292
+ - `RvcCleanMode.ModeTag` - Vacuum clean mode tags (Vacuum, Mop)
1293
+ - `RvcOperationalState.OperationalState` - Vacuum states (Stopped, Running, Docked, etc.)
1294
+
1295
+ **Usage:**
1296
+ ```typescript
1297
+ // Door lock states
1298
+ clusters: {
1299
+ doorLock: {
1300
+ lockState: api.matter.types.DoorLock.LockState.Unlocked,
1301
+ lockType: api.matter.types.DoorLock.LockType.DeadBolt
1302
+ }
1188
1303
  }
1189
1304
 
1190
- // Monitor external changes (Flow B)
1191
- mqttClient.on('message', (topic, message) => {
1192
- const { state } = JSON.parse(message.toString())
1193
- const deviceIsOn = state === 'ON'
1305
+ // Fan modes
1306
+ clusters: {
1307
+ fanControl: {
1308
+ fanMode: api.matter.types.FanControl.FanMode.Auto,
1309
+ fanModeSequence: api.matter.types.FanControl.FanModeSequence.OffLowMedHigh
1310
+ }
1311
+ }
1194
1312
 
1195
- if (deviceIsOn !== accessory.clusters.onOff.onOff) {
1196
- api.matter.updateAccessoryState(
1197
- accessory.uuid,
1198
- api.matter.clusterNames.OnOff,
1199
- { onOff: deviceIsOn }
1200
- )
1313
+ // Color modes
1314
+ clusters: {
1315
+ colorControl: {
1316
+ colorMode: api.matter.types.ColorControl.ColorMode.ColorTemperatureMireds
1201
1317
  }
1202
- })
1318
+ }
1203
1319
  ```
1204
1320
 
1205
- #### Cluster Reference
1321
+ **Benefits:**
1322
+ - Type safety prevents invalid values
1323
+ - IDE autocomplete shows available options
1324
+ - Self-documenting code
1325
+ - Compile-time validation
1326
+
1327
+ **See:** [Using Matter Types](#using-matter-types) for detailed examples
1328
+
1329
+ ---
1330
+
1331
+ ### Matter API Methods
1332
+
1333
+ #### `api.matter.registerPlatformAccessories()`
1206
1334
 
1207
- Access cluster attributes programmatically:
1335
+ Register Matter accessories with the platform (standard registration method).
1208
1336
 
1337
+ **Signature:**
1209
1338
  ```typescript
1210
- // Reading state
1211
- const isOn = accessory.clusters.onOff.onOff
1339
+ registerPlatformAccessories(
1340
+ pluginIdentifier: string,
1341
+ platformName: string,
1342
+ accessories: MatterAccessory[]
1343
+ ): void
1344
+ ```
1212
1345
 
1213
- // All OnOff cluster attributes via api.matter
1214
- const onOffAttrs = api.matter.clusters.OnOffCluster.attributes
1215
- console.log(Object.keys(onOffAttrs))
1216
- // Output: ['onOff', 'clusterRevision', 'featureMap', ...]
1346
+ **Parameters:**
1347
+ - `pluginIdentifier` - Plugin identifier (e.g., `'homebridge-example'`)
1348
+ - `platformName` - Platform name (e.g., `'ExamplePlatform'`)
1349
+ - `accessories` - Array of Matter accessories to register
1350
+
1351
+ **Usage:**
1352
+ ```typescript
1353
+ const PLUGIN_NAME = 'homebridge-example'
1354
+ const PLATFORM_NAME = 'ExamplePlatform'
1355
+
1356
+ const accessories = [
1357
+ {
1358
+ uuid: api.matter.uuid.generate('my-light'),
1359
+ displayName: 'Living Room Light',
1360
+ deviceType: api.matter.deviceTypes.OnOffLight,
1361
+ // ...
1362
+ }
1363
+ ]
1364
+
1365
+ api.matter.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, accessories)
1366
+ ```
1367
+
1368
+ **When to use:**
1369
+ - Standard accessory registration
1370
+ - Multiple accessories on shared bridge
1371
+ - Most common use case
1372
+
1373
+ **See also:** `publishExternalAccessories()` for isolated accessories
1374
+
1375
+ ---
1376
+
1377
+ #### `api.matter.unregisterPlatformAccessories()`
1378
+
1379
+ Unregister Matter accessories by UUID.
1380
+
1381
+ **Signature:**
1382
+ ```typescript
1383
+ unregisterPlatformAccessories(
1384
+ pluginIdentifier: string,
1385
+ platformName: string,
1386
+ accessories: MatterAccessory[]
1387
+ ): void
1388
+ ```
1389
+
1390
+ **Parameters:**
1391
+ - `pluginIdentifier` - Plugin identifier
1392
+ - `platformName` - Platform name
1393
+ - `accessories` - Array of accessories to unregister (only `uuid` is required)
1394
+
1395
+ **Usage:**
1396
+ ```typescript
1397
+ // Unregister accessories
1398
+ const accessoriesToRemove = [
1399
+ { uuid: 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX' }
1400
+ ]
1401
+
1402
+ api.matter.unregisterPlatformAccessories(
1403
+ PLUGIN_NAME,
1404
+ PLATFORM_NAME,
1405
+ accessoriesToRemove
1406
+ )
1407
+ ```
1408
+
1409
+ **When to use:**
1410
+ - Removing accessories from Homebridge
1411
+ - Cleanup during plugin shutdown
1412
+ - User-initiated accessory removal
1413
+
1414
+ ---
1415
+
1416
+ #### `api.matter.publishExternalAccessories()`
1417
+
1418
+ Publish accessories on dedicated Matter bridges (isolated from other accessories).
1419
+
1420
+ **Signature:**
1421
+ ```typescript
1422
+ publishExternalAccessories(
1423
+ pluginIdentifier: string,
1424
+ accessories: MatterAccessory[]
1425
+ ): void
1426
+ ```
1427
+
1428
+ **Parameters:**
1429
+ - `pluginIdentifier` - Plugin identifier
1430
+ - `accessories` - Array of accessories to publish externally
1431
+
1432
+ **Usage:**
1433
+ ```typescript
1434
+ const accessories = [
1435
+ {
1436
+ uuid: api.matter.uuid.generate('robot-vacuum'),
1437
+ displayName: 'Robot Vacuum',
1438
+ deviceType: api.matter.deviceTypes.RoboticVacuumCleaner,
1439
+ // ...
1440
+ }
1441
+ ]
1442
+
1443
+ // Publish on dedicated bridge
1444
+ api.matter.publishExternalAccessories(PLUGIN_NAME, accessories)
1445
+ ```
1446
+
1447
+ **When to use:**
1448
+ - Robotic Vacuum Cleaners (required by Apple Home)
1449
+ - Cameras and video doorbells
1450
+ - Devices requiring isolation
1451
+ - Testing single accessories
1452
+
1453
+ **Behavior:**
1454
+ - Each accessory gets its own Matter server instance
1455
+ - Separate port allocation (e.g., 5541, 5542, etc.)
1456
+ - Independent QR codes for commissioning
1457
+ - Complete isolation from other accessories
1458
+
1459
+ **Similar to:** HAP's `api.publishExternalAccessories()`
1460
+
1461
+ ---
1462
+
1463
+ #### `api.matter.updateAccessoryState()`
1464
+
1465
+ Update accessory cluster state when device changes externally (Flow B).
1466
+
1467
+ **Signature:**
1468
+ ```typescript
1469
+ updateAccessoryState(
1470
+ uuid: string,
1471
+ cluster: string,
1472
+ attributes: Record<string, any>
1473
+ ): void
1474
+ ```
1475
+
1476
+ **Parameters:**
1477
+ - `uuid` - Accessory UUID
1478
+ - `cluster` - Cluster name (use `api.matter.clusterNames.*`)
1479
+ - `attributes` - Attributes to update (key-value pairs)
1480
+
1481
+ **Usage:**
1482
+ ```typescript
1483
+ // Device turned on via native app
1484
+ api.matter.updateAccessoryState(
1485
+ uuid,
1486
+ api.matter.clusterNames.OnOff,
1487
+ { onOff: true }
1488
+ )
1489
+
1490
+ // Brightness changed via physical button
1491
+ api.matter.updateAccessoryState(
1492
+ uuid,
1493
+ api.matter.clusterNames.LevelControl,
1494
+ { currentLevel: 200 }
1495
+ )
1496
+
1497
+ // Update multiple attributes at once
1498
+ api.matter.updateAccessoryState(
1499
+ uuid,
1500
+ api.matter.clusterNames.ColorControl,
1501
+ {
1502
+ colorMode: api.matter.types.ColorControl.ColorMode.ColorTemperatureMireds,
1503
+ colorTemperatureMireds: 250
1504
+ }
1505
+ )
1506
+ ```
1507
+
1508
+ **IMPORTANT:**
1509
+ - ❌ **DO NOT** use inside handlers (state updates automatically)
1510
+ - ✅ **DO** use for external changes (webhooks, polling, events)
1511
+
1512
+ **When to use:**
1513
+ - Native app controls
1514
+ - Physical button presses
1515
+ - Webhook notifications
1516
+ - Polling results
1517
+ - MQTT/WebSocket messages
1518
+
1519
+ **See:** [Flow B: Physical Device → Home App](#flow-b-physical-device--home-app-manual)
1520
+
1521
+ ---
1522
+
1523
+ #### `api.matter.getAccessoryState()`
1524
+
1525
+ Get current cluster state from a Matter accessory.
1526
+
1527
+ **Signature:**
1528
+ ```typescript
1529
+ getAccessoryState(
1530
+ uuid: string,
1531
+ cluster: string
1532
+ ): Record<string, any> | undefined
1533
+ ```
1534
+
1535
+ **Parameters:**
1536
+ - `uuid` - Accessory UUID
1537
+ - `cluster` - Cluster name (use `api.matter.clusterNames.*`)
1538
+
1539
+ **Returns:**
1540
+ - Object with current attribute values, or `undefined` if not found
1541
+
1542
+ **Usage:**
1543
+ ```typescript
1544
+ // Read OnOff state
1545
+ const state = api.matter.getAccessoryState(uuid, api.matter.clusterNames.OnOff)
1546
+ if (state?.onOff) {
1547
+ log.info('Light is currently on')
1548
+ }
1549
+
1550
+ // Read level control state
1551
+ const levelState = api.matter.getAccessoryState(
1552
+ uuid,
1553
+ api.matter.clusterNames.LevelControl
1554
+ )
1555
+ log.info(`Current brightness: ${levelState?.currentLevel}`)
1556
+
1557
+ // Check color mode
1558
+ const colorState = api.matter.getAccessoryState(
1559
+ uuid,
1560
+ api.matter.clusterNames.ColorControl
1561
+ )
1562
+ if (colorState?.colorMode === api.matter.types.ColorControl.ColorMode.ColorTemperatureMireds) {
1563
+ log.info(`Color temp: ${colorState.colorTemperatureMireds} mireds`)
1564
+ }
1217
1565
  ```
1218
1566
 
1567
+ **When to use:**
1568
+ - Reading state after plugin restart
1569
+ - Verifying current state before changes
1570
+ - Debugging and logging
1571
+ - Conditional logic based on state
1572
+
1573
+ **Note:** State is persisted across restarts automatically.
1574
+
1219
1575
  ---
1220
1576
 
1221
1577
  ## Additional Resources
@@ -1304,3 +1660,544 @@ const matterTemp = Math.round(celsius * 100)
1304
1660
  // From Matter
1305
1661
  const celsius = matterTemp / 100
1306
1662
  ```
1663
+
1664
+ ---
1665
+
1666
+ ## Device Reference
1667
+
1668
+ This section documents all available Matter device types with their clusters, attributes, handlers, and usage examples.
1669
+
1670
+ ### On/Off Light
1671
+
1672
+ | Property | Value |
1673
+ |--------------------------|--------------------------------------------------------|
1674
+ | **Device Type** | `api.matter.deviceTypes.OnOffLight` |
1675
+ | **Description** | A lighting device capable of being switched on or off. |
1676
+ | **Matter Specification** | § 4.1 |
1677
+
1678
+ #### Required Clusters
1679
+
1680
+ ###### `OnOff` Cluster
1681
+
1682
+ Controls the power state of the light.
1683
+
1684
+ **Attributes**:
1685
+
1686
+ ```typescript
1687
+ // All OnOff cluster attributes via api.matter
1688
+ const onOffAttrs = api.matter.clusters.OnOffCluster.attributes
1689
+ console.log(Object.keys(onOffAttrs))
1690
+ // Output: ['onOff', 'clusterRevision', 'featureMap', ...]
1691
+ ```
1692
+
1693
+ | Attribute | Type | Range/Values | Description |
1694
+ |-----------|---------|-----------------|----------------------------------|
1695
+ | `onOff` | boolean | `true`, `false` | Power state (true=on, false=off) |
1696
+
1697
+ **Reading State**:
1698
+
1699
+ ```typescript
1700
+ const isOn = accessory.clusters.onOff.onOff
1701
+ ```
1702
+
1703
+ <details>
1704
+ <summary><strong>Handlers</strong></summary>
1705
+
1706
+ ```typescript
1707
+ handlers: {
1708
+ onOff: {
1709
+ /**
1710
+ * Called when user turns light ON via Home app
1711
+ */
1712
+ on: async () => {
1713
+ // Control your physical device
1714
+ await myLightAPI.turnOn()
1715
+ // State automatically updated by Homebridge
1716
+ },
1717
+
1718
+ /**
1719
+ * Called when user turns light OFF via Home app
1720
+ */
1721
+ off: async () => {
1722
+ // Control your physical device
1723
+ await myLightAPI.turnOff()
1724
+ // State automatically updated by Homebridge
1725
+ },
1726
+ },
1727
+ }
1728
+ ```
1729
+
1730
+ </details>
1731
+
1732
+ ### Dimmable Light
1733
+
1734
+ | Property | Value |
1735
+ |--------------------------|--------------------------------------------------------|
1736
+ | **Device Type** | `api.matter.deviceTypes.DimmableLight` |
1737
+ | **Description** | A lighting device with on/off and brightness control. |
1738
+ | **Matter Specification** | § 4.2 |
1739
+
1740
+ #### Required Clusters
1741
+
1742
+ ###### `OnOff` Cluster
1743
+
1744
+ Controls the power state of the light.
1745
+
1746
+ **Attributes**:
1747
+
1748
+ | Attribute | Type | Range/Values | Description |
1749
+ |-----------|---------|-----------------|----------------------------------|
1750
+ | `onOff` | boolean | `true`, `false` | Power state (true=on, false=off) |
1751
+
1752
+ **Reading State**:
1753
+
1754
+ ```typescript
1755
+ const isOn = accessory.clusters.onOff.onOff
1756
+ ```
1757
+
1758
+ ###### `LevelControl` Cluster
1759
+
1760
+ Controls the brightness level of the light.
1761
+
1762
+ **Attributes**:
1763
+
1764
+ ```typescript
1765
+ // All LevelControl cluster attributes via api.matter
1766
+ const levelAttrs = api.matter.clusters.LevelControlCluster.attributes
1767
+ console.log(Object.keys(levelAttrs))
1768
+ // Output: ['currentLevel', 'minLevel', 'maxLevel', 'onLevel', 'options', ...]
1769
+ ```
1770
+
1771
+ | Attribute | Type | Range/Values | Description |
1772
+ |----------------|--------|--------------|--------------------------------------------------|
1773
+ | `currentLevel` | number | 1-254 | Current brightness (1 = 0.4%, 254 = 100%) |
1774
+ | `minLevel` | number | 1-254 | Minimum brightness level |
1775
+ | `maxLevel` | number | 1-254 | Maximum brightness level |
1776
+ | `onLevel` | number | 0-254 | Brightness when turned on (0 = restore previous) |
1777
+
1778
+ **Reading State**:
1779
+
1780
+ ```typescript
1781
+ const level = accessory.clusters.levelControl.currentLevel
1782
+ const brightnessPercent = Math.round((level / 254) * 100)
1783
+ ```
1784
+
1785
+ <details>
1786
+ <summary><strong>Handlers</strong></summary>
1787
+
1788
+ ```typescript
1789
+ handlers: {
1790
+ onOff: {
1791
+ on: async () => {
1792
+ log.info('[Dimmable Light] Turning ON')
1793
+ await myLightAPI.turnOn()
1794
+ },
1795
+
1796
+ off: async () => {
1797
+ log.info('[Dimmable Light] Turning OFF')
1798
+ await myLightAPI.turnOff()
1799
+ },
1800
+ },
1801
+
1802
+ levelControl: {
1803
+ /**
1804
+ * Called when user adjusts brightness via Home app
1805
+ * Also called when turning on with specific brightness
1806
+ */
1807
+ moveToLevelWithOnOff: async (request: MatterRequests.MoveToLevel) => {
1808
+ const { level, transitionTime } = request
1809
+ const brightnessPercent = Math.round((level / 254) * 100)
1810
+
1811
+ log.info(`[Dimmable Light] Setting brightness to ${brightnessPercent}%`)
1812
+ await myLightAPI.setBrightness(brightnessPercent, transitionTime)
1813
+ },
1814
+ },
1815
+ }
1816
+ ```
1817
+
1818
+ </details>
1819
+
1820
+ ---
1821
+
1822
+ ### Color Temperature Light
1823
+
1824
+ | Property | Value |
1825
+ |--------------------------|---------------------------------------------------------------------------|
1826
+ | **Device Type** | `api.matter.deviceTypes.ColorTemperatureLight` |
1827
+ | **Description** | A lighting device with on/off, brightness, and color temperature control. |
1828
+ | **Matter Specification** | § 4.3 |
1829
+
1830
+ #### Required Clusters
1831
+
1832
+ ###### `OnOff` Cluster
1833
+
1834
+ Controls the power state of the light.
1835
+
1836
+ **Attributes**:
1837
+
1838
+ | Attribute | Type | Range/Values | Description |
1839
+ |-----------|---------|-----------------|----------------------------------|
1840
+ | `onOff` | boolean | `true`, `false` | Power state (true=on, false=off) |
1841
+
1842
+ ###### `LevelControl` Cluster
1843
+
1844
+ Controls the brightness level of the light.
1845
+
1846
+ **Attributes**:
1847
+
1848
+ | Attribute | Type | Range/Values | Description |
1849
+ |----------------|--------|--------------|--------------------------------------------------|
1850
+ | `currentLevel` | number | 1-254 | Current brightness (1 = 0.4%, 254 = 100%) |
1851
+ | `minLevel` | number | 1-254 | Minimum brightness level |
1852
+ | `maxLevel` | number | 1-254 | Maximum brightness level |
1853
+
1854
+ ###### `ColorControl` Cluster
1855
+
1856
+ Controls the color temperature of the light.
1857
+
1858
+ **Attributes**:
1859
+
1860
+ ```typescript
1861
+ // All ColorControl cluster attributes via api.matter
1862
+ const colorAttrs = api.matter.clusters.ColorControlCluster.attributes
1863
+ console.log(Object.keys(colorAttrs))
1864
+ ```
1865
+
1866
+ | Attribute | Type | Range/Values | Description |
1867
+ |---------------------------------|--------|--------------|-------------------------------------------------------|
1868
+ | `colorMode` | number | 0-2 | Current color mode (2 = Color Temperature) |
1869
+ | `colorTemperatureMireds` | number | 147-454 | Color temp in mireds (reciprocal megakelvin) |
1870
+ | `colorTempPhysicalMinMireds` | number | 147-500 | Coolest temperature supported (e.g., 147 = ~6800K) |
1871
+ | `colorTempPhysicalMaxMireds` | number | 147-500 | Warmest temperature supported (e.g., 454 = ~2200K) |
1872
+
1873
+ **Reading State**:
1874
+
1875
+ ```typescript
1876
+ const mireds = accessory.clusters.colorControl.colorTemperatureMireds
1877
+ const kelvin = Math.round(1000000 / mireds)
1878
+ ```
1879
+
1880
+ **Value Conversions**:
1881
+
1882
+ ```typescript
1883
+ // Kelvin to Mireds
1884
+ const mireds = Math.round(1000000 / kelvin)
1885
+
1886
+ // Mireds to Kelvin
1887
+ const kelvin = Math.round(1000000 / mireds)
1888
+ ```
1889
+
1890
+ <details>
1891
+ <summary><strong>Handlers</strong></summary>
1892
+
1893
+ ```typescript
1894
+ handlers: {
1895
+ onOff: {
1896
+ on: async () => {
1897
+ log.info('[CCT Light] Turning ON')
1898
+ await myLightAPI.turnOn()
1899
+ },
1900
+
1901
+ off: async () => {
1902
+ log.info('[CCT Light] Turning OFF')
1903
+ await myLightAPI.turnOff()
1904
+ },
1905
+ },
1906
+
1907
+ levelControl: {
1908
+ moveToLevelWithOnOff: async (request: MatterRequests.MoveToLevel) => {
1909
+ const { level } = request
1910
+ const brightnessPercent = Math.round((level / 254) * 100)
1911
+
1912
+ log.info(`[CCT Light] Setting brightness to ${brightnessPercent}%`)
1913
+ await myLightAPI.setBrightness(brightnessPercent)
1914
+ },
1915
+ },
1916
+
1917
+ colorControl: {
1918
+ /**
1919
+ * Called when user adjusts color temperature via Home app
1920
+ */
1921
+ moveToColorTemperatureLogic: async (request: { targetMireds: number, transitionTime: number }) => {
1922
+ const { targetMireds, transitionTime } = request
1923
+ const kelvin = Math.round(1000000 / targetMireds)
1924
+
1925
+ log.info(`[CCT Light] Setting color temp to ${kelvin}K (${targetMireds} mireds)`)
1926
+ await myLightAPI.setColorTemperature(kelvin, transitionTime)
1927
+ },
1928
+ },
1929
+ }
1930
+ ```
1931
+
1932
+ </details>
1933
+
1934
+ ---
1935
+
1936
+ ### Color Light
1937
+
1938
+ | Property | Value |
1939
+ |--------------------------|--------------------------------------------------------------------------------|
1940
+ | **Device Type** | `api.matter.deviceTypes.ExtendedColorLight` |
1941
+ | **Description** | A lighting device with on/off, brightness, and color (Hue/Saturation) control. |
1942
+ | **Matter Specification** | § 4.4 |
1943
+
1944
+ #### Required Clusters
1945
+
1946
+ ###### `OnOff` Cluster
1947
+
1948
+ Controls the power state of the light.
1949
+
1950
+ **Attributes**:
1951
+
1952
+ | Attribute | Type | Range/Values | Description |
1953
+ |-----------|---------|-----------------|----------------------------------|
1954
+ | `onOff` | boolean | `true`, `false` | Power state (true=on, false=off) |
1955
+
1956
+ ###### `LevelControl` Cluster
1957
+
1958
+ Controls the brightness level of the light.
1959
+
1960
+ **Attributes**:
1961
+
1962
+ | Attribute | Type | Range/Values | Description |
1963
+ |----------------|--------|--------------|--------------------------------------------------|
1964
+ | `currentLevel` | number | 1-254 | Current brightness (1 = 0.4%, 254 = 100%) |
1965
+ | `minLevel` | number | 1-254 | Minimum brightness level |
1966
+ | `maxLevel` | number | 1-254 | Maximum brightness level |
1967
+
1968
+ ###### `ColorControl` Cluster
1969
+
1970
+ Controls the color (Hue/Saturation or XY) of the light.
1971
+
1972
+ **Attributes**:
1973
+
1974
+ | Attribute | Type | Range/Values | Description |
1975
+ |--------------------|--------|--------------|-------------------------------------------------------|
1976
+ | `colorMode` | number | 0-2 | Current color mode (0 = HS, 1 = XY) |
1977
+ | `currentHue` | number | 0-254 | Current hue (maps to 0-360 degrees) |
1978
+ | `currentSaturation`| number | 0-254 | Current saturation (maps to 0-100%) |
1979
+ | `currentX` | number | 0-65535 | CIE 1931 x coordinate |
1980
+ | `currentY` | number | 0-65535 | CIE 1931 y coordinate |
1981
+
1982
+ **Reading State**:
1983
+
1984
+ ```typescript
1985
+ const hue = accessory.clusters.colorControl.currentHue
1986
+ const saturation = accessory.clusters.colorControl.currentSaturation
1987
+
1988
+ // Convert to degrees/percentage
1989
+ const hueDegrees = Math.round((hue / 254) * 360)
1990
+ const saturationPercent = Math.round((saturation / 254) * 100)
1991
+ ```
1992
+
1993
+ **Value Conversions**:
1994
+
1995
+ ```typescript
1996
+ // Hue: Degrees (0-360) to Matter (0-254)
1997
+ const matterHue = Math.round((degrees / 360) * 254)
1998
+ const degrees = Math.round((matterHue / 254) * 360)
1999
+
2000
+ // Saturation: Percent (0-100) to Matter (0-254)
2001
+ const matterSat = Math.round((percent / 100) * 254)
2002
+ const percent = Math.round((matterSat / 254) * 100)
2003
+
2004
+ // XY: Float (0.0-1.0) to Matter (0-65535)
2005
+ const matterX = Math.round(floatX * 65535)
2006
+ const floatX = matterX / 65535
2007
+ ```
2008
+
2009
+ <details>
2010
+ <summary><strong>Handlers</strong></summary>
2011
+
2012
+ ```typescript
2013
+ handlers: {
2014
+ onOff: {
2015
+ on: async () => {
2016
+ log.info('[Color Light] Turning ON')
2017
+ await myLightAPI.turnOn()
2018
+ },
2019
+
2020
+ off: async () => {
2021
+ log.info('[Color Light] Turning OFF')
2022
+ await myLightAPI.turnOff()
2023
+ },
2024
+ },
2025
+
2026
+ levelControl: {
2027
+ moveToLevelWithOnOff: async (request: MatterRequests.MoveToLevel) => {
2028
+ const { level } = request
2029
+ const brightnessPercent = Math.round((level / 254) * 100)
2030
+
2031
+ log.info(`[Color Light] Setting brightness to ${brightnessPercent}%`)
2032
+ await myLightAPI.setBrightness(brightnessPercent)
2033
+ },
2034
+ },
2035
+
2036
+ colorControl: {
2037
+ /**
2038
+ * Called when user adjusts color via XY coordinates in Home app
2039
+ */
2040
+ moveToColorLogic: async (request: { targetX: number, targetY: number, transitionTime: number }) => {
2041
+ const { targetX, targetY, transitionTime } = request
2042
+ const xFloat = (targetX / 65535).toFixed(4)
2043
+ const yFloat = (targetY / 65535).toFixed(4)
2044
+
2045
+ log.info(`[Color Light] Setting XY color to (${xFloat}, ${yFloat})`)
2046
+ await myLightAPI.setColorXY(xFloat, yFloat, transitionTime)
2047
+ },
2048
+
2049
+ /**
2050
+ * Called when user adjusts color via Hue/Saturation in Home app
2051
+ */
2052
+ moveToHueAndSaturationLogic: async (request: { targetHue: number, targetSaturation: number, transitionTime: number }) => {
2053
+ const { targetHue, targetSaturation, transitionTime } = request
2054
+ const hueDegrees = Math.round((targetHue / 254) * 360)
2055
+ const saturationPercent = Math.round((targetSaturation / 254) * 100)
2056
+
2057
+ log.info(`[Color Light] Setting color to ${hueDegrees}°, ${saturationPercent}%`)
2058
+ await myLightAPI.setColorHS(hueDegrees, saturationPercent, transitionTime)
2059
+ },
2060
+ },
2061
+ }
2062
+ ```
2063
+
2064
+ </details>
2065
+
2066
+ ---
2067
+
2068
+ ### Extended Color Light
2069
+
2070
+ | Property | Value |
2071
+ |--------------------------|---------------------------------------------------------------------------------------------------|
2072
+ | **Device Type** | `api.matter.deviceTypes.ExtendedColorLight` |
2073
+ | **Description** | A lighting device with on/off, brightness, color (Hue/Saturation), and color temperature control. |
2074
+ | **Matter Specification** | § 4.4 |
2075
+
2076
+ #### Required Clusters
2077
+
2078
+ ###### `OnOff` Cluster
2079
+
2080
+ Controls the power state of the light.
2081
+
2082
+ **Attributes**:
2083
+
2084
+ | Attribute | Type | Range/Values | Description |
2085
+ |-----------|---------|-----------------|----------------------------------|
2086
+ | `onOff` | boolean | `true`, `false` | Power state (true=on, false=off) |
2087
+
2088
+ ###### `LevelControl` Cluster
2089
+
2090
+ Controls the brightness level of the light.
2091
+
2092
+ **Attributes**:
2093
+
2094
+ | Attribute | Type | Range/Values | Description |
2095
+ |----------------|--------|--------------|--------------------------------------------------|
2096
+ | `currentLevel` | number | 1-254 | Current brightness (1 = 0.4%, 254 = 100%) |
2097
+ | `minLevel` | number | 1-254 | Minimum brightness level |
2098
+ | `maxLevel` | number | 1-254 | Maximum brightness level |
2099
+
2100
+ ###### `ColorControl` Cluster
2101
+
2102
+ Controls both color (Hue/Saturation or XY) and color temperature of the light.
2103
+
2104
+ When updating state for Extended Color Light (Flow B), always update the `colorMode` attribute along with the color/temperature values to indicate which mode is active.
2105
+
2106
+ **Attributes**:
2107
+
2108
+ | Attribute | Type | Range/Values | Description |
2109
+ |---------------------------------|--------|--------------|-------------------------------------------------------|
2110
+ | `colorMode` | number | 0-2 | Current color mode (0 = HS, 1 = XY, 2 = ColorTemp) |
2111
+ | `currentHue` | number | 0-254 | Current hue (maps to 0-360 degrees) |
2112
+ | `currentSaturation` | number | 0-254 | Current saturation (maps to 0-100%) |
2113
+ | `currentX` | number | 0-65535 | CIE 1931 x coordinate |
2114
+ | `currentY` | number | 0-65535 | CIE 1931 y coordinate |
2115
+ | `colorTemperatureMireds` | number | 147-454 | Color temp in mireds (when in ColorTemp mode) |
2116
+ | `colorTempPhysicalMinMireds` | number | 147-500 | Coolest temperature supported |
2117
+ | `colorTempPhysicalMaxMireds` | number | 147-500 | Warmest temperature supported |
2118
+
2119
+ **Reading State**:
2120
+
2121
+ ```typescript
2122
+ // Check current mode
2123
+ const mode = accessory.clusters.colorControl.colorMode
2124
+ const ColorMode = api.matter.types.ColorControl.ColorMode
2125
+
2126
+ if (mode === ColorMode.CurrentHueAndCurrentSaturation || mode === ColorMode.CurrentXAndCurrentY) {
2127
+ // Light is in color mode
2128
+ const hue = accessory.clusters.colorControl.currentHue
2129
+ const sat = accessory.clusters.colorControl.currentSaturation
2130
+ } else if (mode === ColorMode.ColorTemperatureMireds) {
2131
+ // Light is in white/CCT mode
2132
+ const mireds = accessory.clusters.colorControl.colorTemperatureMireds
2133
+ const kelvin = Math.round(1000000 / mireds)
2134
+ }
2135
+ ```
2136
+
2137
+ <details>
2138
+ <summary><strong>Handlers</strong></summary>
2139
+
2140
+ ```typescript
2141
+ handlers: {
2142
+ onOff: {
2143
+ on: async () => {
2144
+ log.info('[Extended Color Light] Turning ON')
2145
+ await myLightAPI.turnOn()
2146
+ },
2147
+
2148
+ off: async () => {
2149
+ log.info('[Extended Color Light] Turning OFF')
2150
+ await myLightAPI.turnOff()
2151
+ },
2152
+ },
2153
+
2154
+ levelControl: {
2155
+ moveToLevelWithOnOff: async (request: MatterRequests.MoveToLevel) => {
2156
+ const { level } = request
2157
+ const brightnessPercent = Math.round((level / 254) * 100)
2158
+
2159
+ log.info(`[Extended Color Light] Setting brightness to ${brightnessPercent}%`)
2160
+ await myLightAPI.setBrightness(brightnessPercent)
2161
+ },
2162
+ },
2163
+
2164
+ colorControl: {
2165
+ /**
2166
+ * Called when user adjusts color via XY coordinates in Home app
2167
+ */
2168
+ moveToColorLogic: async (request: { targetX: number, targetY: number, transitionTime: number }) => {
2169
+ const { targetX, targetY, transitionTime } = request
2170
+ const xFloat = (targetX / 65535).toFixed(4)
2171
+ const yFloat = (targetY / 65535).toFixed(4)
2172
+
2173
+ log.info(`[Extended Color Light] Setting XY color to (${xFloat}, ${yFloat})`)
2174
+ await myLightAPI.setColorXY(xFloat, yFloat, transitionTime)
2175
+ },
2176
+
2177
+ /**
2178
+ * Called when user adjusts color via Hue/Saturation in Home app
2179
+ */
2180
+ moveToHueAndSaturationLogic: async (request: { targetHue: number, targetSaturation: number, transitionTime: number }) => {
2181
+ const { targetHue, targetSaturation, transitionTime } = request
2182
+ const hueDegrees = Math.round((targetHue / 254) * 360)
2183
+ const saturationPercent = Math.round((targetSaturation / 254) * 100)
2184
+
2185
+ log.info(`[Extended Color Light] Setting color to ${hueDegrees}°, ${saturationPercent}%`)
2186
+ await myLightAPI.setColorHS(hueDegrees, saturationPercent, transitionTime)
2187
+ },
2188
+
2189
+ /**
2190
+ * Called when user adjusts color temperature via Home app
2191
+ */
2192
+ moveToColorTemperatureLogic: async (request: { targetMireds: number, transitionTime: number }) => {
2193
+ const { targetMireds, transitionTime } = request
2194
+ const kelvin = Math.round(1000000 / targetMireds)
2195
+
2196
+ log.info(`[Extended Color Light] Setting color temp to ${kelvin}K (${targetMireds} mireds)`)
2197
+ await myLightAPI.setColorTemperature(kelvin, transitionTime)
2198
+ },
2199
+ },
2200
+ }
2201
+ ```
2202
+
2203
+ </details>
package/README.md CHANGED
@@ -68,7 +68,7 @@ This plugin provides example implementations of Matter device types in Homebridg
68
68
 
69
69
  - To use this plugin, you will need to already have:
70
70
  - [Node](https://nodejs.org): latest version of `v20`, `v22` or `v24` - any other major version is not supported.
71
- - [Homebridge](https://homebridge.io): `>=2.0.0-alpha.63 <2.0.0-beta.0` - refer to link for more information and installation instructions.
71
+ - [Homebridge](https://homebridge.io): `>=2.0.0-alpha.64 <2.0.0-beta.0` - refer to link for more information and installation instructions.
72
72
 
73
73
  ### Help/About
74
74
 
@@ -9,7 +9,7 @@
9
9
  * - Switch device implementation (input device, sends commands)
10
10
  */
11
11
  export function registerOnOffLightSwitch(context) {
12
- const { api, config } = context;
12
+ const { api, log, config } = context;
13
13
  const accessories = [];
14
14
  if (!config.enableOnOffSwitch) {
15
15
  return accessories;
@@ -22,12 +22,21 @@ export function registerOnOffLightSwitch(context) {
22
22
  manufacturer: 'Matter Examples',
23
23
  model: 'OnOffSwitch v1',
24
24
  clusters: {
25
- // Switches are input devices - they send commands rather than expose state
26
- // The switch cluster configuration depends on the specific implementation
25
+ onOff: {
26
+ onOff: false,
27
+ },
27
28
  },
28
29
  handlers: {
29
- // Switch handlers depend on the specific switch implementation
30
- // Typically, switches trigger events rather than respond to commands
30
+ onOff: {
31
+ on: async () => {
32
+ log.info('[On/Off Switch] Turning ON');
33
+ // TODO: await mySwitchAPI.turnOn()
34
+ },
35
+ off: async () => {
36
+ log.info('[On/Off Switch] Turning OFF');
37
+ // TODO: await mySwitchAPI.turnOff()
38
+ },
39
+ },
31
40
  },
32
41
  });
33
42
  return accessories;
@@ -1 +1 @@
1
- {"version":3,"file":"on-off-light-switch.js","sourceRoot":"","sources":["../../../src/devices/section-6-switches/on-off-light-switch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,MAAM,UAAU,wBAAwB,CAAC,OAAsB;IAC7D,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAA;IAC/B,MAAM,WAAW,GAAU,EAAE,CAAA;IAE7B,IAAI,CAAC,MAAM,CAAC,iBAAiB,EAAE,CAAC;QAC9B,OAAO,WAAW,CAAA;IACpB,CAAC;IAED,WAAW,CAAC,IAAI,CAAC;QACf,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,qBAAqB,CAAC;QACrD,WAAW,EAAE,eAAe;QAC5B,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,WAAW;QAC9C,YAAY,EAAE,YAAY;QAC1B,YAAY,EAAE,iBAAiB;QAC/B,KAAK,EAAE,gBAAgB;QAEvB,QAAQ,EAAE;QACR,2EAA2E;QAC3E,0EAA0E;SAC3E;QAED,QAAQ,EAAE;QACR,+DAA+D;QAC/D,qEAAqE;SACtE;KACF,CAAC,CAAA;IAEF,OAAO,WAAW,CAAA;AACpB,CAAC"}
1
+ {"version":3,"file":"on-off-light-switch.js","sourceRoot":"","sources":["../../../src/devices/section-6-switches/on-off-light-switch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,MAAM,UAAU,wBAAwB,CAAC,OAAsB;IAC7D,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAA;IACpC,MAAM,WAAW,GAAU,EAAE,CAAA;IAE7B,IAAI,CAAC,MAAM,CAAC,iBAAiB,EAAE,CAAC;QAC9B,OAAO,WAAW,CAAA;IACpB,CAAC;IAED,WAAW,CAAC,IAAI,CAAC;QACf,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,qBAAqB,CAAC;QACrD,WAAW,EAAE,eAAe;QAC5B,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,WAAW;QAC9C,YAAY,EAAE,YAAY;QAC1B,YAAY,EAAE,iBAAiB;QAC/B,KAAK,EAAE,gBAAgB;QAEvB,QAAQ,EAAE;YACR,KAAK,EAAE;gBACL,KAAK,EAAE,KAAK;aACb;SACF;QAED,QAAQ,EAAE;YACR,KAAK,EAAE;gBACL,EAAE,EAAE,KAAK,IAAI,EAAE;oBACb,GAAG,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAA;oBACtC,mCAAmC;gBACrC,CAAC;gBAED,GAAG,EAAE,KAAK,IAAI,EAAE;oBACd,GAAG,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAA;oBACvC,oCAAoC;gBACtC,CAAC;aACF;SACF;KACF,CAAC,CAAA;IAEF,OAAO,WAAW,CAAA;AACpB,CAAC"}
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "displayName": "Homebridge Matter",
4
4
  "alias": "Matter",
5
5
  "type": "module",
6
- "version": "0.1.4-beta.0",
6
+ "version": "0.1.4",
7
7
  "description": "Homebridge plugin to showcase examples of Matter devices in Homebridge.",
8
8
  "author": {
9
9
  "name": "bwp91",
@@ -49,7 +49,7 @@
49
49
  "main": "dist/index.js",
50
50
  "engines": {
51
51
  "node": "^20.18.0 || ^22.10.0 || ^24.0.0",
52
- "homebridge": ">=2.0.0-alpha.63 <2.0.0-beta.0"
52
+ "homebridge": ">=2.0.0-alpha.64 <2.0.0-beta.0"
53
53
  },
54
54
  "scripts": {
55
55
  "build": "rimraf ./dist && tsc && npm run plugin-ui",
@@ -65,7 +65,7 @@
65
65
  "devDependencies": {
66
66
  "@antfu/eslint-config": "^6.0.0",
67
67
  "@types/node": "^24.9.1",
68
- "homebridge": "2.0.0-alpha.63",
68
+ "homebridge": "2.0.0-alpha.64",
69
69
  "rimraf": "^6.0.1",
70
70
  "ts-node": "^10.9.2",
71
71
  "typescript": "^5.9.3"