@switchbot/homebridge-switchbot 5.0.0-beta.134 → 5.0.0-beta.135
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/config.schema.json +0 -11
- package/dist/deviceFactory.d.ts +3 -1
- package/dist/deviceFactory.d.ts.map +1 -1
- package/dist/deviceFactory.js +3 -18
- package/dist/deviceFactory.js.map +1 -1
- package/dist/devices/genericDevice.d.ts +1 -1
- package/dist/devices/genericDevice.d.ts.map +1 -1
- package/dist/devices/genericDevice.js +79 -159
- package/dist/devices/genericDevice.js.map +1 -1
- package/dist/homebridge-ui/public/index.html +107 -124
- package/dist/homebridge-ui/public/js/api.d.ts +1 -4
- package/dist/homebridge-ui/public/js/api.d.ts.map +1 -1
- package/dist/homebridge-ui/public/js/api.js +1 -7
- package/dist/homebridge-ui/public/js/api.js.map +1 -1
- package/dist/homebridge-ui/public/js/api.ts +1 -8
- package/dist/homebridge-ui/public/js/app.js +201 -90
- package/dist/homebridge-ui/public/js/app.js.map +2 -2
- package/dist/homebridge-ui/public/js/app.ts +5 -6
- package/dist/homebridge-ui/public/js/credentials.d.ts.map +1 -1
- package/dist/homebridge-ui/public/js/credentials.js +1 -1
- package/dist/homebridge-ui/public/js/credentials.js.map +1 -1
- package/dist/homebridge-ui/public/js/credentials.ts +7 -3
- package/dist/homebridge-ui/public/js/devices-delete.js +1 -1
- package/dist/homebridge-ui/public/js/devices-delete.js.map +1 -1
- package/dist/homebridge-ui/public/js/devices-delete.ts +1 -1
- package/dist/homebridge-ui/public/js/devices.d.ts.map +1 -1
- package/dist/homebridge-ui/public/js/devices.js +0 -1
- package/dist/homebridge-ui/public/js/devices.js.map +1 -1
- package/dist/homebridge-ui/public/js/devices.ts +0 -2
- package/dist/homebridge-ui/public/js/discovery.d.ts.map +1 -1
- package/dist/homebridge-ui/public/js/discovery.js +6 -3
- package/dist/homebridge-ui/public/js/discovery.js.map +1 -1
- package/dist/homebridge-ui/public/js/discovery.ts +9 -3
- package/dist/homebridge-ui/public/js/logger.d.ts +1 -0
- package/dist/homebridge-ui/public/js/logger.d.ts.map +1 -1
- package/dist/homebridge-ui/public/js/logger.js +8 -3
- package/dist/homebridge-ui/public/js/logger.js.map +1 -1
- package/dist/homebridge-ui/public/js/logger.ts +12 -6
- package/dist/homebridge-ui/public/js/modals.d.ts +4 -0
- package/dist/homebridge-ui/public/js/modals.d.ts.map +1 -1
- package/dist/homebridge-ui/public/js/modals.js +152 -59
- package/dist/homebridge-ui/public/js/modals.js.map +1 -1
- package/dist/homebridge-ui/public/js/modals.ts +187 -60
- package/dist/homebridge-ui/public/js/render.d.ts +3 -0
- package/dist/homebridge-ui/public/js/render.d.ts.map +1 -1
- package/dist/homebridge-ui/public/js/render.js +63 -24
- package/dist/homebridge-ui/public/js/render.js.map +1 -1
- package/dist/homebridge-ui/public/js/render.ts +102 -51
- package/dist/homebridge-ui/utils/logger.js +1 -1
- package/dist/homebridge-ui/utils/logger.js.map +1 -1
- package/dist/platform.d.ts.map +1 -1
- package/dist/platform.js +38 -30
- package/dist/platform.js.map +1 -1
- package/dist/switchbotClient.d.ts +5 -5
- package/dist/switchbotClient.d.ts.map +1 -1
- package/dist/switchbotClient.js +21 -12
- package/dist/switchbotClient.js.map +1 -1
- package/docs/variables/default.html +1 -1
- package/package.json +1 -1
- package/scripts/build-ui.js +4 -3
- package/scripts/generate-matter-maps.js +34 -17
- package/scripts/sync-device-types.mjs +4 -1
- package/src/deviceFactory.ts +3 -18
- package/src/devices/genericDevice.ts +77 -164
- package/src/homebridge-ui/public/index.html +107 -124
- package/src/homebridge-ui/public/js/api.ts +1 -8
- package/src/homebridge-ui/public/js/app.ts +5 -6
- package/src/homebridge-ui/public/js/credentials.ts +7 -3
- package/src/homebridge-ui/public/js/devices-delete.ts +1 -1
- package/src/homebridge-ui/public/js/devices.ts +0 -2
- package/src/homebridge-ui/public/js/discovery.ts +9 -3
- package/src/homebridge-ui/public/js/logger.ts +12 -6
- package/src/homebridge-ui/public/js/modals.ts +187 -60
- package/src/homebridge-ui/public/js/render.ts +102 -51
- package/src/homebridge-ui/utils/logger.ts +1 -1
- package/src/platform.ts +38 -29
- package/src/switchbotClient.ts +42 -27
- package/test/accessory-restore.spec.ts +9 -8
- package/test/device-mapping.spec.ts +4 -3
- package/test/deviceFactory.spec.ts +4 -3
- package/test/e2e/run-e2e.spec.ts +6 -10
- package/test/fan-swing.spec.ts +7 -6
- package/test/helpers/matter-harness.ts +18 -7
- package/test/lock-users.spec.ts +5 -5
- package/test/matter-childbridge.spec.ts +10 -7
- package/test/matter-descriptors.spec.ts +8 -8
- package/test/matter-device-state.spec.ts +52 -36
- package/test/matter-integration.spec.ts +53 -6
- package/test/platform.integration.spec.ts +7 -5
- package/test/switchbot-client-debounce.spec.ts +36 -40
- package/test/switchbot-client-openapi.spec.ts +22 -15
- package/test/switchbotClient.spec.ts +4 -3
- package/test/utils.spec.ts +2 -1
package/config.schema.json
CHANGED
|
@@ -155,17 +155,6 @@
|
|
|
155
155
|
"remote with screen"
|
|
156
156
|
]
|
|
157
157
|
},
|
|
158
|
-
"matterType": {
|
|
159
|
-
"type": [
|
|
160
|
-
"integer",
|
|
161
|
-
"null"
|
|
162
|
-
],
|
|
163
|
-
"title": "Matter Window Covering Type (Advanced)",
|
|
164
|
-
"description": "Override the Matter window covering type for this device. Only applies to Roller Shade, Curtain, Curtain3, and Blind Tilt. Leave blank for auto-detect. See Matter spec Table 8.2 for valid values (e.g., 0=RollerShade, 4=Drapery, 8=BlindTilt).",
|
|
165
|
-
"minimum": 0,
|
|
166
|
-
"maximum": 15,
|
|
167
|
-
"default": null
|
|
168
|
-
},
|
|
169
158
|
"connectionPreference": {
|
|
170
159
|
"type": "string",
|
|
171
160
|
"title": "Connection Preference",
|
package/dist/deviceFactory.d.ts
CHANGED
|
@@ -5,7 +5,9 @@ export interface DeviceOptions {
|
|
|
5
5
|
name?: string;
|
|
6
6
|
[key: string]: any;
|
|
7
7
|
}
|
|
8
|
-
export declare function createDevice(opts: DeviceOptions, cfg: SwitchBotPluginConfig, useMatter: boolean
|
|
8
|
+
export declare function createDevice(opts: DeviceOptions, cfg: SwitchBotPluginConfig, useMatter: boolean, log?: {
|
|
9
|
+
info: (...args: any[]) => void;
|
|
10
|
+
}): Promise<{
|
|
9
11
|
instance: any;
|
|
10
12
|
createAccessory: (api: any) => any;
|
|
11
13
|
protocol: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deviceFactory.d.ts","sourceRoot":"","sources":["../src/deviceFactory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAA;AAmCtE,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,UAAU,CAAA;IAChB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CACnB;AAqGD,wBAAsB,YAAY,CAAC,IAAI,EAAE,aAAa,EAAE,GAAG,EAAE,qBAAqB,EAAE,SAAS,EAAE,OAAO;;
|
|
1
|
+
{"version":3,"file":"deviceFactory.d.ts","sourceRoot":"","sources":["../src/deviceFactory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAA;AAmCtE,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,UAAU,CAAA;IAChB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CACnB;AAqGD,wBAAsB,YAAY,CAAC,IAAI,EAAE,aAAa,EAAE,GAAG,EAAE,qBAAqB,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE;IAAE,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAA;CAAE;;2BAgDlI,GAAG;;GAGhB"}
|
package/dist/deviceFactory.js
CHANGED
|
@@ -98,17 +98,10 @@ function classForType(type) {
|
|
|
98
98
|
const key = DEVICE_TYPE_NORMALIZATION_MAP[rawKey] ?? rawKey;
|
|
99
99
|
return DEVICE_CLASS_MAP[key] ?? GenericDevice;
|
|
100
100
|
}
|
|
101
|
-
export async function createDevice(opts, cfg, useMatter) {
|
|
101
|
+
export async function createDevice(opts, cfg, useMatter, log) {
|
|
102
102
|
// Debug: Log the options passed to the device constructor
|
|
103
|
-
if (opts && opts.name) {
|
|
104
|
-
|
|
105
|
-
// eslint-disable-next-line no-console
|
|
106
|
-
console.info(`[Matter/Debug] createDevice: Passing opts for ${opts.name}:`, JSON.stringify(opts, null, 2));
|
|
107
|
-
}
|
|
108
|
-
else {
|
|
109
|
-
// eslint-disable-next-line no-console
|
|
110
|
-
console.info(`[Matter/Debug] createDevice: Passing opts for ${opts.name} (no matterType):`, JSON.stringify(opts, null, 2));
|
|
111
|
-
}
|
|
103
|
+
if (opts && opts.name && log && typeof log.info === 'function') {
|
|
104
|
+
log.info(`[Matter/Debug] createDevice: Passing opts for ${opts.name}:`, JSON.stringify(opts, null, 2));
|
|
112
105
|
}
|
|
113
106
|
// Reuse existing client when provided via config to avoid creating
|
|
114
107
|
// a new SwitchBotClient per device (which can be expensive).
|
|
@@ -127,14 +120,6 @@ export async function createDevice(opts, cfg, useMatter) {
|
|
|
127
120
|
if (opts.keyId) {
|
|
128
121
|
deviceOpts.keyId = opts.keyId;
|
|
129
122
|
}
|
|
130
|
-
// Ensure matterType override is set for curtain devices
|
|
131
|
-
const typeKey = (opts.type || '').toLowerCase();
|
|
132
|
-
if ((typeKey === 'curtain' || typeKey === 'curtain3' || typeKey === 'rollershade' || typeKey === 'blindtilt') && cfg && cfg.devices) {
|
|
133
|
-
const configDevice = cfg.devices.find((d) => d.id === opts.id);
|
|
134
|
-
if (configDevice && typeof configDevice.matterType !== 'undefined') {
|
|
135
|
-
deviceOpts.matterType = configDevice.matterType;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
123
|
const DeviceCtor = classForType(opts.type);
|
|
139
124
|
const device = new DeviceCtor(deviceOpts, mergedCfg);
|
|
140
125
|
await device.init();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deviceFactory.js","sourceRoot":"","sources":["../src/deviceFactory.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"deviceFactory.js","sourceRoot":"","sources":["../src/deviceFactory.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import type { SwitchBotPluginConfig } from '../settings.js';
|
|
|
2
2
|
import { Buffer } from 'node:buffer';
|
|
3
3
|
import { DeviceBase } from './deviceBase.js';
|
|
4
4
|
export declare class GenericDevice extends DeviceBase {
|
|
5
|
-
protected log:
|
|
5
|
+
protected log: import('homebridge').Logger;
|
|
6
6
|
constructor(opts: any, cfg: SwitchBotPluginConfig);
|
|
7
7
|
/**
|
|
8
8
|
* Subscribe to BLE notifications for this device (if supported by node-switchbot)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"genericDevice.d.ts","sourceRoot":"","sources":["../../src/devices/genericDevice.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAA;AAE3D,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAGpC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAgB5C,qBAAa,aAAc,SAAQ,UAAU;IAC3C,SAAS,CAAC,GAAG,EAAE,
|
|
1
|
+
{"version":3,"file":"genericDevice.d.ts","sourceRoot":"","sources":["../../src/devices/genericDevice.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Buffer } from 'node:buffer';
|
|
2
2
|
import { MATTER_ATTRIBUTE_IDS, MATTER_CLUSTER_IDS } from '../utils.js';
|
|
3
3
|
import { DeviceBase } from './deviceBase.js';
|
|
4
|
-
function validateBLEResponseLength(buf, expected, context = '') {
|
|
4
|
+
function validateBLEResponseLength(buf, expected, context = '', log) {
|
|
5
5
|
if (!buf || typeof buf.length !== 'number' || buf.length !== expected) {
|
|
6
|
-
|
|
6
|
+
log.warn(`[BLE] Invalid response length${context ? ` for ${context}` : ''}: expected ${expected}, got ${buf?.length}`);
|
|
7
7
|
return false;
|
|
8
8
|
}
|
|
9
9
|
return true;
|
|
@@ -16,8 +16,11 @@ export class GenericDevice extends DeviceBase {
|
|
|
16
16
|
log;
|
|
17
17
|
constructor(opts, cfg) {
|
|
18
18
|
super(opts, cfg);
|
|
19
|
-
//
|
|
20
|
-
this.log = opts?.log || cfg?.log
|
|
19
|
+
// Require logger from opts or cfg
|
|
20
|
+
this.log = opts?.log || cfg?.log;
|
|
21
|
+
if (!this.log) {
|
|
22
|
+
throw new Error('Device requires a logger (Homebridge logger) in opts or cfg');
|
|
23
|
+
}
|
|
21
24
|
// If BLE encryptionKey/keyId provided, set on node-switchbot device instance if possible
|
|
22
25
|
if (opts.encryptionKey && this.client && typeof this.client.devices?.get === 'function') {
|
|
23
26
|
try {
|
|
@@ -33,10 +36,7 @@ export class GenericDevice extends DeviceBase {
|
|
|
33
36
|
// ignore if device not found or setKey not available
|
|
34
37
|
}
|
|
35
38
|
}
|
|
36
|
-
//
|
|
37
|
-
if (!this.log) {
|
|
38
|
-
this.log = console;
|
|
39
|
-
}
|
|
39
|
+
// ...existing code...
|
|
40
40
|
// Subscribe to BLE notifications if supported (node-switchbot v4+)
|
|
41
41
|
this._subscribeBLENotifications();
|
|
42
42
|
}
|
|
@@ -116,7 +116,7 @@ export class GenericDevice extends DeviceBase {
|
|
|
116
116
|
// If this is a BLE buffer/array, validate length (common BLE status: 12 bytes, but may vary by device)
|
|
117
117
|
if (raw && (raw instanceof Buffer || Array.isArray(raw) || raw instanceof Uint8Array)) {
|
|
118
118
|
// Default to 12, override per device if needed
|
|
119
|
-
if (!validateBLEResponseLength(raw, 12, this.opts.type)) {
|
|
119
|
+
if (!validateBLEResponseLength(raw, 12, this.opts.type, this.log)) {
|
|
120
120
|
return { id: this.opts.id, type: this.opts.type, error: 'invalid_ble_response_length', raw };
|
|
121
121
|
}
|
|
122
122
|
}
|
|
@@ -422,161 +422,81 @@ export class CurtainDevice extends GenericDevice {
|
|
|
422
422
|
],
|
|
423
423
|
};
|
|
424
424
|
}
|
|
425
|
-
// Matter-specific descriptor for Curtain (
|
|
425
|
+
// Matter-specific descriptor for Curtain (WindowCovering cluster) with new attributes
|
|
426
426
|
async createMatterAccessory(api) {
|
|
427
|
-
//
|
|
428
|
-
const
|
|
429
|
-
//
|
|
430
|
-
const
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
let state;
|
|
436
|
-
try {
|
|
437
|
-
state = await this.getState();
|
|
438
|
-
}
|
|
439
|
-
catch (e) {
|
|
440
|
-
state = undefined;
|
|
441
|
-
}
|
|
442
|
-
if (state) {
|
|
443
|
-
hasLiftAttrs = typeof state.position === 'number';
|
|
444
|
-
hasTiltAttrs = typeof state.tilt === 'number';
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
// For SwitchBot Curtain, always set supportsLift = true
|
|
448
|
-
let supportsLift = hasConfigLift || hasLiftAttrs;
|
|
449
|
-
if (typeKey.includes('curtain')) {
|
|
450
|
-
supportsLift = true;
|
|
451
|
-
}
|
|
452
|
-
else if (!supportsLift && (typeKey.includes('rollershade') || typeKey.includes('blindtilt'))) {
|
|
453
|
-
supportsLift = true;
|
|
454
|
-
}
|
|
455
|
-
const supportsTilt = hasConfigTilt || hasTiltAttrs || typeKey.includes('blindtilt') || typeKey.includes('blind tilt');
|
|
456
|
-
// Debug: Log feature detection variables
|
|
457
|
-
this.log.debug(`[Matter/Debug] ${this.opts.name ?? this.opts.id} feature detection: typeKey='${typeKey}', hasConfigLift=${hasConfigLift}, hasLiftAttrs=${hasLiftAttrs}, hasConfigTilt=${hasConfigTilt}, hasTiltAttrs=${hasTiltAttrs}, supportsLift=${supportsLift}, supportsTilt=${supportsTilt}`);
|
|
458
|
-
// If neither lift nor tilt is supported, do not register as Matter window covering
|
|
459
|
-
if (!supportsLift && !supportsTilt) {
|
|
460
|
-
this.log.warn(`[Matter] Skipping Matter registration for window covering device '${this.opts.name ?? this.opts.id}' (id: ${this.opts.id}): no lift or tilt support detected.`);
|
|
461
|
-
return undefined;
|
|
462
|
-
}
|
|
463
|
-
// Allow user to override Matter type via config (opts.matterType)
|
|
464
|
-
if (typeof this.opts.matterType === 'number') {
|
|
465
|
-
const matterType = this.opts.matterType;
|
|
466
|
-
this.log.info(`[Matter/Config] Using user-specified Matter type for ${this.opts.name ?? this.opts.id}: matterType=${matterType}`);
|
|
467
|
-
// Build attributes for Matter WindowCovering
|
|
468
|
-
const attributes = {
|
|
469
|
-
type: {
|
|
470
|
-
read: async () => {
|
|
471
|
-
this.log.debug(`[Matter/Debug] ${this.opts.name ?? this.opts.id} returning config-overridden type attribute value:`, matterType);
|
|
472
|
-
return matterType;
|
|
473
|
-
},
|
|
474
|
-
write: undefined,
|
|
427
|
+
// Get current state for dynamic attributes
|
|
428
|
+
const state = await this.getState();
|
|
429
|
+
// Compose attributes for Matter WindowCovering cluster
|
|
430
|
+
const attributes = {
|
|
431
|
+
currentPositionLiftPercent100ths: {
|
|
432
|
+
read: async () => {
|
|
433
|
+
const s = await this.getState();
|
|
434
|
+
return typeof s.position === 'number' ? Math.round(s.position * 100) : 0;
|
|
475
435
|
},
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
436
|
+
write: undefined,
|
|
437
|
+
},
|
|
438
|
+
targetPositionLiftPercent100ths: {
|
|
439
|
+
read: async () => {
|
|
440
|
+
const s = await this.getState();
|
|
441
|
+
return typeof s.position === 'number' ? Math.round(s.position * 100) : 0;
|
|
442
|
+
},
|
|
443
|
+
write: async (v) => this.setState({ position: Math.round(Number(v) / 100) }),
|
|
444
|
+
},
|
|
445
|
+
operationalStatus: {
|
|
446
|
+
read: async () => state.operationalStatus ?? { global: 0, lift: 0, tilt: 0 },
|
|
447
|
+
write: undefined,
|
|
448
|
+
},
|
|
449
|
+
endProductType: {
|
|
450
|
+
read: async () => state.endProductType ?? 0,
|
|
451
|
+
write: undefined,
|
|
452
|
+
},
|
|
453
|
+
configStatus: {
|
|
454
|
+
read: async () => state.configStatus ?? {
|
|
455
|
+
operational: true,
|
|
456
|
+
onlineReserved: true,
|
|
457
|
+
liftMovementReversed: false,
|
|
458
|
+
liftPositionAware: true,
|
|
459
|
+
tiltPositionAware: false,
|
|
460
|
+
liftEncoderControlled: true,
|
|
461
|
+
tiltEncoderControlled: false,
|
|
462
|
+
},
|
|
463
|
+
write: undefined,
|
|
464
|
+
},
|
|
465
|
+
};
|
|
466
|
+
// If tilt is supported, add tilt attributes
|
|
467
|
+
if (typeof state.tilt === 'number') {
|
|
468
|
+
attributes.currentPositionTiltPercent100ths = {
|
|
469
|
+
read: async () => {
|
|
470
|
+
const s = await this.getState();
|
|
471
|
+
return typeof s.tilt === 'number' ? Math.round(s.tilt * 100) : 0;
|
|
472
|
+
},
|
|
473
|
+
write: undefined,
|
|
494
474
|
};
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
name: this.opts.name ?? this.opts.type,
|
|
502
|
-
protocol: 'matter',
|
|
503
|
-
clusters: clustersArr,
|
|
475
|
+
attributes.targetPositionTiltPercent100ths = {
|
|
476
|
+
read: async () => {
|
|
477
|
+
const s = await this.getState();
|
|
478
|
+
return typeof s.tilt === 'number' ? Math.round(s.tilt * 100) : 0;
|
|
479
|
+
},
|
|
480
|
+
write: async (v) => this.setState({ tilt: Math.round(Number(v) / 100) }),
|
|
504
481
|
};
|
|
505
482
|
}
|
|
506
|
-
const
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
}
|
|
523
|
-
else if (!supportsLift && supportsTilt) {
|
|
524
|
-
// Only tilt: allow BlindTilt (8)
|
|
525
|
-
combos.push({ matterType: 8, supportsLift: false, supportsTilt: true });
|
|
526
|
-
}
|
|
527
|
-
let lastError;
|
|
528
|
-
for (const combo of combos) {
|
|
529
|
-
try {
|
|
530
|
-
this.log.info(`[Matter/Retry] Trying combo for ${this.opts.name ?? this.opts.id}: matterType=${combo.matterType}, supportsLift=${combo.supportsLift}, supportsTilt=${combo.supportsTilt}`);
|
|
531
|
-
this.log.debug(`[Matter/Debug] ${this.opts.name ?? this.opts.id} trying combo: matterType=${combo.matterType}, supportsLift=${combo.supportsLift}, supportsTilt=${combo.supportsTilt}`);
|
|
532
|
-
// Build attributes for Matter WindowCovering (string keys only)
|
|
533
|
-
const attributes = {
|
|
534
|
-
type: {
|
|
535
|
-
read: async () => {
|
|
536
|
-
this.log.debug(`[Matter/Debug] ${this.opts.name ?? this.opts.id} returning type attribute value:`, combo.matterType);
|
|
537
|
-
return combo.matterType;
|
|
538
|
-
},
|
|
539
|
-
write: undefined,
|
|
540
|
-
},
|
|
541
|
-
currentPosition: { read: async () => { const s = await this.getState(); return typeof s.position === 'number' ? s.position : 0; }, write: undefined },
|
|
542
|
-
targetPosition: { read: async () => { const s = await this.getState(); return typeof s.position === 'number' ? s.position : 0; }, write: async (v) => this.setState({ position: Number(v) }) },
|
|
543
|
-
};
|
|
544
|
-
if (combo.supportsTilt) {
|
|
545
|
-
attributes.currentTilt = { read: async () => { const s = await this.getState(); return typeof s.tilt === 'number' ? s.tilt : 0; }, write: undefined };
|
|
546
|
-
attributes.targetTilt = { read: async () => { const s = await this.getState(); return typeof s.tilt === 'number' ? s.tilt : 0; }, write: async (v) => this.setState({ tilt: Number(v) }) };
|
|
547
|
-
}
|
|
548
|
-
// Log the final attributes object
|
|
549
|
-
try {
|
|
550
|
-
this.log.debug(`[Matter/Debug] ${this.opts.name ?? this.opts.id} attributes:`, JSON.stringify(attributes, null, 2));
|
|
551
|
-
}
|
|
552
|
-
catch (e) {
|
|
553
|
-
this.log.debug(`[Matter/Debug] ${this.opts.name ?? this.opts.id} attributes: [unserializable]`);
|
|
554
|
-
}
|
|
555
|
-
// Try to register with this combo
|
|
556
|
-
const windowCoveringCluster = {
|
|
557
|
-
type: 'WindowCovering', // for test compatibility
|
|
558
|
-
matterType: combo.matterType, // actual Matter type number
|
|
559
|
-
clusterId: MATTER_CLUSTER_IDS.WindowCovering,
|
|
560
|
-
attributes,
|
|
561
|
-
};
|
|
562
|
-
const clustersArr = [windowCoveringCluster];
|
|
563
|
-
// Always set clusters.windowCovering to the WindowCovering cluster by clusterId
|
|
564
|
-
const foundWC = clustersArr.find((c) => c && c.clusterId === MATTER_CLUSTER_IDS.WindowCovering);
|
|
565
|
-
clustersArr.windowCovering = foundWC || null;
|
|
566
|
-
return {
|
|
567
|
-
id: this.opts.id,
|
|
568
|
-
name: this.opts.name ?? this.opts.type,
|
|
569
|
-
protocol: 'matter',
|
|
570
|
-
clusters: clustersArr,
|
|
571
|
-
};
|
|
572
|
-
}
|
|
573
|
-
catch (err) {
|
|
574
|
-
lastError = err;
|
|
575
|
-
this.log.warn(`[Matter/Retry] Failed combo matterType=${combo.matterType}, supportsLift=${combo.supportsLift}, supportsTilt=${combo.supportsTilt}: ${err}`);
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
// If all combos fail, throw last error
|
|
579
|
-
throw lastError || new Error('All Matter window covering type combos failed');
|
|
483
|
+
const windowCoveringCluster = {
|
|
484
|
+
type: 'WindowCovering',
|
|
485
|
+
clusterId: MATTER_CLUSTER_IDS.WindowCovering,
|
|
486
|
+
attributes,
|
|
487
|
+
};
|
|
488
|
+
// Provide both array and named property for clusters for compatibility with test expectations
|
|
489
|
+
const clustersArr = [windowCoveringCluster];
|
|
490
|
+
const clusters = [...clustersArr];
|
|
491
|
+
// Always set clusters.windowCovering to the WindowCovering cluster by clusterId
|
|
492
|
+
const foundWC = clustersArr.find((c) => c && c.clusterId === MATTER_CLUSTER_IDS.WindowCovering);
|
|
493
|
+
clusters.windowCovering = foundWC || null;
|
|
494
|
+
return {
|
|
495
|
+
id: this.opts.id,
|
|
496
|
+
name: this.opts.name ?? this.opts.type,
|
|
497
|
+
protocol: 'matter',
|
|
498
|
+
clusters,
|
|
499
|
+
};
|
|
580
500
|
}
|
|
581
501
|
}
|
|
582
502
|
export class FanDevice extends GenericDevice {
|