matterbridge-homey 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,28 @@ All notable changes to this project will be documented in this file.
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [0.4.0] - 2026-10-28
8
+
9
+ ### Changed
10
+
11
+ - [platform]: The `newDevices` setting replaces `exposeNewDevices` of 0.3.0: new Homey devices can be added to the white list or the black list automatically, also the devices added while Matterbridge was stopped. The default applies the lists as they are and exposes new devices right away.
12
+ - [build]: The plugin is published to npm by a GitHub workflow when a GitHub release is created.
13
+ - [test]: The tests use the test utilities of Matterbridge 3.11 (`matterbridge/test-utils`).
14
+
15
+ ### Fixed
16
+
17
+ - [devices]: Plugs have the Lighting feature of the OnOff cluster, and smoke and CO alarms without a battery have a wired power source, as Matter 1.4 requires. Matterbridge 3.11 warned about both.
18
+
19
+ ## [0.3.0] - 2026-10-28
20
+
21
+ ### Added
22
+
23
+ - [platform]: Devices added to Homey are exposed right away, without a Matterbridge restart. The new `exposeNewDevices` setting (default on) turns this off.
24
+
25
+ ### Fixed
26
+
27
+ - [platform]: Homey device changes are applied one at a time, so a device that changes while the plugin starts or adds it isn't registered twice.
28
+
7
29
  ## [0.2.0] - 2026-10-18
8
30
 
9
31
  ### Added
package/README.md CHANGED
@@ -25,19 +25,20 @@ The key is shown only once, so copy it right away.
25
25
 
26
26
  ## Configuration
27
27
 
