@matterbridge/core 3.10.8-dev-20260831-e73fc65 → 3.10.8-dev-20260901-971f7bf
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/dist/behaviors/doorLockServer.js +2 -3
- package/dist/behaviors/thermostatServer.js +19 -19
- package/dist/behaviors/windowCoveringServer.d.ts +17 -3
- package/dist/behaviors/windowCoveringServer.js +120 -18
- package/dist/demoDevices.js +45 -8
- package/dist/devices/closure.d.ts +11 -0
- package/dist/devices/closure.js +80 -10
- package/dist/devices/electricalUtilityMeter.d.ts +15 -0
- package/dist/devices/electricalUtilityMeter.js +16 -16
- package/dist/matterNode.js +10 -1
- package/dist/matterbridge.js +10 -1
- package/dist/matterbridgeEndpoint.d.ts +3 -2
- package/dist/matterbridgeEndpoint.js +36 -8
- package/dist/matterbridgeEndpointHelpers.js +1 -1
- package/dist/matterbridgeFactory.d.ts +1 -0
- package/dist/matterbridgeFactory.js +18 -2
- package/package.json +5 -5
|
@@ -122,11 +122,10 @@ export class MatterbridgeDoorLockServer extends DoorLockServer.with(DoorLock.Fea
|
|
|
122
122
|
context: this.context,
|
|
123
123
|
});
|
|
124
124
|
device.log.debug(`MatterbridgeDoorLockServer: setCredential called for userIndex ${request.userIndex} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
125
|
-
|
|
126
|
-
if (auth.isDuplicateCredential(request.credential.credentialType, request.credentialData, request.credential.credentialIndex)) {
|
|
125
|
+
if (this.auth.isDuplicateCredential(request.credential.credentialType, request.credentialData, request.credential.credentialIndex)) {
|
|
127
126
|
throw new DoorLock.DuplicateError(`MatterbridgeDoorLockServer: credential data duplicates another credential of the same type (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
128
127
|
}
|
|
129
|
-
if (request.operationType === DoorLock.DataOperationType.Add && auth.findCredential(request.credential.credentialType, request.credential.credentialIndex)) {
|
|
128
|
+
if (request.operationType === DoorLock.DataOperationType.Add && this.auth.findCredential(request.credential.credentialType, request.credential.credentialIndex)) {
|
|
130
129
|
throw new DoorLock.OccupiedError(`MatterbridgeDoorLockServer: add operation targets an occupied credential index (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
131
130
|
}
|
|
132
131
|
return await super.setCredential(request);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Bytes } from '@matter/general';
|
|
2
2
|
import { ThermostatServer } from '@matter/node/behaviors/thermostat';
|
|
3
|
-
import {
|
|
3
|
+
import { Status, StatusResponseError } from '@matter/types';
|
|
4
4
|
import { Thermostat } from '@matter/types/clusters/thermostat';
|
|
5
5
|
import { MatterbridgeServer } from './matterbridgeServer.js';
|
|
6
6
|
export class MatterbridgeThermostatServer extends ThermostatServer.with(Thermostat.Feature.Cooling, Thermostat.Feature.Heating, Thermostat.Feature.AutoMode, Thermostat.Feature.Presets, Thermostat.Feature.MatterScheduleConfiguration, Thermostat.Feature.ThermostatSuggestions) {
|
|
@@ -30,18 +30,18 @@ export class MatterbridgeThermostatServer extends ThermostatServer.with(Thermost
|
|
|
30
30
|
return;
|
|
31
31
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
32
32
|
if (remainingSuggestions.length !== currentSuggestions.length) {
|
|
33
|
-
device.log.info(`
|
|
33
|
+
device.log.info(`MatterbridgeThermostatServer: removing ${currentSuggestions.length - remainingSuggestions.length} thermostat suggestion(s) referencing removed preset(s) (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
34
34
|
this.state.thermostatSuggestions = remainingSuggestions;
|
|
35
35
|
}
|
|
36
36
|
if (clearCurrentSuggestion) {
|
|
37
|
-
device.log.info(`
|
|
37
|
+
device.log.info(`MatterbridgeThermostatServer: clearing current thermostat suggestion referencing a removed preset (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
38
38
|
this.state.currentThermostatSuggestion = null;
|
|
39
39
|
this.state.thermostatSuggestionNotFollowingReason = null;
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
async setpointRaiseLower(request) {
|
|
43
43
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
44
|
-
device.log.info(`
|
|
44
|
+
device.log.info(`MatterbridgeThermostatServer: setting setpoint by ${request.amount} in mode ${request.mode} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
45
45
|
await device.commandHandler.executeHandler('Thermostat.setpointRaiseLower', {
|
|
46
46
|
command: 'setpointRaiseLower',
|
|
47
47
|
request,
|
|
@@ -51,13 +51,13 @@ export class MatterbridgeThermostatServer extends ThermostatServer.with(Thermost
|
|
|
51
51
|
context: this.context,
|
|
52
52
|
});
|
|
53
53
|
const lookupSetpointAdjustMode = ['Heat', 'Cool', 'Both'];
|
|
54
|
-
device.log.debug(`MatterbridgeThermostatServer: setpointRaiseLower called with mode: ${lookupSetpointAdjustMode[request.mode]} amount: ${request.amount / 10}`);
|
|
54
|
+
device.log.debug(`MatterbridgeThermostatServer: setpointRaiseLower called with mode: ${lookupSetpointAdjustMode[request.mode]} amount: ${request.amount / 10} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
55
55
|
await super.setpointRaiseLower(request);
|
|
56
56
|
}
|
|
57
57
|
async setActivePresetRequest(request) {
|
|
58
58
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
59
59
|
const presetHandle = request.presetHandle ? `0x${Buffer.from(request.presetHandle).toString('hex')}` : 'null';
|
|
60
|
-
device.log.info(`
|
|
60
|
+
device.log.info(`MatterbridgeThermostatServer: setting preset to ${presetHandle} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
61
61
|
await device.commandHandler.executeHandler('Thermostat.setActivePresetRequest', {
|
|
62
62
|
command: 'setActivePresetRequest',
|
|
63
63
|
request,
|
|
@@ -66,15 +66,15 @@ export class MatterbridgeThermostatServer extends ThermostatServer.with(Thermost
|
|
|
66
66
|
endpoint: this.endpoint,
|
|
67
67
|
context: this.context,
|
|
68
68
|
});
|
|
69
|
-
device.log.debug(`MatterbridgeThermostatServer: setActivePresetRequest called with presetHandle: ${presetHandle}`);
|
|
69
|
+
device.log.debug(`MatterbridgeThermostatServer: setActivePresetRequest called with presetHandle: ${presetHandle} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
70
70
|
await super.setActivePresetRequest(request);
|
|
71
71
|
const activePresetHandle = this.state.activePresetHandle ? `0x${Buffer.from(this.state.activePresetHandle).toString('hex')}` : 'null';
|
|
72
|
-
device.log.debug(`MatterbridgeThermostatServer: setActivePresetRequest completed with activePresetHandle: ${activePresetHandle} occupiedHeatingSetpoint: ${this.state.occupiedHeatingSetpoint} occupiedCoolingSetpoint: ${this.state.occupiedCoolingSetpoint}`);
|
|
72
|
+
device.log.debug(`MatterbridgeThermostatServer: setActivePresetRequest completed with activePresetHandle: ${activePresetHandle} occupiedHeatingSetpoint: ${this.state.occupiedHeatingSetpoint} occupiedCoolingSetpoint: ${this.state.occupiedCoolingSetpoint} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
73
73
|
}
|
|
74
74
|
async setActiveScheduleRequest(request) {
|
|
75
75
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
76
76
|
const scheduleHandle = `0x${Buffer.from(request.scheduleHandle).toString('hex')}`;
|
|
77
|
-
device.log.info(`
|
|
77
|
+
device.log.info(`MatterbridgeThermostatServer: setting schedule to ${scheduleHandle} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
78
78
|
await device.commandHandler.executeHandler('Thermostat.setActiveScheduleRequest', {
|
|
79
79
|
command: 'setActiveScheduleRequest',
|
|
80
80
|
request,
|
|
@@ -85,10 +85,10 @@ export class MatterbridgeThermostatServer extends ThermostatServer.with(Thermost
|
|
|
85
85
|
});
|
|
86
86
|
const schedule = this.state.schedules.find((s) => s.scheduleHandle !== null && Bytes.areEqual(s.scheduleHandle, request.scheduleHandle));
|
|
87
87
|
if (schedule === undefined) {
|
|
88
|
-
throw new
|
|
88
|
+
throw new StatusResponseError(`MatterbridgeThermostatServer: requested ScheduleHandle not found (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`, Status.InvalidCommand);
|
|
89
89
|
}
|
|
90
90
|
this.state.activeScheduleHandle = Uint8Array.from(request.scheduleHandle);
|
|
91
|
-
device.log.debug(`MatterbridgeThermostatServer: setActiveScheduleRequest completed with activeScheduleHandle: ${scheduleHandle}`);
|
|
91
|
+
device.log.debug(`MatterbridgeThermostatServer: setActiveScheduleRequest completed with activeScheduleHandle: ${scheduleHandle} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
92
92
|
}
|
|
93
93
|
removeExpiredThermostatSuggestions() {
|
|
94
94
|
const now = Math.floor(Date.now() / 1000);
|
|
@@ -112,7 +112,7 @@ export class MatterbridgeThermostatServer extends ThermostatServer.with(Thermost
|
|
|
112
112
|
async addThermostatSuggestion(request) {
|
|
113
113
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
114
114
|
const presetHandle = `0x${Buffer.from(request.presetHandle).toString('hex')}`;
|
|
115
|
-
device.log.info(`
|
|
115
|
+
device.log.info(`MatterbridgeThermostatServer: adding thermostat suggestion for preset ${presetHandle} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
116
116
|
await device.commandHandler.executeHandler('Thermostat.addThermostatSuggestion', {
|
|
117
117
|
command: 'addThermostatSuggestion',
|
|
118
118
|
request,
|
|
@@ -122,17 +122,17 @@ export class MatterbridgeThermostatServer extends ThermostatServer.with(Thermost
|
|
|
122
122
|
context: this.context,
|
|
123
123
|
});
|
|
124
124
|
if (this.state.presets.find((p) => p.presetHandle !== null && Bytes.areEqual(p.presetHandle, request.presetHandle)) === undefined) {
|
|
125
|
-
throw new
|
|
125
|
+
throw new StatusResponseError(`MatterbridgeThermostatServer: requested PresetHandle not found (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`, Status.NotFound);
|
|
126
126
|
}
|
|
127
127
|
this.removeExpiredThermostatSuggestions();
|
|
128
128
|
this.reEvaluateCurrentThermostatSuggestion();
|
|
129
129
|
if (this.state.thermostatSuggestions.length >= this.state.maxThermostatSuggestions) {
|
|
130
|
-
throw new
|
|
130
|
+
throw new StatusResponseError(`MatterbridgeThermostatServer: maximum number of thermostat suggestions reached (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`, Status.ResourceExhausted);
|
|
131
131
|
}
|
|
132
132
|
const currentTime = Math.floor(Date.now() / 1000);
|
|
133
133
|
const effectiveTime = request.effectiveTime ?? currentTime;
|
|
134
134
|
if (effectiveTime > currentTime + 24 * 60 * 60) {
|
|
135
|
-
throw new
|
|
135
|
+
throw new StatusResponseError(`MatterbridgeThermostatServer: requested EffectiveTime is more than 24 hours in the future (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`, Status.InvalidCommand);
|
|
136
136
|
}
|
|
137
137
|
const usedUniqueIds = new Set(this.state.thermostatSuggestions.map((s) => s.uniqueId));
|
|
138
138
|
let uniqueId = 0;
|
|
@@ -146,12 +146,12 @@ export class MatterbridgeThermostatServer extends ThermostatServer.with(Thermost
|
|
|
146
146
|
};
|
|
147
147
|
this.state.thermostatSuggestions = [...this.state.thermostatSuggestions, suggestion];
|
|
148
148
|
this.reEvaluateCurrentThermostatSuggestion();
|
|
149
|
-
device.log.debug(`MatterbridgeThermostatServer: addThermostatSuggestion completed with uniqueId: ${uniqueId}`);
|
|
149
|
+
device.log.debug(`MatterbridgeThermostatServer: addThermostatSuggestion completed with uniqueId: ${uniqueId} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
150
150
|
return { uniqueId };
|
|
151
151
|
}
|
|
152
152
|
async removeThermostatSuggestion(request) {
|
|
153
153
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
154
|
-
device.log.info(`
|
|
154
|
+
device.log.info(`MatterbridgeThermostatServer: removing thermostat suggestion ${request.uniqueId} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
155
155
|
await device.commandHandler.executeHandler('Thermostat.removeThermostatSuggestion', {
|
|
156
156
|
command: 'removeThermostatSuggestion',
|
|
157
157
|
request,
|
|
@@ -162,11 +162,11 @@ export class MatterbridgeThermostatServer extends ThermostatServer.with(Thermost
|
|
|
162
162
|
});
|
|
163
163
|
const suggestion = this.state.thermostatSuggestions.find((s) => s.uniqueId === request.uniqueId);
|
|
164
164
|
if (suggestion === undefined) {
|
|
165
|
-
throw new
|
|
165
|
+
throw new StatusResponseError(`MatterbridgeThermostatServer: requested UniqueID not found (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`, Status.NotFound);
|
|
166
166
|
}
|
|
167
167
|
this.state.thermostatSuggestions = this.state.thermostatSuggestions.filter((s) => s.uniqueId !== request.uniqueId);
|
|
168
168
|
this.removeExpiredThermostatSuggestions();
|
|
169
169
|
this.reEvaluateCurrentThermostatSuggestion();
|
|
170
|
-
device.log.debug(`MatterbridgeThermostatServer: removeThermostatSuggestion completed for uniqueId: ${request.uniqueId}`);
|
|
170
|
+
device.log.debug(`MatterbridgeThermostatServer: removeThermostatSuggestion completed for uniqueId: ${request.uniqueId} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
171
171
|
}
|
|
172
172
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type Timer } from '@matter/general';
|
|
2
|
+
import { WindowCoveringBaseServer, WindowCoveringServer } from '@matter/node/behaviors/window-covering';
|
|
2
3
|
import { WindowCovering } from '@matter/types/clusters/window-covering';
|
|
3
4
|
declare const MatterbridgeWindowCoveringServer_base: import("@matter/node").ClusterBehavior.Type<typeof WindowCoveringServer, import("@matter/types").ClusterType.WithSupportedFeatures<WindowCovering, {
|
|
4
5
|
lift: true;
|
|
@@ -7,7 +8,9 @@ declare const MatterbridgeWindowCoveringServer_base: import("@matter/node").Clus
|
|
|
7
8
|
tilt: true;
|
|
8
9
|
}>, import("@matter/types").ClusterType.Concrete, typeof WindowCoveringBaseServer.Internal, "windowCovering">;
|
|
9
10
|
export declare class MatterbridgeWindowCoveringServer extends MatterbridgeWindowCoveringServer_base {
|
|
10
|
-
|
|
11
|
+
#private;
|
|
12
|
+
readonly state: MatterbridgeWindowCoveringServer.State;
|
|
13
|
+
protected internal: MatterbridgeWindowCoveringServer.Internal;
|
|
11
14
|
lookupMovementStatus: string[];
|
|
12
15
|
private getMovementStatusLabel;
|
|
13
16
|
initialize(): void;
|
|
@@ -16,6 +19,17 @@ export declare class MatterbridgeWindowCoveringServer extends MatterbridgeWindow
|
|
|
16
19
|
stopMotion(): Promise<void>;
|
|
17
20
|
goToLiftPercentage(request: WindowCovering.GoToLiftPercentageRequest): Promise<void>;
|
|
18
21
|
goToTiltPercentage(request: WindowCovering.GoToTiltPercentageRequest): Promise<void>;
|
|
19
|
-
|
|
22
|
+
[Symbol.asyncDispose](): Promise<void>;
|
|
23
|
+
}
|
|
24
|
+
export declare namespace MatterbridgeWindowCoveringServer {
|
|
25
|
+
class Internal extends WindowCoveringBaseServer.Internal {
|
|
26
|
+
liftMovementTimer?: Timer;
|
|
27
|
+
liftMovementTarget: number;
|
|
28
|
+
tiltMovementTimer?: Timer;
|
|
29
|
+
tiltMovementTarget: number;
|
|
30
|
+
}
|
|
31
|
+
class State extends WindowCoveringBaseServer.State {
|
|
32
|
+
movementDuration: number;
|
|
33
|
+
}
|
|
20
34
|
}
|
|
21
35
|
export {};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Millis, Time } from '@matter/general';
|
|
2
|
+
import { WindowCoveringBaseServer, WindowCoveringServer } from '@matter/node/behaviors/window-covering';
|
|
2
3
|
import { WindowCovering } from '@matter/types/clusters/window-covering';
|
|
3
4
|
import { MatterbridgeServer } from './matterbridgeServer.js';
|
|
4
5
|
export class MatterbridgeWindowCoveringServer extends WindowCoveringServer.with(WindowCovering.Feature.Lift, WindowCovering.Feature.PositionAwareLift, WindowCovering.Feature.Tilt, WindowCovering.Feature.PositionAwareTilt) {
|
|
@@ -8,13 +9,73 @@ export class MatterbridgeWindowCoveringServer extends WindowCoveringServer.with(
|
|
|
8
9
|
}
|
|
9
10
|
initialize() {
|
|
10
11
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
11
|
-
device.log.info(`
|
|
12
|
+
device.log.info(`MatterbridgeWindowCoveringServer: initializing (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
12
13
|
this.internal.disableOperationalModeHandling = true;
|
|
14
|
+
if (process.env.MATTERBRIDGE_CHIP_TEST) {
|
|
15
|
+
this.state.movementDuration = 3000;
|
|
16
|
+
}
|
|
13
17
|
super.initialize();
|
|
18
|
+
if (this.features.positionAwareLift)
|
|
19
|
+
this.reactTo(this.events.currentPositionLiftPercent100ths$Changing, this.#syncLiftCurrentPositionPercentage);
|
|
20
|
+
if (this.features.positionAwareTilt)
|
|
21
|
+
this.reactTo(this.events.currentPositionTiltPercent100ths$Changing, this.#syncTiltCurrentPositionPercentage);
|
|
22
|
+
}
|
|
23
|
+
#syncLiftCurrentPositionPercentage(percent100ths) {
|
|
24
|
+
this.state.currentPositionLiftPercentage = percent100ths === null ? percent100ths : Math.floor(percent100ths / 100);
|
|
25
|
+
}
|
|
26
|
+
#syncTiltCurrentPositionPercentage(percent100ths) {
|
|
27
|
+
this.state.currentPositionTiltPercentage = percent100ths === null ? percent100ths : Math.floor(percent100ths / 100);
|
|
28
|
+
}
|
|
29
|
+
#computeMovementStatus(target, current) {
|
|
30
|
+
if (current === null || target === null || current === target)
|
|
31
|
+
return WindowCovering.MovementStatus.Stopped;
|
|
32
|
+
return current < target ? WindowCovering.MovementStatus.Closing : WindowCovering.MovementStatus.Opening;
|
|
33
|
+
}
|
|
34
|
+
#updateGlobalOperationalStatus() {
|
|
35
|
+
const { lift, tilt } = this.state.operationalStatus;
|
|
36
|
+
this.state.operationalStatus.global = lift === WindowCovering.MovementStatus.Stopped ? tilt : lift;
|
|
37
|
+
}
|
|
38
|
+
#startLiftMovement(targetPercent100ths) {
|
|
39
|
+
this.internal.liftMovementTimer?.stop();
|
|
40
|
+
this.internal.liftMovementTimer = undefined;
|
|
41
|
+
if (this.state.movementDuration <= 0)
|
|
42
|
+
return;
|
|
43
|
+
const status = this.#computeMovementStatus(targetPercent100ths, this.state.currentPositionLiftPercent100ths);
|
|
44
|
+
this.state.operationalStatus.lift = status;
|
|
45
|
+
this.#updateGlobalOperationalStatus();
|
|
46
|
+
if (status === WindowCovering.MovementStatus.Stopped)
|
|
47
|
+
return;
|
|
48
|
+
this.internal.liftMovementTarget = targetPercent100ths;
|
|
49
|
+
this.internal.liftMovementTimer = Time.getTimer('WindowCovering lift movement complete', Millis(this.state.movementDuration), this.callback(this.#completeLiftMovement, { lock: true })).start();
|
|
50
|
+
}
|
|
51
|
+
#completeLiftMovement() {
|
|
52
|
+
this.internal.liftMovementTimer = undefined;
|
|
53
|
+
this.state.currentPositionLiftPercent100ths = this.internal.liftMovementTarget;
|
|
54
|
+
this.state.operationalStatus.lift = WindowCovering.MovementStatus.Stopped;
|
|
55
|
+
this.#updateGlobalOperationalStatus();
|
|
56
|
+
}
|
|
57
|
+
#startTiltMovement(targetPercent100ths) {
|
|
58
|
+
this.internal.tiltMovementTimer?.stop();
|
|
59
|
+
this.internal.tiltMovementTimer = undefined;
|
|
60
|
+
if (this.state.movementDuration <= 0)
|
|
61
|
+
return;
|
|
62
|
+
const status = this.#computeMovementStatus(targetPercent100ths, this.state.currentPositionTiltPercent100ths);
|
|
63
|
+
this.state.operationalStatus.tilt = status;
|
|
64
|
+
this.#updateGlobalOperationalStatus();
|
|
65
|
+
if (status === WindowCovering.MovementStatus.Stopped)
|
|
66
|
+
return;
|
|
67
|
+
this.internal.tiltMovementTarget = targetPercent100ths;
|
|
68
|
+
this.internal.tiltMovementTimer = Time.getTimer('WindowCovering tilt movement complete', Millis(this.state.movementDuration), this.callback(this.#completeTiltMovement, { lock: true })).start();
|
|
69
|
+
}
|
|
70
|
+
#completeTiltMovement() {
|
|
71
|
+
this.internal.tiltMovementTimer = undefined;
|
|
72
|
+
this.state.currentPositionTiltPercent100ths = this.internal.tiltMovementTarget;
|
|
73
|
+
this.state.operationalStatus.tilt = WindowCovering.MovementStatus.Stopped;
|
|
74
|
+
this.#updateGlobalOperationalStatus();
|
|
14
75
|
}
|
|
15
76
|
async upOrOpen() {
|
|
16
77
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
17
|
-
device.log.info(`
|
|
78
|
+
device.log.info(`MatterbridgeWindowCoveringServer: opening cover (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
18
79
|
await device.commandHandler.executeHandler('WindowCovering.upOrOpen', {
|
|
19
80
|
command: 'upOrOpen',
|
|
20
81
|
request: {},
|
|
@@ -23,13 +84,17 @@ export class MatterbridgeWindowCoveringServer extends WindowCoveringServer.with(
|
|
|
23
84
|
endpoint: this.endpoint,
|
|
24
85
|
context: this.context,
|
|
25
86
|
});
|
|
26
|
-
device.log.debug(`MatterbridgeWindowCoveringServer: upOrOpen called`);
|
|
87
|
+
device.log.debug(`MatterbridgeWindowCoveringServer: upOrOpen called (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
27
88
|
await super.upOrOpen();
|
|
28
|
-
|
|
89
|
+
if (this.features.positionAwareLift && this.state.targetPositionLiftPercent100ths !== null)
|
|
90
|
+
this.#startLiftMovement(this.state.targetPositionLiftPercent100ths);
|
|
91
|
+
if (this.features.positionAwareTilt && this.state.targetPositionTiltPercent100ths !== null)
|
|
92
|
+
this.#startTiltMovement(this.state.targetPositionTiltPercent100ths);
|
|
93
|
+
device.log.debug(`MatterbridgeWindowCoveringServer: upOrOpen result target ${this.state.targetPositionLiftPercent100ths} current ${this.state.currentPositionLiftPercent100ths} status global ${this.getMovementStatusLabel(this.state.operationalStatus.global)} lift ${this.getMovementStatusLabel(this.state.operationalStatus.lift)} tilt ${this.getMovementStatusLabel(this.state.operationalStatus.tilt)} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
29
94
|
}
|
|
30
95
|
async downOrClose() {
|
|
31
96
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
32
|
-
device.log.info(`
|
|
97
|
+
device.log.info(`MatterbridgeWindowCoveringServer: closing cover (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
33
98
|
await device.commandHandler.executeHandler('WindowCovering.downOrClose', {
|
|
34
99
|
command: 'downOrClose',
|
|
35
100
|
request: {},
|
|
@@ -38,13 +103,17 @@ export class MatterbridgeWindowCoveringServer extends WindowCoveringServer.with(
|
|
|
38
103
|
endpoint: this.endpoint,
|
|
39
104
|
context: this.context,
|
|
40
105
|
});
|
|
41
|
-
device.log.debug(`MatterbridgeWindowCoveringServer: downOrClose called`);
|
|
106
|
+
device.log.debug(`MatterbridgeWindowCoveringServer: downOrClose called (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
42
107
|
await super.downOrClose();
|
|
43
|
-
|
|
108
|
+
if (this.features.positionAwareLift && this.state.targetPositionLiftPercent100ths !== null)
|
|
109
|
+
this.#startLiftMovement(this.state.targetPositionLiftPercent100ths);
|
|
110
|
+
if (this.features.positionAwareTilt && this.state.targetPositionTiltPercent100ths !== null)
|
|
111
|
+
this.#startTiltMovement(this.state.targetPositionTiltPercent100ths);
|
|
112
|
+
device.log.debug(`MatterbridgeWindowCoveringServer: downOrClose result target ${this.state.targetPositionLiftPercent100ths} current ${this.state.currentPositionLiftPercent100ths} status global ${this.getMovementStatusLabel(this.state.operationalStatus.global)} lift ${this.getMovementStatusLabel(this.state.operationalStatus.lift)} tilt ${this.getMovementStatusLabel(this.state.operationalStatus.tilt)} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
44
113
|
}
|
|
45
114
|
async stopMotion() {
|
|
46
115
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
47
|
-
device.log.info(`
|
|
116
|
+
device.log.info(`MatterbridgeWindowCoveringServer: stopping cover (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
48
117
|
await device.commandHandler.executeHandler('WindowCovering.stopMotion', {
|
|
49
118
|
command: 'stopMotion',
|
|
50
119
|
request: {},
|
|
@@ -53,13 +122,24 @@ export class MatterbridgeWindowCoveringServer extends WindowCoveringServer.with(
|
|
|
53
122
|
endpoint: this.endpoint,
|
|
54
123
|
context: this.context,
|
|
55
124
|
});
|
|
56
|
-
device.log.debug(`MatterbridgeWindowCoveringServer: stopMotion called`);
|
|
125
|
+
device.log.debug(`MatterbridgeWindowCoveringServer: stopMotion called (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
57
126
|
await super.stopMotion();
|
|
58
|
-
|
|
127
|
+
this.internal.liftMovementTimer?.stop();
|
|
128
|
+
this.internal.liftMovementTimer = undefined;
|
|
129
|
+
this.internal.tiltMovementTimer?.stop();
|
|
130
|
+
this.internal.tiltMovementTimer = undefined;
|
|
131
|
+
if (this.state.movementDuration > 0) {
|
|
132
|
+
if (this.features.positionAwareLift)
|
|
133
|
+
this.state.targetPositionLiftPercent100ths = this.state.currentPositionLiftPercent100ths;
|
|
134
|
+
if (this.features.positionAwareTilt)
|
|
135
|
+
this.state.targetPositionTiltPercent100ths = this.state.currentPositionTiltPercent100ths;
|
|
136
|
+
this.state.operationalStatus = { global: WindowCovering.MovementStatus.Stopped, lift: WindowCovering.MovementStatus.Stopped, tilt: WindowCovering.MovementStatus.Stopped };
|
|
137
|
+
}
|
|
138
|
+
device.log.debug(`MatterbridgeWindowCoveringServer: stopMotion result target ${this.state.targetPositionLiftPercent100ths} current ${this.state.currentPositionLiftPercent100ths} status global ${this.getMovementStatusLabel(this.state.operationalStatus.global)} lift ${this.getMovementStatusLabel(this.state.operationalStatus.lift)} tilt ${this.getMovementStatusLabel(this.state.operationalStatus.tilt)} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
59
139
|
}
|
|
60
140
|
async goToLiftPercentage(request) {
|
|
61
141
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
62
|
-
device.log.info(`
|
|
142
|
+
device.log.info(`MatterbridgeWindowCoveringServer: setting cover lift percentage to ${request.liftPercent100thsValue} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
63
143
|
await device.commandHandler.executeHandler('WindowCovering.goToLiftPercentage', {
|
|
64
144
|
command: 'goToLiftPercentage',
|
|
65
145
|
request,
|
|
@@ -68,13 +148,15 @@ export class MatterbridgeWindowCoveringServer extends WindowCoveringServer.with(
|
|
|
68
148
|
endpoint: this.endpoint,
|
|
69
149
|
context: this.context,
|
|
70
150
|
});
|
|
71
|
-
device.log.debug(`MatterbridgeWindowCoveringServer: goToLiftPercentage with ${request.liftPercent100thsValue}`);
|
|
151
|
+
device.log.debug(`MatterbridgeWindowCoveringServer: goToLiftPercentage with ${request.liftPercent100thsValue} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
72
152
|
await super.goToLiftPercentage(request);
|
|
73
|
-
|
|
153
|
+
if (this.state.targetPositionLiftPercent100ths !== null)
|
|
154
|
+
this.#startLiftMovement(this.state.targetPositionLiftPercent100ths);
|
|
155
|
+
device.log.debug(`MatterbridgeWindowCoveringServer: goToLiftPercentage result target ${this.state.targetPositionLiftPercent100ths} current ${this.state.currentPositionLiftPercent100ths} status global ${this.getMovementStatusLabel(this.state.operationalStatus.global)} lift ${this.getMovementStatusLabel(this.state.operationalStatus.lift)} tilt ${this.getMovementStatusLabel(this.state.operationalStatus.tilt)} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
74
156
|
}
|
|
75
157
|
async goToTiltPercentage(request) {
|
|
76
158
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
77
|
-
device.log.info(`
|
|
159
|
+
device.log.info(`MatterbridgeWindowCoveringServer: setting cover tilt percentage to ${request.tiltPercent100thsValue} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
78
160
|
await device.commandHandler.executeHandler('WindowCovering.goToTiltPercentage', {
|
|
79
161
|
command: 'goToTiltPercentage',
|
|
80
162
|
request,
|
|
@@ -83,10 +165,30 @@ export class MatterbridgeWindowCoveringServer extends WindowCoveringServer.with(
|
|
|
83
165
|
endpoint: this.endpoint,
|
|
84
166
|
context: this.context,
|
|
85
167
|
});
|
|
86
|
-
device.log.debug(`MatterbridgeWindowCoveringServer: goToTiltPercentage with ${request.tiltPercent100thsValue}`);
|
|
168
|
+
device.log.debug(`MatterbridgeWindowCoveringServer: goToTiltPercentage with ${request.tiltPercent100thsValue} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
87
169
|
await super.goToTiltPercentage(request);
|
|
88
|
-
|
|
170
|
+
if (this.state.targetPositionTiltPercent100ths !== null)
|
|
171
|
+
this.#startTiltMovement(this.state.targetPositionTiltPercent100ths);
|
|
172
|
+
device.log.debug(`MatterbridgeWindowCoveringServer: goToTiltPercentage result target ${this.state.targetPositionTiltPercent100ths} current ${this.state.currentPositionTiltPercent100ths} status global ${this.getMovementStatusLabel(this.state.operationalStatus.global)} lift ${this.getMovementStatusLabel(this.state.operationalStatus.lift)} tilt ${this.getMovementStatusLabel(this.state.operationalStatus.tilt)} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
89
173
|
}
|
|
90
|
-
|
|
174
|
+
async [Symbol.asyncDispose]() {
|
|
175
|
+
this.internal.liftMovementTimer?.stop();
|
|
176
|
+
this.internal.liftMovementTimer = undefined;
|
|
177
|
+
this.internal.tiltMovementTimer?.stop();
|
|
178
|
+
this.internal.tiltMovementTimer = undefined;
|
|
179
|
+
await super[Symbol.asyncDispose]?.();
|
|
91
180
|
}
|
|
92
181
|
}
|
|
182
|
+
(function (MatterbridgeWindowCoveringServer) {
|
|
183
|
+
class Internal extends WindowCoveringBaseServer.Internal {
|
|
184
|
+
liftMovementTimer;
|
|
185
|
+
liftMovementTarget = 0;
|
|
186
|
+
tiltMovementTimer;
|
|
187
|
+
tiltMovementTarget = 0;
|
|
188
|
+
}
|
|
189
|
+
MatterbridgeWindowCoveringServer.Internal = Internal;
|
|
190
|
+
class State extends WindowCoveringBaseServer.State {
|
|
191
|
+
movementDuration = 0;
|
|
192
|
+
}
|
|
193
|
+
MatterbridgeWindowCoveringServer.State = State;
|
|
194
|
+
})(MatterbridgeWindowCoveringServer || (MatterbridgeWindowCoveringServer = {}));
|
package/dist/demoDevices.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readFile, writeFile } from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import { ClosureCoveringTag, ClosurePanelTag, ClosureTag, ClosureWindowTag, CommodityTariffChronologyTag, CommodityTariffCommodityTag, CommodityTariffFlowTag, CommonNumberTag, CommonPositionTag, ElectricalMeasurementTag, PowerSourceTag, RefrigeratorTag, } from '@matter/node';
|
|
3
|
+
import { ClosureCoveringTag, ClosurePanelTag, ClosureTag, ClosureWindowTag, CommodityTariffChronologyTag, CommodityTariffCommodityTag, CommodityTariffFlowTag, CommonNumberTag, CommonPositionTag, ElectricalMeasurementTag, PowerSourceTag, RefrigeratorTag, SwitchesTag, } from '@matter/node';
|
|
4
4
|
import { AirQuality } from '@matter/types/clusters/air-quality';
|
|
5
5
|
import { ClosureDimension } from '@matter/types/clusters/closure-dimension';
|
|
6
6
|
import { DoorLock } from '@matter/types/clusters/door-lock';
|
|
@@ -10,6 +10,7 @@ import { PowerTopology } from '@matter/types/clusters/power-topology';
|
|
|
10
10
|
import { ResourceMonitoring } from '@matter/types/clusters/resource-monitoring';
|
|
11
11
|
import { RvcCleanMode } from '@matter/types/clusters/rvc-clean-mode';
|
|
12
12
|
import { RvcRunMode } from '@matter/types/clusters/rvc-run-mode';
|
|
13
|
+
import { Thermostat } from '@matter/types/clusters/thermostat';
|
|
13
14
|
import { EndpointNumber } from '@matter/types/datatype';
|
|
14
15
|
import { getErrorMessage } from '@matterbridge/utils/error';
|
|
15
16
|
import { AirConditioner } from './devices/airConditioner.js';
|
|
@@ -266,8 +267,33 @@ export async function createDemoDevices(matterbridge) {
|
|
|
266
267
|
ep = new MatterbridgeEndpoint([getSupportedDeviceType('PumpController'), bridgedNode, powerSource], { id: 'PumpController', number: EndpointNumber(6_05) });
|
|
267
268
|
ep.createDefaultPowerSourceWiredClusterServer();
|
|
268
269
|
await registerDevice(ep, 'Pump Controller', 'SWITCH-06-05');
|
|
269
|
-
ep = new MatterbridgeEndpoint([getSupportedDeviceType('
|
|
270
|
+
ep = new MatterbridgeEndpoint([getSupportedDeviceType('Aggregator'), bridgedNode, powerSource], { id: 'GenericSwitch', number: EndpointNumber(6_06) });
|
|
270
271
|
ep.createDefaultPowerSourceBatteryClusterServer();
|
|
272
|
+
await ep.addFixedLabel('composed', 'GenericSwitch');
|
|
273
|
+
ep.addChildDeviceType('Button1', getSupportedDeviceType('GenericSwitch'), {
|
|
274
|
+
number: EndpointNumber(6_06_1),
|
|
275
|
+
tagList: [getSemtag(SwitchesTag.On), getSemtag(CommonNumberTag.One)],
|
|
276
|
+
})
|
|
277
|
+
.createDefaultMomentarySwitchClusterServer()
|
|
278
|
+
.addRequiredClusters();
|
|
279
|
+
ep.addChildDeviceType('Button2', getSupportedDeviceType('GenericSwitch'), {
|
|
280
|
+
number: EndpointNumber(6_06_2),
|
|
281
|
+
tagList: [getSemtag(SwitchesTag.Off), getSemtag(CommonNumberTag.Two)],
|
|
282
|
+
})
|
|
283
|
+
.createDefaultMomentarySwitchClusterServer()
|
|
284
|
+
.addRequiredClusters();
|
|
285
|
+
ep.addChildDeviceType('Button3', getSupportedDeviceType('GenericSwitch'), {
|
|
286
|
+
number: EndpointNumber(6_06_3),
|
|
287
|
+
tagList: [getSemtag(SwitchesTag.Up), getSemtag(CommonNumberTag.Three)],
|
|
288
|
+
})
|
|
289
|
+
.createDefaultMomentarySwitchClusterServer()
|
|
290
|
+
.addRequiredClusters();
|
|
291
|
+
ep.addChildDeviceType('Button4', getSupportedDeviceType('GenericSwitch'), {
|
|
292
|
+
number: EndpointNumber(6_06_4),
|
|
293
|
+
tagList: [getSemtag(SwitchesTag.Down), getSemtag(CommonNumberTag.Four)],
|
|
294
|
+
})
|
|
295
|
+
.createDefaultMomentarySwitchClusterServer()
|
|
296
|
+
.addRequiredClusters();
|
|
271
297
|
await registerDevice(ep, 'Generic Switch', 'SWITCH-06-06');
|
|
272
298
|
ep = new MatterbridgeEndpoint([getSupportedDeviceType('ContactSensor'), bridgedNode, powerSource], { id: 'ContactSensor', number: EndpointNumber(7_01) });
|
|
273
299
|
ep.createDefaultPowerSourceBatteryClusterServer();
|
|
@@ -348,11 +374,15 @@ export async function createDemoDevices(matterbridge) {
|
|
|
348
374
|
await registerDevice(ep, 'Door Lock User PIN Schedules', 'ENTRY-08-01-2');
|
|
349
375
|
ep = new MatterbridgeEndpoint([getSupportedDeviceType('DoorLockController'), bridgedNode, powerSource], { id: 'DoorLockController', number: EndpointNumber(8_02) });
|
|
350
376
|
await registerDevice(ep, 'Door Lock Controller', 'ENTRY-08-02');
|
|
351
|
-
ep = new MatterbridgeEndpoint([getSupportedDeviceType('WindowCovering'), bridgedNode, powerSource], { id: '
|
|
352
|
-
|
|
377
|
+
ep = new MatterbridgeEndpoint([getSupportedDeviceType('WindowCovering'), bridgedNode, powerSource], { id: 'WindowCoveringLift', number: EndpointNumber(8_03) });
|
|
378
|
+
ep.createDefaultWindowCoveringClusterServer();
|
|
379
|
+
await registerDevice(ep, 'Window Covering Lift', 'ENTRY-08-03');
|
|
353
380
|
ep = new MatterbridgeEndpoint([getSupportedDeviceType('WindowCovering'), bridgedNode, powerSource], { id: 'WindowCoveringTilt', number: EndpointNumber(8_03_1) });
|
|
354
|
-
ep.
|
|
381
|
+
ep.createDefaultTiltWindowCoveringClusterServer();
|
|
355
382
|
await registerDevice(ep, 'Window Covering Tilt', 'ENTRY-08-03-1');
|
|
383
|
+
ep = new MatterbridgeEndpoint([getSupportedDeviceType('WindowCovering'), bridgedNode, powerSource], { id: 'WindowCoveringLiftTilt', number: EndpointNumber(8_03_2) });
|
|
384
|
+
ep.createDefaultLiftTiltWindowCoveringClusterServer();
|
|
385
|
+
await registerDevice(ep, 'Window Covering LiftTilt', 'ENTRY-08-03-2');
|
|
356
386
|
ep = new MatterbridgeEndpoint([getSupportedDeviceType('WindowCoveringController'), bridgedNode, powerSource], { id: 'WindowCoveringController', number: EndpointNumber(8_04) });
|
|
357
387
|
await registerDevice(ep, 'Window Covering Controller', 'ENTRY-08-04');
|
|
358
388
|
ep = new Closure('Closure', 'ENTRY-08-05', {
|
|
@@ -443,8 +473,9 @@ export async function createDemoDevices(matterbridge) {
|
|
|
443
473
|
await registerDevice(ep, 'Closure Panel Smart-Glass', 'ENTRY-08-06-5');
|
|
444
474
|
ep = new MatterbridgeEndpoint([getSupportedDeviceType('ClosureController'), bridgedNode, powerSource], { id: 'ClosureController', number: EndpointNumber(8_07) });
|
|
445
475
|
await registerDevice(ep, 'Closure Controller', 'ENTRY-08-07');
|
|
446
|
-
ep = new MatterbridgeEndpoint([getSupportedDeviceType('Thermostat'), bridgedNode, powerSource], { id: '
|
|
447
|
-
|
|
476
|
+
ep = new MatterbridgeEndpoint([getSupportedDeviceType('Thermostat'), bridgedNode, powerSource], { id: 'ThermostatAuto', number: EndpointNumber(9_01) });
|
|
477
|
+
ep.createDefaultThermostatClusterServer(23, 21, 25, 2, 0, 47, 3, 50);
|
|
478
|
+
await registerDevice(ep, 'Thermostat Auto', 'HVAC-09-01');
|
|
448
479
|
ep = new MatterbridgeEndpoint([getSupportedDeviceType('Thermostat'), bridgedNode, powerSource], { id: 'ThermostatHeating', number: EndpointNumber(9_01_1) });
|
|
449
480
|
ep.createDefaultHeatingThermostatClusterServer();
|
|
450
481
|
await registerDevice(ep, 'Thermostat Heating', 'HVAC-09-01-1');
|
|
@@ -458,7 +489,13 @@ export async function createDemoDevices(matterbridge) {
|
|
|
458
489
|
ep.createDefaultSchedulesThermostatClusterServer();
|
|
459
490
|
await registerDevice(ep, 'Thermostat Schedules', 'HVAC-09-01-4');
|
|
460
491
|
ep = new MatterbridgeEndpoint([getSupportedDeviceType('Thermostat'), bridgedNode, powerSource], { id: 'ThermostatSuggestions', number: EndpointNumber(9_01_5) });
|
|
461
|
-
ep.createDefaultThermostatSuggestionsClusterServer(
|
|
492
|
+
ep.createDefaultThermostatSuggestionsClusterServer(23, 21, 25, 0, 0, 50, 0, 50, undefined, undefined, undefined, undefined, null, [
|
|
493
|
+
{ presetHandle: Uint8Array.from([0]), presetScenario: Thermostat.PresetScenario.Occupied, name: 'Occupied', coolingSetpoint: 2500, heatingSetpoint: 2100, builtIn: true },
|
|
494
|
+
{ presetHandle: Uint8Array.from([1]), presetScenario: Thermostat.PresetScenario.Unoccupied, name: 'Unoccupied', coolingSetpoint: 2700, heatingSetpoint: 1900, builtIn: true },
|
|
495
|
+
], [
|
|
496
|
+
{ presetScenario: Thermostat.PresetScenario.Occupied, numberOfPresets: 4, presetTypeFeatures: { automatic: false, supportsNames: true } },
|
|
497
|
+
{ presetScenario: Thermostat.PresetScenario.Unoccupied, numberOfPresets: 4, presetTypeFeatures: { automatic: false, supportsNames: true } },
|
|
498
|
+
]);
|
|
462
499
|
await registerDevice(ep, 'Thermostat Suggestions', 'HVAC-09-01-5');
|
|
463
500
|
ep = new MatterbridgeEndpoint([getSupportedDeviceType('Fan'), bridgedNode, powerSource], { id: 'Fan', number: EndpointNumber(9_02) });
|
|
464
501
|
await registerDevice(ep, 'Fan OffLowMedHighAuto', 'HVAC-09-02');
|
|
@@ -36,6 +36,8 @@ export declare namespace MatterbridgeClosureControlServer {
|
|
|
36
36
|
movementDuration: number;
|
|
37
37
|
calibrationDuration: number;
|
|
38
38
|
signaturePosition: number;
|
|
39
|
+
ventilationPosition: number;
|
|
40
|
+
pedestrianPosition: number;
|
|
39
41
|
}
|
|
40
42
|
}
|
|
41
43
|
export interface ClosureOptions {
|
|
@@ -51,6 +53,8 @@ export interface ClosureOptions {
|
|
|
51
53
|
movementDuration?: number;
|
|
52
54
|
calibrationDuration?: number;
|
|
53
55
|
signaturePosition?: number;
|
|
56
|
+
ventilationPosition?: number;
|
|
57
|
+
pedestrianPosition?: number;
|
|
54
58
|
motionLatching?: boolean;
|
|
55
59
|
speed?: boolean;
|
|
56
60
|
ventilation?: boolean;
|
|
@@ -64,10 +68,17 @@ export declare class Closure extends MatterbridgeEndpoint {
|
|
|
64
68
|
constructor(name: string, serial: string, options?: ClosureOptions);
|
|
65
69
|
getMainState(): ClosureControl.MainState | undefined;
|
|
66
70
|
getSignaturePosition(): number | undefined;
|
|
71
|
+
getVentilationPosition(): number | undefined;
|
|
72
|
+
getPedestrianPosition(): number | undefined;
|
|
67
73
|
setState(currentState: ClosureControl.OverallCurrentState, targetState: ClosureControl.OverallTargetState, mainState?: ClosureControl.MainState, countdownTime?: number, currentErrorList?: ClosureControl.ClosureError[]): Promise<void>;
|
|
68
74
|
setFullyClosed(): Promise<void>;
|
|
69
75
|
setFullOpened(): Promise<void>;
|
|
70
76
|
setPartiallyOpened(): Promise<void>;
|
|
77
|
+
setOpenedAtSignature(): Promise<void>;
|
|
78
|
+
setOpenedForVentilation(): Promise<void>;
|
|
79
|
+
setOpenedForPedestrian(): Promise<void>;
|
|
80
|
+
targetPositionToCurrentPosition(position: ClosureControl.TargetPosition): ClosureControl.CurrentPosition;
|
|
81
|
+
targetPositionToTargetPercent(position: ClosureControl.TargetPosition): number;
|
|
71
82
|
triggerOperationalError(errorState?: ClosureControl.ClosureError[]): Promise<void>;
|
|
72
83
|
triggerMovementCompleted(): Promise<void>;
|
|
73
84
|
triggerSecureStateChanged(secureValue: boolean): Promise<void>;
|
package/dist/devices/closure.js
CHANGED
|
@@ -175,12 +175,14 @@ export class MatterbridgeClosureControlServer extends MatterbridgeClosureControl
|
|
|
175
175
|
movementDuration = 0;
|
|
176
176
|
calibrationDuration = 0;
|
|
177
177
|
signaturePosition = 50_00;
|
|
178
|
+
ventilationPosition = 50_00;
|
|
179
|
+
pedestrianPosition = 50_00;
|
|
178
180
|
}
|
|
179
181
|
MatterbridgeClosureControlServer.State = State;
|
|
180
182
|
})(MatterbridgeClosureControlServer || (MatterbridgeClosureControlServer = {}));
|
|
181
183
|
export class Closure extends MatterbridgeEndpoint {
|
|
182
184
|
constructor(name, serial, options = {}) {
|
|
183
|
-
const { identifyTime = 0, identifyType = Identify.IdentifyType.None, powerSourceType = 'Wired', countdownTime = 0, mainState = ClosureControl.MainState.Stopped, currentErrorList = [], overallCurrentState, overallTargetState, latchControlModes, movementDuration = 0, calibrationDuration = 0, signaturePosition = 50_00, motionLatching = false, speed = false, ventilation = false, pedestrian = false, calibration = false, id, number, tagList = [getSemtag(ClosureTag.Covering)], } = options;
|
|
185
|
+
const { identifyTime = 0, identifyType = Identify.IdentifyType.None, powerSourceType = 'Wired', countdownTime = 0, mainState = ClosureControl.MainState.Stopped, currentErrorList = [], overallCurrentState, overallTargetState, latchControlModes, movementDuration = 0, calibrationDuration = 0, signaturePosition = 50_00, ventilationPosition = 50_00, pedestrianPosition = 50_00, motionLatching = false, speed = false, ventilation = false, pedestrian = false, calibration = false, id, number, tagList = [getSemtag(ClosureTag.Covering)], } = options;
|
|
184
186
|
super(powerSourceType === 'None' ? [closure] : [closure, powerSource], {
|
|
185
187
|
id: id ?? `${name.replaceAll(' ', '')}-${serial.replaceAll(' ', '')}`,
|
|
186
188
|
number,
|
|
@@ -223,6 +225,8 @@ export class Closure extends MatterbridgeEndpoint {
|
|
|
223
225
|
movementDuration,
|
|
224
226
|
calibrationDuration,
|
|
225
227
|
signaturePosition,
|
|
228
|
+
ventilationPosition,
|
|
229
|
+
pedestrianPosition,
|
|
226
230
|
};
|
|
227
231
|
this.behaviors.require(MatterbridgeClosureControlServer.with(ClosureControl.Feature.Positioning, ...(motionLatching ? [ClosureControl.Feature.MotionLatching] : []), ...(speed ? [ClosureControl.Feature.Speed] : []), ...(calibration ? [ClosureControl.Feature.Calibration] : []), ...(ventilation ? [ClosureControl.Feature.Ventilation] : []), ...(pedestrian ? [ClosureControl.Feature.Pedestrian] : [])), closureControlOptions);
|
|
228
232
|
}
|
|
@@ -232,23 +236,31 @@ export class Closure extends MatterbridgeEndpoint {
|
|
|
232
236
|
getSignaturePosition() {
|
|
233
237
|
return this.getAttribute(MatterbridgeClosureControlServer, 'signaturePosition');
|
|
234
238
|
}
|
|
239
|
+
getVentilationPosition() {
|
|
240
|
+
return this.getAttribute(MatterbridgeClosureControlServer, 'ventilationPosition');
|
|
241
|
+
}
|
|
242
|
+
getPedestrianPosition() {
|
|
243
|
+
return this.getAttribute(MatterbridgeClosureControlServer, 'pedestrianPosition');
|
|
244
|
+
}
|
|
235
245
|
async setState(currentState, targetState, mainState = ClosureControl.MainState.Stopped, countdownTime = 0, currentErrorList = []) {
|
|
236
|
-
const
|
|
237
|
-
const
|
|
238
|
-
|
|
246
|
+
const features = this.featuresOf(MatterbridgeClosureControlServer.id);
|
|
247
|
+
const supportsCurrentPosition = (currentState.position !== ClosureControl.CurrentPosition.OpenedForVentilation || features.ventilation) &&
|
|
248
|
+
(currentState.position !== ClosureControl.CurrentPosition.OpenedForPedestrian || features.pedestrian);
|
|
249
|
+
const supportsTargetPosition = (targetState.position !== ClosureControl.TargetPosition.MoveToVentilationPosition || features.ventilation) &&
|
|
250
|
+
(targetState.position !== ClosureControl.TargetPosition.MoveToPedestrianPosition || features.pedestrian);
|
|
239
251
|
await this.setAttribute(ClosureControl, 'countdownTime', countdownTime);
|
|
240
252
|
await this.setAttribute(ClosureControl, 'mainState', mainState);
|
|
241
253
|
await this.setAttribute(ClosureControl, 'currentErrorList', currentErrorList);
|
|
242
254
|
await this.setAttribute(ClosureControl, 'overallCurrentState', {
|
|
243
|
-
position: currentState.position,
|
|
244
|
-
...(
|
|
245
|
-
...(
|
|
255
|
+
...(supportsCurrentPosition ? { position: currentState.position } : null),
|
|
256
|
+
...(features.motionLatching ? { latch: currentState.latch } : null),
|
|
257
|
+
...(features.speed ? { speed: currentState.speed } : null),
|
|
246
258
|
secureState: currentState.secureState,
|
|
247
259
|
});
|
|
248
260
|
await this.setAttribute(ClosureControl, 'overallTargetState', {
|
|
249
|
-
position: targetState.position,
|
|
250
|
-
...(
|
|
251
|
-
...(
|
|
261
|
+
...(supportsTargetPosition ? { position: targetState.position } : null),
|
|
262
|
+
...(features.motionLatching ? { latch: targetState.latch } : null),
|
|
263
|
+
...(features.speed ? { speed: targetState.speed } : null),
|
|
252
264
|
});
|
|
253
265
|
}
|
|
254
266
|
async setFullyClosed() {
|
|
@@ -287,6 +299,64 @@ export class Closure extends MatterbridgeEndpoint {
|
|
|
287
299
|
speed: ThreeLevelAuto.Auto,
|
|
288
300
|
});
|
|
289
301
|
}
|
|
302
|
+
async setOpenedAtSignature() {
|
|
303
|
+
await this.setState({
|
|
304
|
+
position: ClosureControl.CurrentPosition.OpenedAtSignature,
|
|
305
|
+
latch: false,
|
|
306
|
+
speed: ThreeLevelAuto.Auto,
|
|
307
|
+
secureState: false,
|
|
308
|
+
}, {
|
|
309
|
+
position: ClosureControl.TargetPosition.MoveToSignaturePosition,
|
|
310
|
+
latch: false,
|
|
311
|
+
speed: ThreeLevelAuto.Auto,
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
async setOpenedForVentilation() {
|
|
315
|
+
await this.setState({
|
|
316
|
+
position: ClosureControl.CurrentPosition.OpenedForVentilation,
|
|
317
|
+
latch: false,
|
|
318
|
+
speed: ThreeLevelAuto.Auto,
|
|
319
|
+
secureState: false,
|
|
320
|
+
}, {
|
|
321
|
+
position: ClosureControl.TargetPosition.MoveToVentilationPosition,
|
|
322
|
+
latch: false,
|
|
323
|
+
speed: ThreeLevelAuto.Auto,
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
async setOpenedForPedestrian() {
|
|
327
|
+
await this.setState({
|
|
328
|
+
position: ClosureControl.CurrentPosition.OpenedForPedestrian,
|
|
329
|
+
latch: false,
|
|
330
|
+
speed: ThreeLevelAuto.Auto,
|
|
331
|
+
secureState: false,
|
|
332
|
+
}, {
|
|
333
|
+
position: ClosureControl.TargetPosition.MoveToPedestrianPosition,
|
|
334
|
+
latch: false,
|
|
335
|
+
speed: ThreeLevelAuto.Auto,
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
targetPositionToCurrentPosition(position) {
|
|
339
|
+
if (position === ClosureControl.TargetPosition.MoveToFullyClosed)
|
|
340
|
+
return ClosureControl.CurrentPosition.FullyClosed;
|
|
341
|
+
if (position === ClosureControl.TargetPosition.MoveToFullyOpen)
|
|
342
|
+
return ClosureControl.CurrentPosition.FullyOpened;
|
|
343
|
+
if (position === ClosureControl.TargetPosition.MoveToPedestrianPosition)
|
|
344
|
+
return ClosureControl.CurrentPosition.OpenedForPedestrian;
|
|
345
|
+
if (position === ClosureControl.TargetPosition.MoveToVentilationPosition)
|
|
346
|
+
return ClosureControl.CurrentPosition.OpenedForVentilation;
|
|
347
|
+
return ClosureControl.CurrentPosition.OpenedAtSignature;
|
|
348
|
+
}
|
|
349
|
+
targetPositionToTargetPercent(position) {
|
|
350
|
+
if (position === ClosureControl.TargetPosition.MoveToFullyOpen)
|
|
351
|
+
return 0;
|
|
352
|
+
if (position === ClosureControl.TargetPosition.MoveToFullyClosed)
|
|
353
|
+
return 100_00;
|
|
354
|
+
if (position === ClosureControl.TargetPosition.MoveToPedestrianPosition)
|
|
355
|
+
return this.getPedestrianPosition() ?? 50_00;
|
|
356
|
+
if (position === ClosureControl.TargetPosition.MoveToVentilationPosition)
|
|
357
|
+
return this.getVentilationPosition() ?? 50_00;
|
|
358
|
+
return this.getSignaturePosition() ?? 50_00;
|
|
359
|
+
}
|
|
290
360
|
async triggerOperationalError(errorState = []) {
|
|
291
361
|
await this.setAttribute(ClosureControl, 'mainState', ClosureControl.MainState.Error);
|
|
292
362
|
await this.setAttribute(ClosureControl, 'currentErrorList', errorState);
|
|
@@ -62,6 +62,21 @@ export interface ElectricalEnergyTariffOptions {
|
|
|
62
62
|
currentPrice?: CommodityPrice.CommodityPriceStruct | null;
|
|
63
63
|
localGenerationAvailable?: boolean | null;
|
|
64
64
|
currentConditions?: ElectricalGridConditions.ElectricalGridConditionsStruct | null;
|
|
65
|
+
startDate?: number | null;
|
|
66
|
+
dayEntries?: CommodityTariff.DayEntry[] | null;
|
|
67
|
+
dayPatterns?: CommodityTariff.DayPattern[] | null;
|
|
68
|
+
calendarPeriods?: CommodityTariff.CalendarPeriod[] | null;
|
|
69
|
+
individualDays?: CommodityTariff.Day[] | null;
|
|
70
|
+
currentDay?: CommodityTariff.Day | null;
|
|
71
|
+
nextDay?: CommodityTariff.Day | null;
|
|
72
|
+
currentDayEntry?: CommodityTariff.DayEntry | null;
|
|
73
|
+
currentDayEntryDate?: number | null;
|
|
74
|
+
nextDayEntry?: CommodityTariff.DayEntry | null;
|
|
75
|
+
nextDayEntryDate?: number | null;
|
|
76
|
+
tariffComponents?: CommodityTariff.TariffComponent[] | null;
|
|
77
|
+
tariffPeriods?: CommodityTariff.TariffPeriod[] | null;
|
|
78
|
+
currentTariffComponents?: CommodityTariff.TariffComponent[] | null;
|
|
79
|
+
nextTariffComponents?: CommodityTariff.TariffComponent[] | null;
|
|
65
80
|
tagList?: Semtag[];
|
|
66
81
|
}
|
|
67
82
|
export declare class ElectricalUtilityMeter extends MatterbridgeEndpoint {
|
|
@@ -106,7 +106,7 @@ export class ElectricalUtilityMeter extends MatterbridgeEndpoint {
|
|
|
106
106
|
return tariff;
|
|
107
107
|
}
|
|
108
108
|
configureElectricalEnergyTariffClusters(endpoint, options) {
|
|
109
|
-
const { tariffLabel = null, providerName = null, tariffUnit = TariffUnit.KWh, currency = null, currentPrice = null, localGenerationAvailable = null, currentConditions = null, } = options;
|
|
109
|
+
const { tariffLabel = null, providerName = null, tariffUnit = TariffUnit.KWh, currency = null, currentPrice = null, localGenerationAvailable = null, currentConditions = null, startDate = null, dayEntries = null, dayPatterns = null, calendarPeriods = null, individualDays = null, currentDay = null, nextDay = null, currentDayEntry = null, currentDayEntryDate = null, nextDayEntry = null, nextDayEntryDate = null, tariffComponents = null, tariffPeriods = null, currentTariffComponents = null, nextTariffComponents = null, } = options;
|
|
110
110
|
endpoint.behaviors.require(MatterbridgeCommodityPriceServer, {
|
|
111
111
|
tariffUnit,
|
|
112
112
|
currency,
|
|
@@ -125,21 +125,21 @@ export class ElectricalUtilityMeter extends MatterbridgeEndpoint {
|
|
|
125
125
|
endpoint.behaviors.require(MatterbridgeCommodityTariffServer, {
|
|
126
126
|
tariffInfo,
|
|
127
127
|
tariffUnit: tariffInfo === null ? null : tariffUnit,
|
|
128
|
-
startDate: null,
|
|
129
|
-
dayEntries: null,
|
|
130
|
-
dayPatterns: null,
|
|
131
|
-
calendarPeriods: null,
|
|
132
|
-
individualDays: null,
|
|
133
|
-
tariffComponents: null,
|
|
134
|
-
tariffPeriods: null,
|
|
135
|
-
currentDay: null,
|
|
136
|
-
nextDay: null,
|
|
137
|
-
currentDayEntry: null,
|
|
138
|
-
currentDayEntryDate: null,
|
|
139
|
-
nextDayEntry: null,
|
|
140
|
-
nextDayEntryDate: null,
|
|
141
|
-
currentTariffComponents: null,
|
|
142
|
-
nextTariffComponents: null,
|
|
128
|
+
startDate: tariffInfo === null ? null : startDate,
|
|
129
|
+
dayEntries: tariffInfo === null ? null : dayEntries,
|
|
130
|
+
dayPatterns: tariffInfo === null ? null : dayPatterns,
|
|
131
|
+
calendarPeriods: tariffInfo === null ? null : calendarPeriods,
|
|
132
|
+
individualDays: tariffInfo === null ? null : individualDays,
|
|
133
|
+
tariffComponents: tariffInfo === null ? null : tariffComponents,
|
|
134
|
+
tariffPeriods: tariffInfo === null ? null : tariffPeriods,
|
|
135
|
+
currentDay: tariffInfo === null ? null : currentDay,
|
|
136
|
+
nextDay: tariffInfo === null ? null : nextDay,
|
|
137
|
+
currentDayEntry: tariffInfo === null ? null : currentDayEntry,
|
|
138
|
+
currentDayEntryDate: tariffInfo === null ? null : currentDayEntryDate,
|
|
139
|
+
nextDayEntry: tariffInfo === null ? null : nextDayEntry,
|
|
140
|
+
nextDayEntryDate: tariffInfo === null ? null : nextDayEntryDate,
|
|
141
|
+
currentTariffComponents: tariffInfo === null ? null : currentTariffComponents,
|
|
142
|
+
nextTariffComponents: tariffInfo === null ? null : nextTariffComponents,
|
|
143
143
|
});
|
|
144
144
|
endpoint.behaviors.require(ElectricalGridConditionsServer, { localGenerationAvailable, currentConditions });
|
|
145
145
|
}
|
package/dist/matterNode.js
CHANGED
|
@@ -407,7 +407,16 @@ export class MatterNode extends EventEmitter {
|
|
|
407
407
|
this.log.warn(`Invalid discriminator ${discriminator} for server node ${storeId}. Discriminator must be between 0 and 4095 (0xFFF). Generating a random discriminator...`);
|
|
408
408
|
discriminator = PaseClient.generateRandomDiscriminator(this.environment.get(Crypto));
|
|
409
409
|
}
|
|
410
|
-
|
|
410
|
+
let rootEndpoint;
|
|
411
|
+
if (hasParameter('root-power-source') || process.env.MATTERBRIDGE_CHIP_TEST) {
|
|
412
|
+
this.log.warn(' ****************************************************************************************');
|
|
413
|
+
this.log.warn(' * Adding the PowerSource cluster server to the root endpoint. *');
|
|
414
|
+
this.log.warn(' ****************************************************************************************');
|
|
415
|
+
rootEndpoint = ServerNode.RootEndpoint.with(PowerSourceServer.with(PowerSource.Feature.Wired));
|
|
416
|
+
}
|
|
417
|
+
else {
|
|
418
|
+
rootEndpoint = ServerNode.RootEndpoint;
|
|
419
|
+
}
|
|
411
420
|
const serverNode = await ServerNode.create(rootEndpoint, {
|
|
412
421
|
id: storeId,
|
|
413
422
|
environment: this.environment,
|
package/dist/matterbridge.js
CHANGED
|
@@ -1893,7 +1893,16 @@ export class Matterbridge extends EventEmitter {
|
|
|
1893
1893
|
this.log.warn(`Invalid discriminator ${discriminator} for server node ${storeId}. Discriminator must be between 0 and 4095 (0xFFF). Generating a random discriminator...`);
|
|
1894
1894
|
discriminator = PaseClient.generateRandomDiscriminator(this.environment.get(Crypto));
|
|
1895
1895
|
}
|
|
1896
|
-
let rootEndpoint
|
|
1896
|
+
let rootEndpoint;
|
|
1897
|
+
if (hasParameter('root-power-source') || process.env.MATTERBRIDGE_CHIP_TEST) {
|
|
1898
|
+
this.log.warn(' ****************************************************************************************');
|
|
1899
|
+
this.log.warn(' * Adding the PowerSource cluster server to the root endpoint. *');
|
|
1900
|
+
this.log.warn(' ****************************************************************************************');
|
|
1901
|
+
rootEndpoint = ServerNode.RootEndpoint.with(PowerSourceServer.with(PowerSource.Feature.Wired));
|
|
1902
|
+
}
|
|
1903
|
+
else {
|
|
1904
|
+
rootEndpoint = ServerNode.RootEndpoint;
|
|
1905
|
+
}
|
|
1897
1906
|
if (process.env.MATTERBRIDGE_CHIP_TEST && fs.existsSync(path.join(path.dirname(fileURLToPath(import.meta.url)), 'chipTests.js'))) {
|
|
1898
1907
|
this.log.warn(' ****************************************************************************************');
|
|
1899
1908
|
this.log.warn(' * MATTERBRIDGE_CHIP_TEST environment variable is set. Running TestEventTrigger server. *');
|
|
@@ -171,8 +171,9 @@ export declare class MatterbridgeEndpoint extends Endpoint {
|
|
|
171
171
|
createCtColorControlClusterServer(colorTemperatureMireds?: number, colorTempPhysicalMinMireds?: number, colorTempPhysicalMaxMireds?: number): this;
|
|
172
172
|
configureColorControlMode(colorMode: ColorControl.ColorMode): Promise<void>;
|
|
173
173
|
configureEnhancedColorControlMode(colorMode: ColorControl.EnhancedColorMode): Promise<void>;
|
|
174
|
-
createDefaultWindowCoveringClusterServer(positionPercent100ths?: number, type?: WindowCovering.WindowCoveringType, endProductType?: WindowCovering.EndProductType): this;
|
|
175
|
-
createDefaultLiftTiltWindowCoveringClusterServer(positionLiftPercent100ths?: number, positionTiltPercent100ths?: number, type?: WindowCovering.WindowCoveringType, endProductType?: WindowCovering.EndProductType): this;
|
|
174
|
+
createDefaultWindowCoveringClusterServer(positionPercent100ths?: number | null, type?: WindowCovering.WindowCoveringType, endProductType?: WindowCovering.EndProductType, movementDuration?: number): this;
|
|
175
|
+
createDefaultLiftTiltWindowCoveringClusterServer(positionLiftPercent100ths?: number | null, positionTiltPercent100ths?: number | null, type?: WindowCovering.WindowCoveringType, endProductType?: WindowCovering.EndProductType, movementDuration?: number): this;
|
|
176
|
+
createDefaultTiltWindowCoveringClusterServer(positionTiltPercent100ths?: number | null, type?: WindowCovering.WindowCoveringType, endProductType?: WindowCovering.EndProductType, movementDuration?: number): this;
|
|
176
177
|
setWindowCoveringTargetAsCurrentAndStopped(): Promise<void>;
|
|
177
178
|
setWindowCoveringCurrentTargetStatus(current: number, target: number, status: WindowCovering.MovementStatus): Promise<void>;
|
|
178
179
|
setWindowCoveringStatus(status: WindowCovering.MovementStatus): Promise<void>;
|
|
@@ -825,7 +825,7 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
825
825
|
await this.setAttribute(ColorControl.id, 'enhancedColorMode', colorMode, this.log);
|
|
826
826
|
}
|
|
827
827
|
}
|
|
828
|
-
createDefaultWindowCoveringClusterServer(positionPercent100ths, type = WindowCovering.WindowCoveringType.Rollershade, endProductType = WindowCovering.EndProductType.RollerShade) {
|
|
828
|
+
createDefaultWindowCoveringClusterServer(positionPercent100ths = 0, type = WindowCovering.WindowCoveringType.Rollershade, endProductType = WindowCovering.EndProductType.RollerShade, movementDuration = 0) {
|
|
829
829
|
this.behaviors.require(MatterbridgeWindowCoveringServer.with(WindowCovering.Feature.Lift, WindowCovering.Feature.PositionAwareLift), {
|
|
830
830
|
type,
|
|
831
831
|
numberOfActuationsLift: 0,
|
|
@@ -841,12 +841,14 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
841
841
|
operationalStatus: { global: WindowCovering.MovementStatus.Stopped, lift: WindowCovering.MovementStatus.Stopped, tilt: WindowCovering.MovementStatus.Stopped },
|
|
842
842
|
endProductType,
|
|
843
843
|
mode: { motorDirectionReversed: false, calibrationMode: false, maintenanceMode: false, ledFeedback: false },
|
|
844
|
-
targetPositionLiftPercent100ths: positionPercent100ths
|
|
845
|
-
currentPositionLiftPercent100ths: positionPercent100ths
|
|
844
|
+
targetPositionLiftPercent100ths: positionPercent100ths,
|
|
845
|
+
currentPositionLiftPercent100ths: positionPercent100ths,
|
|
846
|
+
currentPositionLiftPercentage: positionPercent100ths === null ? null : Math.floor(positionPercent100ths / 100),
|
|
847
|
+
movementDuration,
|
|
846
848
|
});
|
|
847
849
|
return this;
|
|
848
850
|
}
|
|
849
|
-
createDefaultLiftTiltWindowCoveringClusterServer(positionLiftPercent100ths, positionTiltPercent100ths, type = WindowCovering.WindowCoveringType.TiltBlindLift, endProductType = WindowCovering.EndProductType.InteriorBlind) {
|
|
851
|
+
createDefaultLiftTiltWindowCoveringClusterServer(positionLiftPercent100ths = 0, positionTiltPercent100ths = 0, type = WindowCovering.WindowCoveringType.TiltBlindLift, endProductType = WindowCovering.EndProductType.InteriorBlind, movementDuration = 0) {
|
|
850
852
|
this.behaviors.require(MatterbridgeWindowCoveringServer.with(WindowCovering.Feature.Lift, WindowCovering.Feature.PositionAwareLift, WindowCovering.Feature.Tilt, WindowCovering.Feature.PositionAwareTilt), {
|
|
851
853
|
type,
|
|
852
854
|
numberOfActuationsLift: 0,
|
|
@@ -863,10 +865,36 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
863
865
|
operationalStatus: { global: WindowCovering.MovementStatus.Stopped, lift: WindowCovering.MovementStatus.Stopped, tilt: WindowCovering.MovementStatus.Stopped },
|
|
864
866
|
endProductType,
|
|
865
867
|
mode: { motorDirectionReversed: false, calibrationMode: false, maintenanceMode: false, ledFeedback: false },
|
|
866
|
-
targetPositionLiftPercent100ths: positionLiftPercent100ths
|
|
867
|
-
currentPositionLiftPercent100ths: positionLiftPercent100ths
|
|
868
|
-
|
|
869
|
-
|
|
868
|
+
targetPositionLiftPercent100ths: positionLiftPercent100ths,
|
|
869
|
+
currentPositionLiftPercent100ths: positionLiftPercent100ths,
|
|
870
|
+
currentPositionLiftPercentage: positionLiftPercent100ths === null ? null : Math.floor(positionLiftPercent100ths / 100),
|
|
871
|
+
targetPositionTiltPercent100ths: positionTiltPercent100ths,
|
|
872
|
+
currentPositionTiltPercent100ths: positionTiltPercent100ths,
|
|
873
|
+
currentPositionTiltPercentage: positionTiltPercent100ths === null ? null : Math.floor(positionTiltPercent100ths / 100),
|
|
874
|
+
movementDuration,
|
|
875
|
+
});
|
|
876
|
+
return this;
|
|
877
|
+
}
|
|
878
|
+
createDefaultTiltWindowCoveringClusterServer(positionTiltPercent100ths = 0, type = WindowCovering.WindowCoveringType.TiltBlindTiltOnly, endProductType = WindowCovering.EndProductType.InteriorVenetianBlind, movementDuration = 0) {
|
|
879
|
+
this.behaviors.require(MatterbridgeWindowCoveringServer.with(WindowCovering.Feature.Tilt, WindowCovering.Feature.PositionAwareTilt), {
|
|
880
|
+
type,
|
|
881
|
+
numberOfActuationsTilt: 0,
|
|
882
|
+
configStatus: {
|
|
883
|
+
operational: true,
|
|
884
|
+
onlineReserved: false,
|
|
885
|
+
liftMovementReversed: false,
|
|
886
|
+
liftPositionAware: false,
|
|
887
|
+
tiltPositionAware: true,
|
|
888
|
+
liftEncoderControlled: false,
|
|
889
|
+
tiltEncoderControlled: false,
|
|
890
|
+
},
|
|
891
|
+
operationalStatus: { global: WindowCovering.MovementStatus.Stopped, lift: WindowCovering.MovementStatus.Stopped, tilt: WindowCovering.MovementStatus.Stopped },
|
|
892
|
+
endProductType,
|
|
893
|
+
mode: { motorDirectionReversed: false, calibrationMode: false, maintenanceMode: false, ledFeedback: false },
|
|
894
|
+
targetPositionTiltPercent100ths: positionTiltPercent100ths,
|
|
895
|
+
currentPositionTiltPercent100ths: positionTiltPercent100ths,
|
|
896
|
+
currentPositionTiltPercentage: positionTiltPercent100ths === null ? null : Math.floor(positionTiltPercent100ths / 100),
|
|
897
|
+
movementDuration,
|
|
870
898
|
});
|
|
871
899
|
return this;
|
|
872
900
|
}
|
|
@@ -208,7 +208,7 @@ export function featuresFor(endpoint, cluster) {
|
|
|
208
208
|
const supportedBehavior = endpoint.behaviors.supported[lowercaseFirstLetter(behaviorId)];
|
|
209
209
|
if (!supportedBehavior || !ClusterBehavior.isType(supportedBehavior))
|
|
210
210
|
return {};
|
|
211
|
-
return supportedBehavior.features
|
|
211
|
+
return supportedBehavior.features;
|
|
212
212
|
}
|
|
213
213
|
export async function internalFor(endpoint, cluster) {
|
|
214
214
|
const behaviorId = getBehavior(endpoint, cluster)?.id;
|
|
@@ -9,4 +9,5 @@ export declare function snakeCase(name: string): string;
|
|
|
9
9
|
export declare function pascalCase(name: string): string;
|
|
10
10
|
export declare function camelCase(name: string): string;
|
|
11
11
|
export declare function getServerBehaviorFromClusterId(clusterId: ClusterId, features?: Record<string, boolean> | string[]): Promise<Behavior.Type | undefined>;
|
|
12
|
+
export declare function getClientBehaviorFromClusterId(clusterId: ClusterId): Promise<Behavior.Type | undefined>;
|
|
12
13
|
export declare function createClusterServer(endpoint: MatterbridgeEndpoint, clusterId: ClusterId, options?: CreateClusterServerOptions): Promise<MatterbridgeEndpoint>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ClusterBehavior } from '@matter/node';
|
|
1
|
+
import { ClusterBehavior, isClientBehavior } from '@matter/node';
|
|
2
2
|
import { getClusterNameById } from '@matter/types/cluster';
|
|
3
3
|
import { logModuleLoaded } from '@matterbridge/utils/loader';
|
|
4
4
|
import { db, hk } from 'node-ansi-logger';
|
|
@@ -44,7 +44,7 @@ export async function getServerBehaviorFromClusterId(clusterId, features) {
|
|
|
44
44
|
return undefined;
|
|
45
45
|
}
|
|
46
46
|
const base = mod[`${name}Server`];
|
|
47
|
-
if (!base || !ClusterBehavior.isType(base))
|
|
47
|
+
if (!base || !ClusterBehavior.isType(base) || isClientBehavior(base))
|
|
48
48
|
return undefined;
|
|
49
49
|
const featureNames = (Array.isArray(features)
|
|
50
50
|
? features
|
|
@@ -53,6 +53,22 @@ export async function getServerBehaviorFromClusterId(clusterId, features) {
|
|
|
53
53
|
.map(([key]) => key)).map((key) => pascalCase(key));
|
|
54
54
|
return featureNames.length > 0 ? base.with(...featureNames) : base;
|
|
55
55
|
}
|
|
56
|
+
export async function getClientBehaviorFromClusterId(clusterId) {
|
|
57
|
+
const name = getClusterNameById(clusterId);
|
|
58
|
+
if (name.includes('Unknown cluster'))
|
|
59
|
+
return undefined;
|
|
60
|
+
let mod;
|
|
61
|
+
try {
|
|
62
|
+
mod = (await import(`@matter/node/behaviors/${snakeCase(name)}`));
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
const base = mod[`${name}Client`];
|
|
68
|
+
if (!base || !ClusterBehavior.isType(base) || !isClientBehavior(base))
|
|
69
|
+
return undefined;
|
|
70
|
+
return base;
|
|
71
|
+
}
|
|
56
72
|
export async function createClusterServer(endpoint, clusterId, options) {
|
|
57
73
|
const type = await getServerBehaviorFromClusterId(clusterId, options?.features);
|
|
58
74
|
if (!type) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@matterbridge/core",
|
|
3
|
-
"version": "3.10.8-dev-
|
|
3
|
+
"version": "3.10.8-dev-20260901-971f7bf",
|
|
4
4
|
"description": "Matterbridge core library",
|
|
5
5
|
"author": "https://github.com/Luligu",
|
|
6
6
|
"homepage": "https://matterbridge.io/",
|
|
@@ -132,10 +132,10 @@
|
|
|
132
132
|
},
|
|
133
133
|
"dependencies": {
|
|
134
134
|
"@matter/main": "0.17.9",
|
|
135
|
-
"@matterbridge/dgram": "3.10.8-dev-
|
|
136
|
-
"@matterbridge/thread": "3.10.8-dev-
|
|
137
|
-
"@matterbridge/types": "3.10.8-dev-
|
|
138
|
-
"@matterbridge/utils": "3.10.8-dev-
|
|
135
|
+
"@matterbridge/dgram": "3.10.8-dev-20260901-971f7bf",
|
|
136
|
+
"@matterbridge/thread": "3.10.8-dev-20260901-971f7bf",
|
|
137
|
+
"@matterbridge/types": "3.10.8-dev-20260901-971f7bf",
|
|
138
|
+
"@matterbridge/utils": "3.10.8-dev-20260901-971f7bf",
|
|
139
139
|
"escape-html": "1.0.3",
|
|
140
140
|
"express": "5.2.1",
|
|
141
141
|
"express-rate-limit": "8.7.0",
|