@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. [
|
|
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
|
|
176
|
-
MatterRequests.Move
|
|
177
|
-
MatterRequests.Step
|
|
178
|
-
MatterRequests.Stop
|
|
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
|
|
184
|
-
MatterRequests.MoveToSaturation
|
|
185
|
-
MatterRequests.MoveToHueAndSaturation
|
|
186
|
-
MatterRequests.MoveToColorTemperature
|
|
187
|
-
MatterRequests.MoveHue
|
|
188
|
-
MatterRequests.MoveSaturation
|
|
189
|
-
MatterRequests.MoveColorTemperature
|
|
190
|
-
MatterRequests.StepHue
|
|
191
|
-
MatterRequests.StepSaturation
|
|
192
|
-
MatterRequests.StepColorTemperature
|
|
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
|
|
198
|
-
MatterRequests.UnlockDoor
|
|
198
|
+
MatterRequests.LockDoor // { pinCode? }
|
|
199
|
+
MatterRequests.UnlockDoor // { pinCode? }
|
|
199
200
|
```
|
|
200
201
|
|
|
201
202
|
#### Window Covering
|
|
202
203
|
```typescript
|
|
203
|
-
MatterRequests.GoToLiftPercentage
|
|
204
|
-
MatterRequests.GoToTiltPercentage
|
|
204
|
+
MatterRequests.GoToLiftPercentage // { liftPercent100thsValue }
|
|
205
|
+
MatterRequests.GoToTiltPercentage // { tiltPercent100thsValue }
|
|
205
206
|
```
|
|
206
207
|
|
|
207
208
|
#### Thermostat
|
|
208
209
|
```typescript
|
|
209
|
-
MatterRequests.SetpointRaiseLower
|
|
210
|
+
MatterRequests.SetpointRaiseLower // { mode, amount }
|
|
210
211
|
```
|
|
211
212
|
|
|
212
213
|
#### Fan Control
|
|
213
214
|
```typescript
|
|
214
|
-
MatterRequests.FanStep
|
|
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 },
|
|
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
|
|
585
|
+
const isOn = accessory.clusters.onOff.onOff // boolean
|
|
585
586
|
|
|
586
587
|
// Read brightness
|
|
587
|
-
const level = accessory.clusters.levelControl.currentLevel
|
|
588
|
-
const percent = Math.round((level / 254) * 100)
|
|
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
|
|
592
|
-
const saturation = accessory.clusters.colorControl.currentSaturation
|
|
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
|
|
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
|
|
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,
|
|
636
|
-
api.matter.clusterNames.OnOff,
|
|
637
|
-
{ onOff: true }
|
|
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)
|
|
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
|
-
##
|
|
1103
|
+
## API Reference
|
|
1103
1104
|
|
|
1104
|
-
|
|
1105
|
+
Complete reference for all Matter API methods and properties available in Homebridge.
|
|
1105
1106
|
|
|
1106
|
-
###
|
|
1107
|
+
### Platform API Methods
|
|
1107
1108
|
|
|
1108
|
-
|
|
1109
|
+
#### `api.isMatterAvailable(): boolean`
|
|
1109
1110
|
|
|
1110
|
-
|
|
1111
|
+
Check if Matter is available in the current version of Homebridge.
|
|
1111
1112
|
|
|
1112
|
-
**
|
|
1113
|
+
**Returns:** `true` if Homebridge version is >= 2.0.0-alpha.0
|
|
1113
1114
|
|
|
1114
|
-
|
|
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
|
-
|
|
1124
|
+
**When to use:**
|
|
1125
|
+
- Plugin compatibility checks
|
|
1126
|
+
- Conditional feature loading
|
|
1127
|
+
- Version-specific functionality
|
|
1117
1128
|
|
|
1118
|
-
|
|
1129
|
+
---
|
|
1119
1130
|
|
|
1120
|
-
|
|
1131
|
+
#### `api.isMatterEnabled(): boolean`
|
|
1121
1132
|
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
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
|
-
**
|
|
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
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
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
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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('
|
|
1164
|
-
displayName: '
|
|
1165
|
-
deviceType: api.matter.deviceTypes.
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
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
|
-
|
|
1171
|
-
onOff: {
|
|
1172
|
-
onOff: false, // Initial state: off
|
|
1173
|
-
},
|
|
1174
|
-
},
|
|
1213
|
+
**See:** [Available Device Types](#available-device-types) for complete list
|
|
1175
1214
|
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
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
|
-
//
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
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
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1335
|
+
Register Matter accessories with the platform (standard registration method).
|
|
1208
1336
|
|
|
1337
|
+
**Signature:**
|
|
1209
1338
|
```typescript
|
|
1210
|
-
|
|
1211
|
-
|
|
1339
|
+
registerPlatformAccessories(
|
|
1340
|
+
pluginIdentifier: string,
|
|
1341
|
+
platformName: string,
|
|
1342
|
+
accessories: MatterAccessory[]
|
|
1343
|
+
): void
|
|
1344
|
+
```
|
|
1212
1345
|
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
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.
|
|
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
|
-
|
|
26
|
-
|
|
25
|
+
onOff: {
|
|
26
|
+
onOff: false,
|
|
27
|
+
},
|
|
27
28
|
},
|
|
28
29
|
handlers: {
|
|
29
|
-
|
|
30
|
-
|
|
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;
|
|
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
|
|
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.
|
|
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.
|
|
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"
|