28
- | Setting | Description |
29
- | --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
30
- | `address` | Local address of the Homey, e.g. `http://192.168.1.50`. `https://192-168-1-50.homey.homeylocal.com` also works, unless your router blocks DNS rebinding. |
31
- | `token` | The API key. |
32
- | `whiteList` | Only these devices are exposed (names or Homey device IDs). Empty exposes all supported devices. The frontend offers a device picker after the first start. |
33
- | `blackList` | These devices are never exposed. |
34
- | `zoneWhiteList` | Only devices in these Homey zones are exposed, including sub-zones. Empty exposes all zones. |
35
- | `lightList` | These devices are exposed as lights, whatever their Homey class. |
36
- | `outletList` | These devices are exposed as plugs, whatever their Homey class. |
37
- | `capabilityBlackList` | These Homey capabilities are never exposed, e.g. `meter_power`. |
38
- | `deviceCapabilityBlackList` | Capabilities not exposed for one device: the device name (or ID) and its list of capabilities, e.g. `{ "Multisensor": ["alarm_occupancy"] }`. |
39
- | `debug` | Log the homey-api debug output. |
40
- | `unregisterOnShutdown` | Remove all devices from the controllers on shutdown. For development only. |
28
+ | Setting | Description |
29
+ | --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
30
+ | `address` | Local address of the Homey, e.g. `http://192.168.1.50`. `https://192-168-1-50.homey.homeylocal.com` also works, unless your router blocks DNS rebinding. |
31
+ | `token` | The API key. |
32
+ | `whiteList` | Only these devices are exposed (names or Homey device IDs). Empty exposes all supported devices. The frontend offers a device picker after the first start. |
33
+ | `blackList` | These devices are never exposed. |
34
+ | `zoneWhiteList` | Only devices in these Homey zones are exposed, including sub-zones. Empty exposes all zones. |
35
+ | `lightList` | These devices are exposed as lights, whatever their Homey class. |
36
+ | `outletList` | These devices are exposed as plugs, whatever their Homey class. |
37
+ | `capabilityBlackList` | These Homey capabilities are never exposed, e.g. `meter_power`. |
38
+ | `deviceCapabilityBlackList` | Capabilities not exposed for one device: the device name (or ID) and its list of capabilities, e.g. `{ "Multisensor": ["alarm_occupancy"] }`. |
39
+ | `newDevices` | What happens to devices added to Homey, also while Matterbridge is stopped: `default` applies the lists as they are, `whiteList` adds them to the white list (when it isn't empty), `blackList` adds them to the black list. |
40
+ | `debug` | Log the homey-api debug output. |
41
+ | `unregisterOnShutdown` | Remove all devices from the controllers on shutdown. For development only. |
41
42
 
42
43
  ## Supported devices
43
44
 
@@ -113,7 +114,8 @@ The white and black lists accept Homey device IDs as well as names. Entries by n
113
114
 
114
115
  ### Limitations
115
116
 
116
- - New Homey devices need a Matterbridge restart; the frontend asks for it. Deleted devices are removed right away.
117
+ - New Homey devices are exposed right away, unless the lists or `newDevices` keep them out, and deleted devices are removed right away. `newDevices` adds a device to a list by its name: like the other entries by name, it stops matching when the device is renamed.
118
+ - A new device is exposed with the capabilities Homey reports for it. Capabilities that its app adds later appear after a restart.
117
119
  - Devices with the same name get their zone appended, e.g. `Ceiling light Kitchen`.
118
120
  - Not supported yet: buttons and remotes, media players and TVs (only their `onoff`), window covering tilt, plant moisture, `level_aqi`.
119
121
 
@@ -137,7 +139,16 @@ Uploading a newer tarball replaces the installed version. Test builds are marked
137
139
 
138
140
  ## Development
139
141
 
140
- The plugin follows the [Matterbridge plugin template](https://github.com/Luligu/matterbridge-plugin-template). Matterbridge must never be a dependency of the plugin: link a global or locally built Matterbridge with `npm link matterbridge` (see the [development guide](https://matterbridge.io/README-DEV.html)).
142
+ The plugin follows the [Matterbridge plugin template](https://github.com/Luligu/matterbridge-plugin-template). Matterbridge must never be a dependency of the plugin: clone and build Matterbridge next to the plugin and link it, like the CI does (see the [development guide](https://matterbridge.io/README-DEV.html)):
143
+
144
+ ```bash
145
+ git clone --depth 1 --single-branch --no-tags https://github.com/Luligu/matterbridge.git ../matterbridge
146
+ (cd ../matterbridge && npm install && npm run build && npm link)
147
+ npm install
148
+ npm run link
149
+ ```
150
+
151
+ A Matterbridge installed with `npm install -g matterbridge` builds the plugin, but the tests and the typecheck fail: its test utilities need Vitest, which only a clone installs. Pull and rebuild the clone to update it. The tests need Matterbridge 3.11 or later.
141
152
 
142
153
  | Script | Purpose |
143
154
  | ----------------------- | ------------------------------- |
@@ -158,6 +169,16 @@ Source layout:
158
169
 
159
170
  The tests run the platform against a Matter server node with a fake Homey. `vitest/homey.real.test.ts` runs it against your own Homey, read-only (every write is refused): put `HOMEY_ADDRESS`, `HOMEY_TOKEN` and `HOMEY_REAL_TEST=1` in `.env` (ignored by git) and run `npm run test -- vitest/homey.real.test.ts`.
160
171
 
172
+ ### Publishing
173
+
174
+ The [Publish to npm](.github/workflows/publish.yml) workflow publishes the plugin when a GitHub release is created: it builds Matterbridge, runs the build, typecheck, lint and tests, and publishes with [npm trusted publishing](https://docs.npmjs.com/trusted-publishers), so neither an npm login nor a local Matterbridge is needed.
175
+
176
+ 1. `npm version minor --no-git-tag-version --ignore-scripts` (or `patch`), and move the `[Unreleased]` changes in `CHANGELOG.md` under the new version and date.
177
+ 2. Commit and push.
178
+ 3. `node scripts/create-release.mjs`: creates the GitHub release from the changelog (needs the [GitHub CLI](https://cli.github.com)), which starts the workflow.
179
+
180
+ Once, before the first release from the workflow: on npmjs.com, add the trusted publisher in the settings of the package (GitHub Actions, repository `stefan-schweiger/matterbridge-homey`, workflow `publish.yml`).
181
+
161
182
  ## License
162
183
 
163
184
  Apache-2.0
package/dist/features.js CHANGED
@@ -1,4 +1,4 @@
1
- import { airQualitySensor, colorTemperatureLight, contactSensor, dimmableLight, dimmablePlugInUnit, doorLock, electricalSensor, extendedColorLight, fan, humiditySensor, lightSensor, occupancySensor, onOffLight, onOffPlugInUnit, pressureSensor, rainSensor, roboticVacuumCleaner, smokeCoAlarm, temperatureSensor, thermostat, waterLeakDetector, windowCovering, } from 'matterbridge';
1
+ import { airQualitySensor, colorTemperatureLight, contactSensor, dimmableLight, dimmablePlugInUnit, doorLock, electricalSensor, extendedColorLight, fan, humiditySensor, lightSensor, occupancySensor, onOffLight, onOffPlugInUnit, powerSource, pressureSensor, rainSensor, roboticVacuumCleaner, smokeCoAlarm, temperatureSensor, thermostat, waterLeakDetector, windowCovering, } from 'matterbridge';
2
2
  import { MatterbridgeRvcCleanModeServer, MatterbridgeRvcOperationalStateServer, MatterbridgeRvcRunModeServer } from 'matterbridge/devices';
3
3
  import { AirQuality, BooleanState, CarbonDioxideConcentrationMeasurement, CarbonMonoxideConcentrationMeasurement, ColorControl, DoorLock, ElectricalEnergyMeasurement, ElectricalPowerMeasurement, FanControl, IlluminanceMeasurement, LevelControl, OccupancySensing, OnOff, Pm10ConcentrationMeasurement, Pm25ConcentrationMeasurement, PressureMeasurement, RelativeHumidityMeasurement, RvcCleanMode, RvcOperationalState, RvcRunMode, SmokeCoAlarm, TemperatureMeasurement, Thermostat, TotalVolatileOrganicCompoundsConcentrationMeasurement, WindowCovering, } from 'matterbridge/matter/clusters';
4
4
  import { kelvinToRGB, miredToKelvin, rgbColorToHslColor, xyToHsl } from 'matterbridge/utils';
@@ -119,7 +119,7 @@ function lightFeature(device) {
119
119
  deviceTypes: [deviceType],
120
120
  clusters,
121
121
  build: (context) => {
122
- buildOnOff(context, 'onoff', true);
122
+ buildOnOff(context, 'onoff');
123
123
  if (clusters.includes('LevelControl'))
124
124
  buildLevelControl(context);
125
125
  if (hasHueSaturation)
@@ -137,19 +137,16 @@ function plugFeature(device, capabilityId) {
137
137
  deviceTypes: [isDimmable ? dimmablePlugInUnit : onOffPlugInUnit],
138
138
  clusters: isDimmable ? ['OnOff', 'LevelControl'] : ['OnOff'],
139
139
  build: (context) => {
140
- buildOnOff(context, capabilityId, isDimmable);
140
+ buildOnOff(context, capabilityId);
141
141
  if (isDimmable)
142
142
  buildLevelControl(context);
143
143
  },
144
144
  };
145
145
  }
146
- function buildOnOff(context, capabilityId, isLighting) {
146
+ function buildOnOff(context, capabilityId) {
147
147
  const { device, endpoint } = context;
148
148
  const isOn = context.value(capabilityId) === true;
149
- if (isLighting)
150
- endpoint.createDefaultOnOffClusterServer(isOn);
151
- else
152
- endpoint.createOnOffClusterServer(isOn);
149
+ endpoint.createDefaultOnOffClusterServer(isOn);
153
150
  if (hasCapability(device, capabilityId)) {
154
151
  endpoint.addCommandHandler('on', () => context.set(capabilityId, true));
155
152
  endpoint.addCommandHandler('off', () => context.set(capabilityId, false));
@@ -578,18 +575,17 @@ function vacuumFeature(device) {
578
575
  else if (request.newMode === vacuumIdleMode)
579
576
  stop('stopped', true);
580
577
  });
578
+ const isInState = (state, ...states) => states.includes(state);
581
579
  endpoint.addCommandHandler('RvcOperationalState.pause', ({ attributes }) => {
582
- if (attributes.operationalState === OperationalState.Running || attributes.operationalState === OperationalState.SeekingCharger)
580
+ if (isInState(attributes.operationalState, OperationalState.Running, OperationalState.SeekingCharger))
583
581
  stop('stopped', false);
584
582
  });
585
583
  endpoint.addCommandHandler('RvcOperationalState.resume', ({ attributes }) => {
586
- if (attributes.operationalState === OperationalState.Paused)
584
+ if (isInState(attributes.operationalState, OperationalState.Paused))
587
585
  start();
588
586
  });
589
587
  endpoint.addCommandHandler('RvcOperationalState.goHome', ({ attributes }) => {
590
- if (attributes.operationalState === OperationalState.Stopped ||
591
- attributes.operationalState === OperationalState.Running ||
592
- attributes.operationalState === OperationalState.Paused)
588
+ if (isInState(attributes.operationalState, OperationalState.Stopped, OperationalState.Running, OperationalState.Paused))
593
589
  stop('docked', true);
594
590
  });
595
591
  if (cleanModeIds.length > 0) {
@@ -719,11 +715,12 @@ function booleanStateFeature(capabilityId, deviceType, toState) {
719
715
  function smokeCoAlarmFeature(device) {
720
716
  const hasSmoke = hasCapability(device, 'alarm_smoke');
721
717
  const hasCo = hasCapability(device, 'alarm_co');
718
+ const hasBattery = hasCapability(device, 'measure_battery') || hasCapability(device, 'alarm_battery');
722
719
  const alarmState = (value) => (value === true ? SmokeCoAlarm.AlarmState.Critical : SmokeCoAlarm.AlarmState.Normal);
723
720
  return {
724
721
  name: 'smokecoalarm',
725
722
  capabilities: ['alarm_smoke', 'alarm_co'],
726
- deviceTypes: [smokeCoAlarm],
723
+ deviceTypes: [smokeCoAlarm, powerSource],
727
724
  clusters: ['SmokeCoAlarm'],
728
725
  build: (context) => {
729
726
  const { endpoint } = context;
@@ -733,6 +730,8 @@ function smokeCoAlarmFeature(device) {
733
730
  endpoint.createSmokeOnlySmokeCOAlarmClusterServer(alarmState(context.value('alarm_smoke')));
734
731
  else
735
732
  endpoint.createCoOnlySmokeCOAlarmClusterServer(alarmState(context.value('alarm_co')));
733
+ if (!hasBattery)
734
+ endpoint.createDefaultPowerSourceWiredClusterServer();
736
735
  if (hasSmoke) {
737
736
  context.bind('alarm_smoke', async (value) => {
738
737
  await endpoint.updateAttribute(SmokeCoAlarm, 'smokeState', alarmState(value), endpoint.log);
package/dist/module.js CHANGED
@@ -54,6 +54,10 @@ export class HomeyPlatform extends MatterbridgeDynamicPlatform {
54
54
  homey;
55
55
  bridgedDevices = new Map();
56
56
  zones = [];
57
+ newDeviceIds = new Set();
58
+ knownDeviceIds = new Set();
59
+ areDevicesConfigured = false;
60
+ deviceChanges = Promise.resolve();
57
61
  constructor(matterbridge, log, config, homey) {
58
62
  super(matterbridge, log, config);
59
63
  this.config = config;
@@ -73,20 +77,20 @@ export class HomeyPlatform extends MatterbridgeDynamicPlatform {
73
77
  this.config.outletList = isValidArray(config.outletList) ? config.outletList : [];
74
78
  this.config.capabilityBlackList = isValidArray(config.capabilityBlackList) ? config.capabilityBlackList : [];
75
79
  this.config.deviceCapabilityBlackList = isValidObject(config.deviceCapabilityBlackList) ? config.deviceCapabilityBlackList : {};
80
+ this.config.newDevices = config.newDevices === 'whiteList' || config.newDevices === 'blackList' ? config.newDevices : 'default';
76
81
  this.config.debug ??= false;
77
82
  this.config.unregisterOnShutdown ??= false;
78
83
  this.homey =
79
84
  homey ?? new HomeyApiConnection(config.address, config.token, 15000, config.debug ? (message) => this.log.debug(`[homey-api] ${message}`) : undefined);
80
85
  this.homey.on('device.create', (device) => {
81
- this.log.notice(`New Homey device ${CYAN}${device.name}${nf}: restart Matterbridge to expose it`);
82
- if (this.isConfigured)
83
- this.wssSendRestartRequired();
86
+ this.log.notice(`New Homey device ${CYAN}${device.name}${nf}`);
87
+ fireAndForget(this.serialize(async () => this.addNewDevice(device)), this.log, `addition of ${device.name}`);
84
88
  });
85
89
  this.homey.on('device.update', (device) => {
86
- fireAndForget(this.updateDevice(device), this.log, `update of ${device.name}`);
90
+ fireAndForget(this.serialize(async () => this.updateDevice(device)), this.log, `update of ${device.name}`);
87
91
  });
88
92
  this.homey.on('device.delete', (device) => {
89
- fireAndForget(this.removeDevice(device.id), this.log, `removal of ${device.id}`);
93
+ fireAndForget(this.serialize(async () => this.removeDevice(device.id)), this.log, `removal of ${device.id}`);
90
94
  });
91
95
  this.homey.on('disconnected', () => {
92
96
  this.log.warn('Disconnected from Homey');
@@ -113,22 +117,30 @@ export class HomeyPlatform extends MatterbridgeDynamicPlatform {
113
117
  throw new Error(`Unable to connect to Homey at ${this.config.address}: ${getErrorMessage(error)}`, { cause: error });
114
118
  }
115
119
  this.log.notice(`Connected to Homey ${CYAN}${this.homey.homeyId ?? ''}${nf}`);
116
- const [devices, zones] = await Promise.all([this.homey.getDevices(), this.homey.getZones()]);
117
- this.zones = zones;
118
- this.log.info(`Found ${CYAN}${devices.length}${nf} devices in ${CYAN}${zones.length}${nf} zones`);
119
- const names = getUniqueDeviceNames(devices, zones);
120
- for (const device of devices.toSorted((a, b) => a.name.localeCompare(b.name))) {
121
- await this.addDevice(device, names.get(device.id) ?? device.name, zones);
122
- }
120
+ await this.serialize(async () => {
121
+ const [devices, zones] = await Promise.all([this.homey.getDevices(), this.homey.getZones()]);
122
+ this.zones = zones;
123
+ this.log.info(`Found ${CYAN}${devices.length}${nf} devices in ${CYAN}${zones.length}${nf} zones`);
124
+ const names = getUniqueDeviceNames(devices, zones);
125
+ const knownDeviceIds = await this.context?.get('knownDeviceIds');
126
+ for (const device of devices.toSorted((a, b) => a.name.localeCompare(b.name))) {
127
+ await this.addDevice(device, names.get(device.id) ?? device.name, zones, knownDeviceIds?.includes(device.id) === false);
128
+ this.knownDeviceIds.add(device.id);
129
+ }
130
+ await this.saveKnownDevices();
131
+ });
123
132
  this.log.info(`Started platform ${idn}${this.config.name}${rs}${nf} with ${CYAN}${this.bridgedDevices.size}${nf} devices`);
124
133
  }
125
134
  async onConfigure() {
126
135
  await super.onConfigure();
127
136
  this.log.info(`Configuring platform ${idn}${this.config.name}${rs}${nf}...`);
128
- for (const bridgedDevice of this.bridgedDevices.values()) {
129
- await bridgedDevice.applyAll();
130
- bridgedDevice.subscribe();
131
- }
137
+ await this.serialize(async () => {
138
+ for (const bridgedDevice of this.bridgedDevices.values()) {
139
+ await bridgedDevice.applyAll();
140
+ bridgedDevice.subscribe();
141
+ }
142
+ this.areDevicesConfigured = true;
143
+ });
132
144
  this.log.info(`Configured platform ${idn}${this.config.name}${rs}${nf}`);
133
145
  }
134
146
  async onChangeLoggerLevel(logLevel) {
@@ -156,7 +168,7 @@ export class HomeyPlatform extends MatterbridgeDynamicPlatform {
156
168
  this.bridgedDevices.clear();
157
169
  this.log.info(`Shut down platform ${idn}${this.config.name}${rs}${nf}`);
158
170
  }
159
- async addDevice(device, name, zones) {
171
+ async addDevice(device, name, zones, isNew = false) {
160
172
  const serial = getSerialNumber(device.id);
161
173
  const keys = [name, device.name, device.id, serial];
162
174
  const isListed = (list) => keys.some((key) => list.includes(key));
@@ -176,6 +188,8 @@ export class HomeyPlatform extends MatterbridgeDynamicPlatform {
176
188
  for (const entity of entities)
177
189
  this.setSelectEntity(entity.name, entity.description, 'component');
178
190
  this.setSelectDevice(serial, name, configUrl, 'hub', entities);
191
+ if (isNew)
192
+ this.listNewDevice(keys);
179
193
  if (!this.validateDevice(keys))
180
194
  return;
181
195
  const excludedCapabilities = new Set([...this.config.capabilityBlackList, ...keys.flatMap((key) => this.config.deviceCapabilityBlackList[key] ?? [])]);
@@ -203,10 +217,37 @@ export class HomeyPlatform extends MatterbridgeDynamicPlatform {
203
217
  inspectError(this.log, `Failed to register device ${name}`, error);
204
218
  }
205
219
  }
220
+ async addNewDevice(device) {
221
+ if (this.bridgedDevices.has(device.id))
222
+ return;
223
+ if (!this.knownDeviceIds.has(device.id)) {
224
+ this.knownDeviceIds.add(device.id);
225
+ await this.saveKnownDevices();
226
+ }
227
+ const [devices, zones] = await Promise.all([this.homey.getDevices(), this.homey.getZones()]);
228
+ this.zones = zones;
229
+ const names = getUniqueDeviceNames([...devices.filter((other) => other.id !== device.id), device], zones);
230
+ for (const [deviceId, bridged] of this.bridgedDevices)
231
+ await bridged.setName(names.get(deviceId) ?? bridged.device.name);
232
+ await this.addDevice(device, names.get(device.id) ?? device.name, zones, true);
233
+ const bridgedDevice = this.bridgedDevices.get(device.id);
234
+ if (!bridgedDevice) {
235
+ this.newDeviceIds.add(device.id);
236
+ return;
237
+ }
238
+ this.newDeviceIds.delete(device.id);
239
+ if (!this.areDevicesConfigured)
240
+ return;
241
+ await bridgedDevice.applyAll();
242
+ bridgedDevice.subscribe();
243
+ }
206
244
  async updateDevice(device) {
207
245
  const bridgedDevice = this.bridgedDevices.get(device.id);
208
- if (!bridgedDevice)
246
+ if (!bridgedDevice) {
247
+ if (this.newDeviceIds.has(device.id))
248
+ await this.addNewDevice(device);
209
249
  return;
250
+ }
210
251
  const isRenamed = device.name !== bridgedDevice.homeyName;
211
252
  await bridgedDevice.update(device);
212
253
  if (!isRenamed)
@@ -216,6 +257,9 @@ export class HomeyPlatform extends MatterbridgeDynamicPlatform {
216
257
  await bridged.setName(names.get(deviceId) ?? bridged.device.name);
217
258
  }
218
259
  async removeDevice(deviceId) {
260
+ this.newDeviceIds.delete(deviceId);
261
+ if (this.knownDeviceIds.delete(deviceId))
262
+ await this.saveKnownDevices();
219
263
  const bridgedDevice = this.bridgedDevices.get(deviceId);
220
264
  if (!bridgedDevice)
221
265
  return;
@@ -224,4 +268,24 @@ export class HomeyPlatform extends MatterbridgeDynamicPlatform {
224
268
  this.bridgedDevices.delete(deviceId);
225
269
  await this.unregisterDevice(bridgedDevice.endpoint);
226
270
  }
271
+ listNewDevice(keys) {
272
+ const listName = this.config.newDevices;
273
+ if (listName === 'default' || (listName === 'whiteList' && this.config.whiteList.length === 0))
274
+ return;
275
+ const list = this.config[listName];
276
+ if (keys.some((key) => list.includes(key)))
277
+ return;
278
+ list.push(keys[0]);
279
+ this.log.notice(`Added the new device ${CYAN}${keys[0]}${nf} to the ${listName === 'whiteList' ? 'white' : 'black'} list`);
280
+ this.saveConfig(this.config);
281
+ }
282
+ async saveKnownDevices() {
283
+ await this.context?.set('knownDeviceIds', [...this.knownDeviceIds]);
284
+ }
285
+ async serialize(change) {
286
+ const result = this.deviceChanges.then(change);
287
+ this.deviceChanges = result.catch(() => {
288
+ });
289
+ await result;
290
+ }
227
291
  }
@@ -10,6 +10,7 @@
10
10
  "outletList": [],
11
11
  "capabilityBlackList": [],
12
12
  "deviceCapabilityBlackList": {},
13
+ "newDevices": "default",
13
14
  "debug": false,
14
15
  "unregisterOnShutdown": false
15
16
  }
@@ -104,6 +104,13 @@
104
104
  "selectDeviceEntityFrom": "name"
105
105
  }
106
106
  },
107
+ "newDevices": {
108
+ "title": "New Devices",
109
+ "description": "What happens to the devices added to Homey, also while Matterbridge is stopped. default: the lists apply as they are, so with an empty white list new devices are exposed right away. whiteList: new devices are added to the white list, so they are exposed (only when the white list isn't empty). blackList: new devices are added to the black list, so they aren't exposed until you remove them from it.",
110
+ "type": "string",
111
+ "enum": ["default", "whiteList", "blackList"],
112
+ "default": "default"
113
+ },
107
114
  "debug": {
108
115
  "title": "Enable Debug",
109
116
  "description": "Enable debug mode for the plugin. Only for debugging purposes, not recommended for production use.",
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "matterbridge-homey",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "matterbridge-homey",
9
- "version": "0.2.0",
9
+ "version": "0.4.0",
10
10
  "license": "Apache-2.0",
11
11
  "dependencies": {
12
12
  "homey-api": "3.20.0"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "matterbridge-homey",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "Matterbridge plugin that exposes Athom Homey Pro devices to Matter",
5
5
  "author": "Stefan Schweiger",
6
6
  "license": "Apache-2.0",