@matterbridge/core 3.10.6 → 3.10.7-dev-20260823-f911eb8
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/colorControlServer.d.ts +2 -0
- package/dist/behaviors/colorControlServer.js +77 -0
- package/dist/behaviors/levelControlServer.d.ts +2 -0
- package/dist/behaviors/levelControlServer.js +37 -0
- package/dist/behaviors/onOffServer.js +66 -54
- package/dist/chipTests.js +53 -0
- package/dist/demoDevices.js +44 -3
- package/dist/devices/closure.d.ts +23 -3
- package/dist/devices/closure.js +109 -4
- package/dist/frontend.js +3 -1
- package/dist/matterbridgeEndpointCommandHandler.d.ts +7 -0
- package/package.json +5 -5
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { MaybePromise } from '@matter/general';
|
|
1
2
|
import { ColorControlServer } from '@matter/node/behaviors/color-control';
|
|
2
3
|
import { ColorControl } from '@matter/types/clusters/color-control';
|
|
3
4
|
declare const MatterbridgeColorControlServer_base: import("@matter/node").ClusterBehavior.Type<typeof ColorControlServer, import("@matter/types").ClusterType.WithSupportedFeatures<ColorControl, {
|
|
@@ -8,6 +9,7 @@ declare const MatterbridgeColorControlServer_base: import("@matter/node").Cluste
|
|
|
8
9
|
xy: true;
|
|
9
10
|
}>, import("@matter/types").ClusterType.Concrete, typeof import("@matter/node/behaviors/color-control").ColorControlBaseServer.Internal, "colorControl">;
|
|
10
11
|
export declare class MatterbridgeColorControlServer extends MatterbridgeColorControlServer_base {
|
|
12
|
+
initialize(): MaybePromise;
|
|
11
13
|
moveToHue(request: ColorControl.MoveToHueRequest): Promise<void>;
|
|
12
14
|
moveHue(request: ColorControl.MoveHueRequest): Promise<void>;
|
|
13
15
|
stepHue(request: ColorControl.StepHueRequest): Promise<void>;
|
|
@@ -2,9 +2,18 @@ import { ColorControlServer } from '@matter/node/behaviors/color-control';
|
|
|
2
2
|
import { ColorControl } from '@matter/types/clusters/color-control';
|
|
3
3
|
import { MatterbridgeServer } from './matterbridgeServer.js';
|
|
4
4
|
export class MatterbridgeColorControlServer extends ColorControlServer.with(ColorControl.Feature.HueSaturation, ColorControl.Feature.Xy, ColorControl.Feature.ColorTemperature, ColorControl.Feature.EnhancedHue) {
|
|
5
|
+
initialize() {
|
|
6
|
+
if (process.env.MATTERBRIDGE_CHIP_TEST)
|
|
7
|
+
this.state.managedTransitionTimeHandling = true;
|
|
8
|
+
return super.initialize();
|
|
9
|
+
}
|
|
5
10
|
async moveToHue(request) {
|
|
6
11
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
7
12
|
device.log.info(`Setting hue to ${request.hue} with transitionTime ${request.transitionTime} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
13
|
+
if (process.env.MATTERBRIDGE_CHIP_TEST) {
|
|
14
|
+
await super.moveToHue(request);
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
8
17
|
await device.commandHandler.executeHandler('ColorControl.moveToHue', {
|
|
9
18
|
command: 'moveToHue',
|
|
10
19
|
request,
|
|
@@ -19,6 +28,10 @@ export class MatterbridgeColorControlServer extends ColorControlServer.with(Colo
|
|
|
19
28
|
async moveHue(request) {
|
|
20
29
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
21
30
|
device.log.info(`Moving hue with mode ${request.moveMode} and rate ${request.rate} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
31
|
+
if (process.env.MATTERBRIDGE_CHIP_TEST) {
|
|
32
|
+
await super.moveHue(request);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
22
35
|
await device.commandHandler.executeHandler('ColorControl.moveHue', {
|
|
23
36
|
command: 'moveHue',
|
|
24
37
|
request,
|
|
@@ -33,6 +46,10 @@ export class MatterbridgeColorControlServer extends ColorControlServer.with(Colo
|
|
|
33
46
|
async stepHue(request) {
|
|
34
47
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
35
48
|
device.log.info(`Stepping hue with mode ${request.stepMode} and size ${request.stepSize} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
49
|
+
if (process.env.MATTERBRIDGE_CHIP_TEST) {
|
|
50
|
+
await super.stepHue(request);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
36
53
|
await device.commandHandler.executeHandler('ColorControl.stepHue', {
|
|
37
54
|
command: 'stepHue',
|
|
38
55
|
request,
|
|
@@ -47,6 +64,10 @@ export class MatterbridgeColorControlServer extends ColorControlServer.with(Colo
|
|
|
47
64
|
async enhancedMoveToHue(request) {
|
|
48
65
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
49
66
|
device.log.info(`Setting enhanced hue to ${request.enhancedHue} with transitionTime ${request.transitionTime} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
67
|
+
if (process.env.MATTERBRIDGE_CHIP_TEST) {
|
|
68
|
+
await super.enhancedMoveToHue(request);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
50
71
|
await device.commandHandler.executeHandler('ColorControl.enhancedMoveToHue', {
|
|
51
72
|
command: 'enhancedMoveToHue',
|
|
52
73
|
request,
|
|
@@ -61,6 +82,10 @@ export class MatterbridgeColorControlServer extends ColorControlServer.with(Colo
|
|
|
61
82
|
async enhancedMoveHue(request) {
|
|
62
83
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
63
84
|
device.log.info(`Moving enhanced hue with mode ${request.moveMode} and rate ${request.rate} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
85
|
+
if (process.env.MATTERBRIDGE_CHIP_TEST) {
|
|
86
|
+
await super.enhancedMoveHue(request);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
64
89
|
await device.commandHandler.executeHandler('ColorControl.enhancedMoveHue', {
|
|
65
90
|
command: 'enhancedMoveHue',
|
|
66
91
|
request,
|
|
@@ -75,6 +100,10 @@ export class MatterbridgeColorControlServer extends ColorControlServer.with(Colo
|
|
|
75
100
|
async enhancedStepHue(request) {
|
|
76
101
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
77
102
|
device.log.info(`Stepping enhanced hue with mode ${request.stepMode} and size ${request.stepSize} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
103
|
+
if (process.env.MATTERBRIDGE_CHIP_TEST) {
|
|
104
|
+
await super.enhancedStepHue(request);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
78
107
|
await device.commandHandler.executeHandler('ColorControl.enhancedStepHue', {
|
|
79
108
|
command: 'enhancedStepHue',
|
|
80
109
|
request,
|
|
@@ -89,6 +118,10 @@ export class MatterbridgeColorControlServer extends ColorControlServer.with(Colo
|
|
|
89
118
|
async moveToSaturation(request) {
|
|
90
119
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
91
120
|
device.log.info(`Setting saturation to ${request.saturation} with transitionTime ${request.transitionTime} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
121
|
+
if (process.env.MATTERBRIDGE_CHIP_TEST) {
|
|
122
|
+
await super.moveToSaturation(request);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
92
125
|
await device.commandHandler.executeHandler('ColorControl.moveToSaturation', {
|
|
93
126
|
command: 'moveToSaturation',
|
|
94
127
|
request,
|
|
@@ -103,6 +136,10 @@ export class MatterbridgeColorControlServer extends ColorControlServer.with(Colo
|
|
|
103
136
|
async moveSaturation(request) {
|
|
104
137
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
105
138
|
device.log.info(`Moving saturation with mode ${request.moveMode} and rate ${request.rate} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
139
|
+
if (process.env.MATTERBRIDGE_CHIP_TEST) {
|
|
140
|
+
await super.moveSaturation(request);
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
106
143
|
await device.commandHandler.executeHandler('ColorControl.moveSaturation', {
|
|
107
144
|
command: 'moveSaturation',
|
|
108
145
|
request,
|
|
@@ -117,6 +154,10 @@ export class MatterbridgeColorControlServer extends ColorControlServer.with(Colo
|
|
|
117
154
|
async stepSaturation(request) {
|
|
118
155
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
119
156
|
device.log.info(`Stepping saturation with mode ${request.stepMode} and size ${request.stepSize} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
157
|
+
if (process.env.MATTERBRIDGE_CHIP_TEST) {
|
|
158
|
+
await super.stepSaturation(request);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
120
161
|
await device.commandHandler.executeHandler('ColorControl.stepSaturation', {
|
|
121
162
|
command: 'stepSaturation',
|
|
122
163
|
request,
|
|
@@ -131,6 +172,10 @@ export class MatterbridgeColorControlServer extends ColorControlServer.with(Colo
|
|
|
131
172
|
async moveToHueAndSaturation(request) {
|
|
132
173
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
133
174
|
device.log.info(`Setting hue to ${request.hue} and saturation to ${request.saturation} with transitionTime ${request.transitionTime} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
175
|
+
if (process.env.MATTERBRIDGE_CHIP_TEST) {
|
|
176
|
+
await super.moveToHueAndSaturation(request);
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
134
179
|
await device.commandHandler.executeHandler('ColorControl.moveToHueAndSaturation', {
|
|
135
180
|
command: 'moveToHueAndSaturation',
|
|
136
181
|
request,
|
|
@@ -145,6 +190,10 @@ export class MatterbridgeColorControlServer extends ColorControlServer.with(Colo
|
|
|
145
190
|
async enhancedMoveToHueAndSaturation(request) {
|
|
146
191
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
147
192
|
device.log.info(`Setting enhanced hue to ${request.enhancedHue} and saturation to ${request.saturation} with transitionTime ${request.transitionTime} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
193
|
+
if (process.env.MATTERBRIDGE_CHIP_TEST) {
|
|
194
|
+
await super.enhancedMoveToHueAndSaturation(request);
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
148
197
|
await device.commandHandler.executeHandler('ColorControl.enhancedMoveToHueAndSaturation', {
|
|
149
198
|
command: 'enhancedMoveToHueAndSaturation',
|
|
150
199
|
request,
|
|
@@ -159,6 +208,10 @@ export class MatterbridgeColorControlServer extends ColorControlServer.with(Colo
|
|
|
159
208
|
async moveToColor(request) {
|
|
160
209
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
161
210
|
device.log.info(`Setting color to ${request.colorX}, ${request.colorY} with transitionTime ${request.transitionTime} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
211
|
+
if (process.env.MATTERBRIDGE_CHIP_TEST) {
|
|
212
|
+
await super.moveToColor(request);
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
162
215
|
await device.commandHandler.executeHandler('ColorControl.moveToColor', {
|
|
163
216
|
command: 'moveToColor',
|
|
164
217
|
request,
|
|
@@ -173,6 +226,10 @@ export class MatterbridgeColorControlServer extends ColorControlServer.with(Colo
|
|
|
173
226
|
async moveColor(request) {
|
|
174
227
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
175
228
|
device.log.info(`Moving color with rateX ${request.rateX} and rateY ${request.rateY} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
229
|
+
if (process.env.MATTERBRIDGE_CHIP_TEST) {
|
|
230
|
+
await super.moveColor(request);
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
176
233
|
await device.commandHandler.executeHandler('ColorControl.moveColor', {
|
|
177
234
|
command: 'moveColor',
|
|
178
235
|
request,
|
|
@@ -187,6 +244,10 @@ export class MatterbridgeColorControlServer extends ColorControlServer.with(Colo
|
|
|
187
244
|
async stepColor(request) {
|
|
188
245
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
189
246
|
device.log.info(`Stepping color with stepX ${request.stepX} and stepY ${request.stepY} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
247
|
+
if (process.env.MATTERBRIDGE_CHIP_TEST) {
|
|
248
|
+
await super.stepColor(request);
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
190
251
|
await device.commandHandler.executeHandler('ColorControl.stepColor', {
|
|
191
252
|
command: 'stepColor',
|
|
192
253
|
request,
|
|
@@ -201,6 +262,10 @@ export class MatterbridgeColorControlServer extends ColorControlServer.with(Colo
|
|
|
201
262
|
async moveToColorTemperature(request) {
|
|
202
263
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
203
264
|
device.log.info(`Setting color temperature to ${request.colorTemperatureMireds} with transitionTime ${request.transitionTime} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
265
|
+
if (process.env.MATTERBRIDGE_CHIP_TEST) {
|
|
266
|
+
await super.moveToColorTemperature(request);
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
204
269
|
await device.commandHandler.executeHandler('ColorControl.moveToColorTemperature', {
|
|
205
270
|
command: 'moveToColorTemperature',
|
|
206
271
|
request,
|
|
@@ -215,6 +280,10 @@ export class MatterbridgeColorControlServer extends ColorControlServer.with(Colo
|
|
|
215
280
|
async moveColorTemperature(request) {
|
|
216
281
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
217
282
|
device.log.info(`Moving color temperature with mode ${request.moveMode} and rate ${request.rate} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
283
|
+
if (process.env.MATTERBRIDGE_CHIP_TEST) {
|
|
284
|
+
await super.moveColorTemperature(request);
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
218
287
|
await device.commandHandler.executeHandler('ColorControl.moveColorTemperature', {
|
|
219
288
|
command: 'moveColorTemperature',
|
|
220
289
|
request,
|
|
@@ -229,6 +298,10 @@ export class MatterbridgeColorControlServer extends ColorControlServer.with(Colo
|
|
|
229
298
|
async stepColorTemperature(request) {
|
|
230
299
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
231
300
|
device.log.info(`Stepping color temperature with mode ${request.stepMode} and size ${request.stepSize} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
301
|
+
if (process.env.MATTERBRIDGE_CHIP_TEST) {
|
|
302
|
+
await super.stepColorTemperature(request);
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
232
305
|
await device.commandHandler.executeHandler('ColorControl.stepColorTemperature', {
|
|
233
306
|
command: 'stepColorTemperature',
|
|
234
307
|
request,
|
|
@@ -243,6 +316,10 @@ export class MatterbridgeColorControlServer extends ColorControlServer.with(Colo
|
|
|
243
316
|
async stopMoveStep(request) {
|
|
244
317
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
245
318
|
device.log.info(`Stopping color move/step (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
319
|
+
if (process.env.MATTERBRIDGE_CHIP_TEST) {
|
|
320
|
+
await super.stopMoveStep(request);
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
246
323
|
await device.commandHandler.executeHandler('ColorControl.stopMoveStep', {
|
|
247
324
|
command: 'stopMoveStep',
|
|
248
325
|
request,
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import type { MaybePromise } from '@matter/general';
|
|
1
2
|
import { LevelControlServer } from '@matter/node/behaviors/level-control';
|
|
2
3
|
import type { LevelControl } from '@matter/types/clusters/level-control';
|
|
3
4
|
export declare class MatterbridgeLevelControlServer extends LevelControlServer {
|
|
5
|
+
initialize(): MaybePromise;
|
|
4
6
|
moveToLevel(request: LevelControl.MoveToLevelRequest): Promise<void>;
|
|
5
7
|
moveToLevelWithOnOff(request: LevelControl.MoveToLevelRequest): Promise<void>;
|
|
6
8
|
move(request: LevelControl.MoveRequest): Promise<void>;
|
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
import { LevelControlServer } from '@matter/node/behaviors/level-control';
|
|
2
2
|
import { MatterbridgeServer } from './matterbridgeServer.js';
|
|
3
3
|
export class MatterbridgeLevelControlServer extends LevelControlServer {
|
|
4
|
+
initialize() {
|
|
5
|
+
if (process.env.MATTERBRIDGE_CHIP_TEST)
|
|
6
|
+
this.state.managedTransitionTimeHandling = true;
|
|
7
|
+
return super.initialize();
|
|
8
|
+
}
|
|
4
9
|
async moveToLevel(request) {
|
|
5
10
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
6
11
|
device.log.info(`Setting level to ${request.level} with transitionTime ${request.transitionTime} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
12
|
+
if (process.env.MATTERBRIDGE_CHIP_TEST) {
|
|
13
|
+
await super.moveToLevel(request);
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
7
16
|
await device.commandHandler.executeHandler('LevelControl.moveToLevel', {
|
|
8
17
|
command: 'moveToLevel',
|
|
9
18
|
request,
|
|
@@ -18,6 +27,10 @@ export class MatterbridgeLevelControlServer extends LevelControlServer {
|
|
|
18
27
|
async moveToLevelWithOnOff(request) {
|
|
19
28
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
20
29
|
device.log.info(`Setting level to ${request.level} with transitionTime ${request.transitionTime} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
30
|
+
if (process.env.MATTERBRIDGE_CHIP_TEST) {
|
|
31
|
+
await super.moveToLevelWithOnOff(request);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
21
34
|
await device.commandHandler.executeHandler('LevelControl.moveToLevelWithOnOff', {
|
|
22
35
|
command: 'moveToLevelWithOnOff',
|
|
23
36
|
request,
|
|
@@ -32,6 +45,10 @@ export class MatterbridgeLevelControlServer extends LevelControlServer {
|
|
|
32
45
|
async move(request) {
|
|
33
46
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
34
47
|
device.log.info(`Moving level with mode ${request.moveMode} and rate ${request.rate} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
48
|
+
if (process.env.MATTERBRIDGE_CHIP_TEST) {
|
|
49
|
+
await super.move(request);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
35
52
|
await device.commandHandler.executeHandler('LevelControl.move', {
|
|
36
53
|
command: 'move',
|
|
37
54
|
request,
|
|
@@ -46,6 +63,10 @@ export class MatterbridgeLevelControlServer extends LevelControlServer {
|
|
|
46
63
|
async moveWithOnOff(request) {
|
|
47
64
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
48
65
|
device.log.info(`Moving level with mode ${request.moveMode} and rate ${request.rate} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
66
|
+
if (process.env.MATTERBRIDGE_CHIP_TEST) {
|
|
67
|
+
await super.moveWithOnOff(request);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
49
70
|
await device.commandHandler.executeHandler('LevelControl.moveWithOnOff', {
|
|
50
71
|
command: 'moveWithOnOff',
|
|
51
72
|
request,
|
|
@@ -60,6 +81,10 @@ export class MatterbridgeLevelControlServer extends LevelControlServer {
|
|
|
60
81
|
async step(request) {
|
|
61
82
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
62
83
|
device.log.info(`Stepping level with mode ${request.stepMode} and size ${request.stepSize} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
84
|
+
if (process.env.MATTERBRIDGE_CHIP_TEST) {
|
|
85
|
+
await super.step(request);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
63
88
|
await device.commandHandler.executeHandler('LevelControl.step', {
|
|
64
89
|
command: 'step',
|
|
65
90
|
request,
|
|
@@ -74,6 +99,10 @@ export class MatterbridgeLevelControlServer extends LevelControlServer {
|
|
|
74
99
|
async stepWithOnOff(request) {
|
|
75
100
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
76
101
|
device.log.info(`Stepping level with mode ${request.stepMode} and size ${request.stepSize} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
102
|
+
if (process.env.MATTERBRIDGE_CHIP_TEST) {
|
|
103
|
+
await super.stepWithOnOff(request);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
77
106
|
await device.commandHandler.executeHandler('LevelControl.stepWithOnOff', {
|
|
78
107
|
command: 'stepWithOnOff',
|
|
79
108
|
request,
|
|
@@ -88,6 +117,10 @@ export class MatterbridgeLevelControlServer extends LevelControlServer {
|
|
|
88
117
|
async stop(request) {
|
|
89
118
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
90
119
|
device.log.info(`Stopping level change (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
120
|
+
if (process.env.MATTERBRIDGE_CHIP_TEST) {
|
|
121
|
+
await super.stop(request);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
91
124
|
await device.commandHandler.executeHandler('LevelControl.stop', {
|
|
92
125
|
command: 'stop',
|
|
93
126
|
request,
|
|
@@ -102,6 +135,10 @@ export class MatterbridgeLevelControlServer extends LevelControlServer {
|
|
|
102
135
|
async stopWithOnOff(request) {
|
|
103
136
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
104
137
|
device.log.info(`Stopping level change (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
138
|
+
if (process.env.MATTERBRIDGE_CHIP_TEST) {
|
|
139
|
+
await super.stopWithOnOff(request);
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
105
142
|
await device.commandHandler.executeHandler('LevelControl.stopWithOnOff', {
|
|
106
143
|
command: 'stopWithOnOff',
|
|
107
144
|
request,
|
|
@@ -5,96 +5,108 @@ export class MatterbridgeOnOffServer extends OnOffServer.with(OnOff.Feature.Ligh
|
|
|
5
5
|
async on() {
|
|
6
6
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
7
7
|
device.log.info(`Switching device on (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
8
|
-
if (
|
|
9
|
-
await
|
|
10
|
-
|
|
11
|
-
request: {},
|
|
12
|
-
cluster: OnOffServer.id,
|
|
13
|
-
attributes: this.state,
|
|
14
|
-
endpoint: this.endpoint,
|
|
15
|
-
context: this.context,
|
|
16
|
-
});
|
|
8
|
+
if (process.env.MATTERBRIDGE_CHIP_TEST) {
|
|
9
|
+
await super.on();
|
|
10
|
+
return;
|
|
17
11
|
}
|
|
12
|
+
await device.commandHandler.executeHandler('OnOff.on', {
|
|
13
|
+
command: 'on',
|
|
14
|
+
request: {},
|
|
15
|
+
cluster: OnOffServer.id,
|
|
16
|
+
attributes: this.state,
|
|
17
|
+
endpoint: this.endpoint,
|
|
18
|
+
context: this.context,
|
|
19
|
+
});
|
|
18
20
|
device.log.debug(`MatterbridgeOnOffServer: on called`);
|
|
19
21
|
await super.on();
|
|
20
22
|
}
|
|
21
23
|
async off() {
|
|
22
24
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
23
25
|
device.log.info(`Switching device off (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
24
|
-
if (
|
|
25
|
-
await
|
|
26
|
-
|
|
27
|
-
request: {},
|
|
28
|
-
cluster: OnOffServer.id,
|
|
29
|
-
attributes: this.state,
|
|
30
|
-
endpoint: this.endpoint,
|
|
31
|
-
context: this.context,
|
|
32
|
-
});
|
|
26
|
+
if (process.env.MATTERBRIDGE_CHIP_TEST) {
|
|
27
|
+
await super.off();
|
|
28
|
+
return;
|
|
33
29
|
}
|
|
30
|
+
await device.commandHandler.executeHandler('OnOff.off', {
|
|
31
|
+
command: 'off',
|
|
32
|
+
request: {},
|
|
33
|
+
cluster: OnOffServer.id,
|
|
34
|
+
attributes: this.state,
|
|
35
|
+
endpoint: this.endpoint,
|
|
36
|
+
context: this.context,
|
|
37
|
+
});
|
|
34
38
|
device.log.debug(`MatterbridgeOnOffServer: off called`);
|
|
35
39
|
await super.off();
|
|
36
40
|
}
|
|
37
41
|
async toggle() {
|
|
38
42
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
39
43
|
device.log.info(`Toggle device on/off (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
40
|
-
if (
|
|
41
|
-
await
|
|
42
|
-
|
|
43
|
-
request: {},
|
|
44
|
-
cluster: OnOffServer.id,
|
|
45
|
-
attributes: this.state,
|
|
46
|
-
endpoint: this.endpoint,
|
|
47
|
-
context: this.context,
|
|
48
|
-
});
|
|
44
|
+
if (process.env.MATTERBRIDGE_CHIP_TEST) {
|
|
45
|
+
await super.toggle();
|
|
46
|
+
return;
|
|
49
47
|
}
|
|
48
|
+
await device.commandHandler.executeHandler('OnOff.toggle', {
|
|
49
|
+
command: 'toggle',
|
|
50
|
+
request: {},
|
|
51
|
+
cluster: OnOffServer.id,
|
|
52
|
+
attributes: this.state,
|
|
53
|
+
endpoint: this.endpoint,
|
|
54
|
+
context: this.context,
|
|
55
|
+
});
|
|
50
56
|
device.log.debug(`MatterbridgeOnOffServer: toggle called`);
|
|
51
57
|
await super.toggle();
|
|
52
58
|
}
|
|
53
59
|
async offWithEffect(request) {
|
|
54
60
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
55
61
|
device.log.info(`Switching device off with effect ${request.effectIdentifier} and variant ${request.effectVariant} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
56
|
-
if (
|
|
57
|
-
await
|
|
58
|
-
|
|
59
|
-
request,
|
|
60
|
-
cluster: OnOffServer.id,
|
|
61
|
-
attributes: this.state,
|
|
62
|
-
endpoint: this.endpoint,
|
|
63
|
-
context: this.context,
|
|
64
|
-
});
|
|
62
|
+
if (process.env.MATTERBRIDGE_CHIP_TEST) {
|
|
63
|
+
await super.offWithEffect(request);
|
|
64
|
+
return;
|
|
65
65
|
}
|
|
66
|
+
await device.commandHandler.executeHandler('OnOff.offWithEffect', {
|
|
67
|
+
command: 'offWithEffect',
|
|
68
|
+
request,
|
|
69
|
+
cluster: OnOffServer.id,
|
|
70
|
+
attributes: this.state,
|
|
71
|
+
endpoint: this.endpoint,
|
|
72
|
+
context: this.context,
|
|
73
|
+
});
|
|
66
74
|
device.log.debug(`MatterbridgeOnOffServer: offWithEffect called`);
|
|
67
75
|
await super.offWithEffect(request);
|
|
68
76
|
}
|
|
69
77
|
async onWithRecallGlobalScene() {
|
|
70
78
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
71
79
|
device.log.info(`Switching device on with recall global scene (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
72
|
-
if (
|
|
73
|
-
await
|
|
74
|
-
|
|
75
|
-
request: {},
|
|
76
|
-
cluster: OnOffServer.id,
|
|
77
|
-
attributes: this.state,
|
|
78
|
-
endpoint: this.endpoint,
|
|
79
|
-
context: this.context,
|
|
80
|
-
});
|
|
80
|
+
if (process.env.MATTERBRIDGE_CHIP_TEST) {
|
|
81
|
+
await super.onWithRecallGlobalScene();
|
|
82
|
+
return;
|
|
81
83
|
}
|
|
84
|
+
await device.commandHandler.executeHandler('OnOff.onWithRecallGlobalScene', {
|
|
85
|
+
command: 'onWithRecallGlobalScene',
|
|
86
|
+
request: {},
|
|
87
|
+
cluster: OnOffServer.id,
|
|
88
|
+
attributes: this.state,
|
|
89
|
+
endpoint: this.endpoint,
|
|
90
|
+
context: this.context,
|
|
91
|
+
});
|
|
82
92
|
device.log.debug(`MatterbridgeOnOffServer: onWithRecallGlobalScene called`);
|
|
83
93
|
await super.onWithRecallGlobalScene();
|
|
84
94
|
}
|
|
85
95
|
async onWithTimedOff(request) {
|
|
86
96
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
87
97
|
device.log.info(`Switching device on with timed off control ${JSON.stringify(request.onOffControl)}, offWaitTime ${request.offWaitTime} and onTime ${request.onTime} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
88
|
-
if (
|
|
89
|
-
await
|
|
90
|
-
|
|
91
|
-
request,
|
|
92
|
-
cluster: OnOffServer.id,
|
|
93
|
-
attributes: this.state,
|
|
94
|
-
endpoint: this.endpoint,
|
|
95
|
-
context: this.context,
|
|
96
|
-
});
|
|
98
|
+
if (process.env.MATTERBRIDGE_CHIP_TEST) {
|
|
99
|
+
await super.onWithTimedOff(request);
|
|
100
|
+
return;
|
|
97
101
|
}
|
|
102
|
+
await device.commandHandler.executeHandler('OnOff.onWithTimedOff', {
|
|
103
|
+
command: 'onWithTimedOff',
|
|
104
|
+
request,
|
|
105
|
+
cluster: OnOffServer.id,
|
|
106
|
+
attributes: this.state,
|
|
107
|
+
endpoint: this.endpoint,
|
|
108
|
+
context: this.context,
|
|
109
|
+
});
|
|
98
110
|
device.log.debug(`MatterbridgeOnOffServer: onWithTimedOff called`);
|
|
99
111
|
await super.onWithTimedOff(request);
|
|
100
112
|
}
|
package/dist/chipTests.js
CHANGED
|
@@ -6,6 +6,7 @@ import { BridgedDeviceBasicInformationServer } from '@matter/node/behaviors/brid
|
|
|
6
6
|
import { GeneralDiagnosticsServer } from '@matter/node/behaviors/general-diagnostics';
|
|
7
7
|
import { Status, StatusResponseError } from '@matter/types';
|
|
8
8
|
import { BooleanStateConfiguration } from '@matter/types/clusters/boolean-state-configuration';
|
|
9
|
+
import { ClosureControl } from '@matter/types/clusters/closure-control';
|
|
9
10
|
import { DeviceEnergyManagement } from '@matter/types/clusters/device-energy-management';
|
|
10
11
|
import { ElectricalEnergyMeasurement } from '@matter/types/clusters/electrical-energy-measurement';
|
|
11
12
|
import { ElectricalPowerMeasurement } from '@matter/types/clusters/electrical-power-measurement';
|
|
@@ -47,6 +48,12 @@ const deviceEnergyManagementForecastTrigger = 0x009800000000000fn;
|
|
|
47
48
|
const deviceEnergyManagementForecastClearTrigger = 0x0098000000000010n;
|
|
48
49
|
const booleanStateConfigurationSensorTrigger = 0x0080000000000000n;
|
|
49
50
|
const booleanStateConfigurationSensorUntriggerTrigger = 0x0080000000000001n;
|
|
51
|
+
const closureControlErrorTrigger = 0x0104000000000000n;
|
|
52
|
+
const closureControlProtectedTrigger = 0x0104000000000001n;
|
|
53
|
+
const closureControlDisengagedTrigger = 0x0104000000000002n;
|
|
54
|
+
const closureControlSetupRequiredTrigger = 0x0104000000000003n;
|
|
55
|
+
const closureControlClearTrigger = 0x0104000000000004n;
|
|
56
|
+
const closureControlEndpointTriggerMask = 0x0000ffff00000000n;
|
|
50
57
|
export const chipTestEnableKey = Uint8Array.from({ length: 16 }, (_, index) => index);
|
|
51
58
|
const smokeCoAlarmChipTestEnableKey = Uint8Array.from([0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]);
|
|
52
59
|
let chipTestMatterbridge;
|
|
@@ -198,6 +205,14 @@ async function handleChipTestEventTrigger(eventTrigger) {
|
|
|
198
205
|
if (eventTrigger === booleanStateConfigurationSensorTrigger || eventTrigger === booleanStateConfigurationSensorUntriggerTrigger) {
|
|
199
206
|
return await handleBooleanStateConfigurationTestEventTrigger(eventTrigger);
|
|
200
207
|
}
|
|
208
|
+
const closureControlTrigger = eventTrigger & ~closureControlEndpointTriggerMask;
|
|
209
|
+
if (closureControlTrigger === closureControlErrorTrigger ||
|
|
210
|
+
closureControlTrigger === closureControlProtectedTrigger ||
|
|
211
|
+
closureControlTrigger === closureControlDisengagedTrigger ||
|
|
212
|
+
closureControlTrigger === closureControlSetupRequiredTrigger ||
|
|
213
|
+
closureControlTrigger === closureControlClearTrigger) {
|
|
214
|
+
return await handleClosureControlTestEventTrigger(closureControlTrigger);
|
|
215
|
+
}
|
|
201
216
|
if (eventTrigger !== smokeCoAlarmWarningSmokeAlarmTrigger &&
|
|
202
217
|
eventTrigger !== smokeCoAlarmCriticalSmokeAlarmTrigger &&
|
|
203
218
|
eventTrigger !== smokeCoAlarmSmokeAlarmClearTrigger &&
|
|
@@ -354,6 +369,44 @@ async function applyBooleanStateConfigurationTestEventTrigger(endpoint, eventTri
|
|
|
354
369
|
return;
|
|
355
370
|
}
|
|
356
371
|
}
|
|
372
|
+
async function handleClosureControlTestEventTrigger(eventTrigger) {
|
|
373
|
+
if (!chipTestMatterbridge || chipTestActiveEndpointId === undefined)
|
|
374
|
+
return false;
|
|
375
|
+
const endpoint = getChipTestEndpoint(chipTestMatterbridge, chipTestActiveEndpointId);
|
|
376
|
+
if (!endpoint || !endpoint.hasClusterServer(ClosureControl.id))
|
|
377
|
+
return false;
|
|
378
|
+
await applyClosureControlTestEventTrigger(endpoint, eventTrigger, chipTestMatterbridge.log);
|
|
379
|
+
return true;
|
|
380
|
+
}
|
|
381
|
+
async function applyClosureControlTestEventTrigger(endpoint, eventTrigger, log) {
|
|
382
|
+
switch (eventTrigger) {
|
|
383
|
+
case closureControlErrorTrigger: {
|
|
384
|
+
const errorState = [ClosureControl.ClosureError.PhysicallyBlocked];
|
|
385
|
+
await endpoint.setCluster(ClosureControl, { mainState: ClosureControl.MainState.Error, currentErrorList: errorState }, log);
|
|
386
|
+
await endpoint.triggerEvent(ClosureControl, 'operationalError', { errorState }, log);
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
case closureControlProtectedTrigger:
|
|
390
|
+
await endpoint.setCluster(ClosureControl, { mainState: ClosureControl.MainState.Protected }, log);
|
|
391
|
+
return;
|
|
392
|
+
case closureControlDisengagedTrigger:
|
|
393
|
+
await endpoint.setCluster(ClosureControl, { mainState: ClosureControl.MainState.Disengaged }, log);
|
|
394
|
+
await endpoint.triggerEvent(ClosureControl, 'engageStateChanged', { engageValue: false }, log);
|
|
395
|
+
return;
|
|
396
|
+
case closureControlSetupRequiredTrigger:
|
|
397
|
+
await endpoint.setCluster(ClosureControl, { mainState: ClosureControl.MainState.SetupRequired }, log);
|
|
398
|
+
return;
|
|
399
|
+
case closureControlClearTrigger: {
|
|
400
|
+
const wasDisengaged = endpoint.getAttribute(ClosureControl.id, 'mainState') === ClosureControl.MainState.Disengaged;
|
|
401
|
+
await endpoint.setCluster(ClosureControl, { mainState: ClosureControl.MainState.Stopped, currentErrorList: [] }, log);
|
|
402
|
+
if (wasDisengaged)
|
|
403
|
+
await endpoint.triggerEvent(ClosureControl, 'engageStateChanged', { engageValue: true }, log);
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
default:
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
357
410
|
const electricalPowerMeasurementIdleReading = { voltage: 220_000, activeCurrent: 1_000, activePower: 220_000_000, frequency: 50_000 };
|
|
358
411
|
const electricalEnergyMeasurementImportedEnergyPerTick = 278;
|
|
359
412
|
const electricalEnergyMeasurementExportedEnergyPerTick = 833;
|
package/dist/demoDevices.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CommonNumberTag } from '@matter/node';
|
|
1
|
+
import { ClosureTag, ClosureWindowTag, CommonNumberTag } from '@matter/node';
|
|
2
2
|
import { AirQuality } from '@matter/types/clusters/air-quality';
|
|
3
3
|
import { FanControl } from '@matter/types/clusters/fan-control';
|
|
4
4
|
import { PowerSource } from '@matter/types/clusters/power-source';
|
|
@@ -32,7 +32,7 @@ export async function createDemoDevices(matterbridge) {
|
|
|
32
32
|
description: 'Matterbridge demo devices',
|
|
33
33
|
author: 'Matterbridge',
|
|
34
34
|
enabled: false,
|
|
35
|
-
private:
|
|
35
|
+
private: true,
|
|
36
36
|
registeredDevices: 0,
|
|
37
37
|
});
|
|
38
38
|
const registerDevice = async (device, deviceName, serialNumber) => {
|
|
@@ -201,10 +201,51 @@ export async function createDemoDevices(matterbridge) {
|
|
|
201
201
|
await registerDevice(ep, 'Door Lock Controller', 'ENTRY-08-02');
|
|
202
202
|
ep = new MatterbridgeEndpoint([getSupportedDeviceType('WindowCovering'), bridgedNode, powerSource], { id: 'WindowCovering', number: EndpointNumber(8_03) });
|
|
203
203
|
await registerDevice(ep, 'Window Covering', 'ENTRY-08-03');
|
|
204
|
+
ep = new MatterbridgeEndpoint([getSupportedDeviceType('WindowCovering'), bridgedNode, powerSource], { id: 'WindowCoveringTilt', number: EndpointNumber(8_03_1) });
|
|
205
|
+
ep.createDefaultLiftTiltWindowCoveringClusterServer();
|
|
206
|
+
await registerDevice(ep, 'Window Covering Tilt', 'ENTRY-08-03-1');
|
|
204
207
|
ep = new MatterbridgeEndpoint([getSupportedDeviceType('WindowCoveringController'), bridgedNode, powerSource], { id: 'WindowCoveringController', number: EndpointNumber(8_04) });
|
|
205
208
|
await registerDevice(ep, 'Window Covering Controller', 'ENTRY-08-04');
|
|
206
|
-
ep = new Closure('Closure', 'ENTRY-08-05', { id: 'Closure', number: EndpointNumber(8_05) });
|
|
209
|
+
ep = new Closure('Closure', 'ENTRY-08-05', { id: 'Closure', number: EndpointNumber(8_05), movementDuration: 2000, calibrationDuration: 2000 });
|
|
207
210
|
await registerDevice(ep, 'Closure', 'ENTRY-08-05');
|
|
211
|
+
ep = new Closure('Closure Pedestrian', 'ENTRY-08-05-1', {
|
|
212
|
+
id: 'ClosurePedestrian',
|
|
213
|
+
number: EndpointNumber(8_05_1),
|
|
214
|
+
movementDuration: 2000,
|
|
215
|
+
calibrationDuration: 2000,
|
|
216
|
+
pedestrian: true,
|
|
217
|
+
tagList: [getSemtag(ClosureTag.Gate)],
|
|
218
|
+
});
|
|
219
|
+
await registerDevice(ep, 'Closure Pedestrian', 'ENTRY-08-05-1');
|
|
220
|
+
ep = new Closure('Closure Ventilation', 'ENTRY-08-05-2', {
|
|
221
|
+
id: 'ClosureVentilation',
|
|
222
|
+
number: EndpointNumber(8_05_2),
|
|
223
|
+
movementDuration: 2000,
|
|
224
|
+
calibrationDuration: 2000,
|
|
225
|
+
ventilation: true,
|
|
226
|
+
tagList: [getSemtag(ClosureTag.Window), getSemtag(ClosureWindowTag.Facade)],
|
|
227
|
+
});
|
|
228
|
+
await registerDevice(ep, 'Closure Ventilation', 'ENTRY-08-05-2');
|
|
229
|
+
ep = new Closure('Closure Calibrate', 'ENTRY-08-05-3', {
|
|
230
|
+
id: 'ClosureCalibrate',
|
|
231
|
+
number: EndpointNumber(8_05_3),
|
|
232
|
+
movementDuration: 2000,
|
|
233
|
+
calibrationDuration: 2000,
|
|
234
|
+
calibration: true,
|
|
235
|
+
tagList: [getSemtag(ClosureTag.GarageDoor)],
|
|
236
|
+
});
|
|
237
|
+
await registerDevice(ep, 'Closure Calibrate', 'ENTRY-08-05-3');
|
|
238
|
+
ep = new Closure('Closure Complete', 'ENTRY-08-05-4', {
|
|
239
|
+
id: 'ClosureComplete',
|
|
240
|
+
number: EndpointNumber(8_05_4),
|
|
241
|
+
movementDuration: 2000,
|
|
242
|
+
calibrationDuration: 2000,
|
|
243
|
+
ventilation: true,
|
|
244
|
+
pedestrian: true,
|
|
245
|
+
calibration: true,
|
|
246
|
+
tagList: [getSemtag(ClosureTag.Door)],
|
|
247
|
+
});
|
|
248
|
+
await registerDevice(ep, 'Closure Complete', 'ENTRY-08-05-4');
|
|
208
249
|
ep = new MatterbridgeEndpoint([getSupportedDeviceType('ClosureController'), bridgedNode, powerSource], { id: 'ClosureController', number: EndpointNumber(8_07) });
|
|
209
250
|
await registerDevice(ep, 'Closure Controller', 'ENTRY-08-07');
|
|
210
251
|
ep = new MatterbridgeEndpoint([getSupportedDeviceType('Thermostat'), bridgedNode, powerSource], { id: 'Thermostat', number: EndpointNumber(9_01) });
|
|
@@ -5,8 +5,8 @@ import { Identify } from '@matter/types/clusters/identify';
|
|
|
5
5
|
import type { Semtag } from '@matter/types/globals';
|
|
6
6
|
import { MatterbridgeEndpoint } from '../matterbridgeEndpoint.js';
|
|
7
7
|
import { type ClosureDimensionType, type ClosurePanelOptions } from './closurePanel.js';
|
|
8
|
-
declare const
|
|
9
|
-
calibration:
|
|
8
|
+
declare const MatterbridgeClosureControlServerBase: import("@matter/node").ClusterBehavior.Type<typeof ClosureControlServer, import("@matter/types").ClusterType.WithSupportedFeatures<ClosureControl, {
|
|
9
|
+
calibration: true;
|
|
10
10
|
instantaneous: false;
|
|
11
11
|
manuallyOperable: false;
|
|
12
12
|
motionLatching: true;
|
|
@@ -16,9 +16,24 @@ declare const MatterbridgeClosureControlServer_base: import("@matter/node").Clus
|
|
|
16
16
|
speed: true;
|
|
17
17
|
ventilation: false;
|
|
18
18
|
}>, import("@matter/types").ClusterType.Concrete, new () => {}, "closureControl">;
|
|
19
|
-
export declare class MatterbridgeClosureControlServer extends
|
|
19
|
+
export declare class MatterbridgeClosureControlServer extends MatterbridgeClosureControlServerBase {
|
|
20
|
+
readonly state: MatterbridgeClosureControlServer.State;
|
|
21
|
+
protected internal: MatterbridgeClosureControlServer.Internal;
|
|
20
22
|
moveTo: (request: ClosureControl.MoveToRequest) => Promise<void>;
|
|
23
|
+
private completeMoveTo;
|
|
21
24
|
stop: () => Promise<void>;
|
|
25
|
+
calibrate: () => Promise<void>;
|
|
26
|
+
private completeCalibrate;
|
|
27
|
+
}
|
|
28
|
+
export declare namespace MatterbridgeClosureControlServer {
|
|
29
|
+
class Internal extends MatterbridgeClosureControlServerBase.Internal {
|
|
30
|
+
movementTimer?: NodeJS.Timeout;
|
|
31
|
+
calibrateTimer?: NodeJS.Timeout;
|
|
32
|
+
}
|
|
33
|
+
class State extends MatterbridgeClosureControlServerBase.State {
|
|
34
|
+
movementDuration: number;
|
|
35
|
+
calibrationDuration: number;
|
|
36
|
+
}
|
|
22
37
|
}
|
|
23
38
|
export interface ClosureOptions {
|
|
24
39
|
identifyTime?: number;
|
|
@@ -30,6 +45,11 @@ export interface ClosureOptions {
|
|
|
30
45
|
overallCurrentState?: ClosureControl.OverallCurrentState;
|
|
31
46
|
overallTargetState?: ClosureControl.OverallTargetState;
|
|
32
47
|
latchControlModes?: ClosureControl.LatchControlModes;
|
|
48
|
+
movementDuration?: number;
|
|
49
|
+
calibrationDuration?: number;
|
|
50
|
+
ventilation?: boolean;
|
|
51
|
+
pedestrian?: boolean;
|
|
52
|
+
calibration?: boolean;
|
|
33
53
|
id?: string;
|
|
34
54
|
number?: EndpointNumber;
|
|
35
55
|
tagList?: Semtag[];
|
package/dist/devices/closure.js
CHANGED
|
@@ -9,7 +9,15 @@ import { closure, closurePanel, powerSource } from '../matterbridgeDeviceTypes.j
|
|
|
9
9
|
import { MatterbridgeEndpoint } from '../matterbridgeEndpoint.js';
|
|
10
10
|
import { getSemtag } from '../matterbridgeEndpointHelpers.js';
|
|
11
11
|
import { createClosureDimensionClusterServer } from './closurePanel.js';
|
|
12
|
-
|
|
12
|
+
const targetToCurrentPosition = {
|
|
13
|
+
[ClosureControl.TargetPosition.MoveToFullyClosed]: ClosureControl.CurrentPosition.FullyClosed,
|
|
14
|
+
[ClosureControl.TargetPosition.MoveToFullyOpen]: ClosureControl.CurrentPosition.FullyOpened,
|
|
15
|
+
[ClosureControl.TargetPosition.MoveToPedestrianPosition]: ClosureControl.CurrentPosition.OpenedForPedestrian,
|
|
16
|
+
[ClosureControl.TargetPosition.MoveToVentilationPosition]: ClosureControl.CurrentPosition.OpenedForVentilation,
|
|
17
|
+
[ClosureControl.TargetPosition.MoveToSignaturePosition]: ClosureControl.CurrentPosition.OpenedAtSignature,
|
|
18
|
+
};
|
|
19
|
+
const MatterbridgeClosureControlServerBase = ClosureControlServer.with(ClosureControl.Feature.Positioning, ClosureControl.Feature.MotionLatching, ClosureControl.Feature.Speed, ClosureControl.Feature.Calibration);
|
|
20
|
+
export class MatterbridgeClosureControlServer extends MatterbridgeClosureControlServerBase {
|
|
13
21
|
moveTo = async (request) => {
|
|
14
22
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
15
23
|
device.log.info(`MoveTo (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
@@ -20,6 +28,15 @@ export class MatterbridgeClosureControlServer extends ClosureControlServer.with(
|
|
|
20
28
|
attributes: this.state,
|
|
21
29
|
endpoint: this.endpoint,
|
|
22
30
|
});
|
|
31
|
+
if (request.position !== undefined && !(request.position in targetToCurrentPosition)) {
|
|
32
|
+
throw new StatusResponse.ConstraintErrorError('ClosureControl.moveTo Position is not a valid TargetPositionEnum value');
|
|
33
|
+
}
|
|
34
|
+
if (request.latch !== undefined && typeof request.latch !== 'boolean') {
|
|
35
|
+
throw new StatusResponse.ConstraintErrorError('ClosureControl.moveTo Latch is not a boolean value');
|
|
36
|
+
}
|
|
37
|
+
if (request.speed !== undefined && !(request.speed in ThreeLevelAuto)) {
|
|
38
|
+
throw new StatusResponse.ConstraintErrorError('ClosureControl.moveTo Speed is not a valid ThreeLevelAutoEnum value');
|
|
39
|
+
}
|
|
23
40
|
if (request.position === undefined && request.latch === undefined && request.speed === undefined) {
|
|
24
41
|
throw new StatusResponse.InvalidCommandError('ClosureControl.moveTo requires at least one of position, latch, or speed to be present');
|
|
25
42
|
}
|
|
@@ -47,6 +64,38 @@ export class MatterbridgeClosureControlServer extends ClosureControlServer.with(
|
|
|
47
64
|
(nextTarget.latch === undefined || nextTarget.latch === currentState.latch) &&
|
|
48
65
|
nextTarget.speed === currentState.speed;
|
|
49
66
|
this.state.mainState = isAtTarget ? ClosureControl.MainState.Stopped : ClosureControl.MainState.Moving;
|
|
67
|
+
clearTimeout(this.internal.movementTimer);
|
|
68
|
+
if (isAtTarget) {
|
|
69
|
+
this.internal.movementTimer = undefined;
|
|
70
|
+
this.state.countdownTime = 0;
|
|
71
|
+
}
|
|
72
|
+
else if (currentState === null || this.state.movementDuration <= 0) {
|
|
73
|
+
this.internal.movementTimer = undefined;
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
this.state.countdownTime = this.state.movementDuration / 1000;
|
|
77
|
+
const previousState = currentState;
|
|
78
|
+
this.internal.movementTimer = setTimeout(() => {
|
|
79
|
+
this.internal.movementTimer = undefined;
|
|
80
|
+
void this.completeMoveTo(nextTarget, previousState);
|
|
81
|
+
}, this.state.movementDuration);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
completeMoveTo = async (targetState, previousState) => {
|
|
85
|
+
const closure = this.endpoint;
|
|
86
|
+
let position = previousState.position;
|
|
87
|
+
if (targetState.position !== undefined && targetState.position !== null) {
|
|
88
|
+
const mappedPosition = targetToCurrentPosition[targetState.position];
|
|
89
|
+
if (mappedPosition !== undefined)
|
|
90
|
+
position = mappedPosition;
|
|
91
|
+
}
|
|
92
|
+
const latch = targetState.latch ?? previousState.latch;
|
|
93
|
+
const secureState = latch === true;
|
|
94
|
+
await closure.setState({ position, latch, speed: targetState.speed, secureState }, targetState, ClosureControl.MainState.Stopped, 0);
|
|
95
|
+
if (secureState !== previousState.secureState) {
|
|
96
|
+
await closure.triggerSecureStateChanged(secureState);
|
|
97
|
+
}
|
|
98
|
+
await closure.triggerMovementCompleted();
|
|
50
99
|
};
|
|
51
100
|
stop = async () => {
|
|
52
101
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
@@ -58,11 +107,62 @@ export class MatterbridgeClosureControlServer extends ClosureControlServer.with(
|
|
|
58
107
|
attributes: this.state,
|
|
59
108
|
endpoint: this.endpoint,
|
|
60
109
|
});
|
|
110
|
+
clearTimeout(this.internal.movementTimer);
|
|
111
|
+
this.internal.movementTimer = undefined;
|
|
112
|
+
clearTimeout(this.internal.calibrateTimer);
|
|
113
|
+
this.internal.calibrateTimer = undefined;
|
|
61
114
|
if ([ClosureControl.MainState.Moving, ClosureControl.MainState.WaitingForMotion, ClosureControl.MainState.Calibrating].includes(this.state.mainState)) {
|
|
62
115
|
this.state.mainState = ClosureControl.MainState.Stopped;
|
|
116
|
+
this.state.countdownTime = 0;
|
|
63
117
|
}
|
|
64
118
|
};
|
|
119
|
+
calibrate = async () => {
|
|
120
|
+
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
121
|
+
device.log.info(`Calibrate (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
122
|
+
await device.commandHandler.executeHandler('ClosureControl.calibrate', {
|
|
123
|
+
command: 'calibrate',
|
|
124
|
+
request: {},
|
|
125
|
+
cluster: ClosureControlServer.id,
|
|
126
|
+
attributes: this.state,
|
|
127
|
+
endpoint: this.endpoint,
|
|
128
|
+
});
|
|
129
|
+
if (this.state.mainState === ClosureControl.MainState.Calibrating) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
if (![ClosureControl.MainState.Stopped, ClosureControl.MainState.SetupRequired].includes(this.state.mainState)) {
|
|
133
|
+
throw new StatusResponse.InvalidInStateError('ClosureControl.calibrate is only allowed while Stopped or SetupRequired');
|
|
134
|
+
}
|
|
135
|
+
this.state.mainState = ClosureControl.MainState.Calibrating;
|
|
136
|
+
clearTimeout(this.internal.calibrateTimer);
|
|
137
|
+
if (this.state.calibrationDuration <= 0) {
|
|
138
|
+
this.internal.calibrateTimer = undefined;
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
this.state.countdownTime = this.state.calibrationDuration / 1000;
|
|
142
|
+
this.internal.calibrateTimer = setTimeout(() => {
|
|
143
|
+
this.internal.calibrateTimer = undefined;
|
|
144
|
+
void this.completeCalibrate();
|
|
145
|
+
}, this.state.calibrationDuration);
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
completeCalibrate = async () => {
|
|
149
|
+
const closure = this.endpoint;
|
|
150
|
+
await closure.setAttribute(ClosureControl, 'countdownTime', 0);
|
|
151
|
+
await closure.setAttribute(ClosureControl, 'mainState', ClosureControl.MainState.Stopped);
|
|
152
|
+
};
|
|
65
153
|
}
|
|
154
|
+
(function (MatterbridgeClosureControlServer) {
|
|
155
|
+
class Internal extends MatterbridgeClosureControlServerBase.Internal {
|
|
156
|
+
movementTimer;
|
|
157
|
+
calibrateTimer;
|
|
158
|
+
}
|
|
159
|
+
MatterbridgeClosureControlServer.Internal = Internal;
|
|
160
|
+
class State extends MatterbridgeClosureControlServerBase.State {
|
|
161
|
+
movementDuration = 0;
|
|
162
|
+
calibrationDuration = 0;
|
|
163
|
+
}
|
|
164
|
+
MatterbridgeClosureControlServer.State = State;
|
|
165
|
+
})(MatterbridgeClosureControlServer || (MatterbridgeClosureControlServer = {}));
|
|
66
166
|
export class Closure extends MatterbridgeEndpoint {
|
|
67
167
|
constructor(name, serial, options = {}) {
|
|
68
168
|
const { identifyTime = 0, identifyType = Identify.IdentifyType.None, powerSourceType = 'Wired', countdownTime = 0, mainState = ClosureControl.MainState.Stopped, currentErrorList = [], overallCurrentState = {
|
|
@@ -74,7 +174,7 @@ export class Closure extends MatterbridgeEndpoint {
|
|
|
74
174
|
position: ClosureControl.TargetPosition.MoveToFullyClosed,
|
|
75
175
|
latch: true,
|
|
76
176
|
speed: ThreeLevelAuto.Auto,
|
|
77
|
-
}, latchControlModes = { remoteLatching: true, remoteUnlatching: true }, id, number, tagList = [getSemtag(ClosureTag.Covering)], } = options;
|
|
177
|
+
}, latchControlModes = { remoteLatching: true, remoteUnlatching: true }, movementDuration = 0, calibrationDuration = 0, ventilation = false, pedestrian = false, calibration = false, id, number, tagList = [getSemtag(ClosureTag.Covering)], } = options;
|
|
78
178
|
super(powerSourceType === 'None' ? [closure] : [closure, powerSource], {
|
|
79
179
|
id: id ?? `${name.replaceAll(' ', '')}-${serial.replaceAll(' ', '')}`,
|
|
80
180
|
number,
|
|
@@ -98,14 +198,19 @@ export class Closure extends MatterbridgeEndpoint {
|
|
|
98
198
|
case 'None':
|
|
99
199
|
break;
|
|
100
200
|
}
|
|
101
|
-
|
|
201
|
+
const closureControlOptions = {
|
|
102
202
|
countdownTime,
|
|
103
203
|
mainState,
|
|
104
204
|
currentErrorList,
|
|
105
205
|
overallCurrentState,
|
|
106
206
|
overallTargetState,
|
|
107
207
|
latchControlModes,
|
|
108
|
-
|
|
208
|
+
movementDuration,
|
|
209
|
+
calibrationDuration,
|
|
210
|
+
};
|
|
211
|
+
this.behaviors.require(calibration || ventilation || pedestrian
|
|
212
|
+
? MatterbridgeClosureControlServer.with(ClosureControl.Feature.Positioning, ClosureControl.Feature.MotionLatching, ClosureControl.Feature.Speed, ...(calibration ? [ClosureControl.Feature.Calibration] : []), ...(ventilation ? [ClosureControl.Feature.Ventilation] : []), ...(pedestrian ? [ClosureControl.Feature.Pedestrian] : []))
|
|
213
|
+
: MatterbridgeClosureControlServer, closureControlOptions);
|
|
109
214
|
}
|
|
110
215
|
getMainState() {
|
|
111
216
|
return this.getAttribute(ClosureControlServer, 'mainState');
|
package/dist/frontend.js
CHANGED
|
@@ -17,6 +17,7 @@ import { SoilMeasurement } from '@matter/types/clusters/soil-measurement';
|
|
|
17
17
|
import { ValveConfigurationAndControl } from '@matter/types/clusters/valve-configuration-and-control';
|
|
18
18
|
import { CommissioningOptions } from '@matter/types/commissioning';
|
|
19
19
|
import { FabricIndex } from '@matter/types/datatype';
|
|
20
|
+
import { ThreeLevelAuto } from '@matter/types/globals';
|
|
20
21
|
import { BroadcastServer } from '@matterbridge/thread/server';
|
|
21
22
|
import { MATTER_LOGGER_FILE, MATTER_STORAGE_DIR, MATTERBRIDGE_DIAGNOSTIC_FILE, MATTERBRIDGE_HISTORY_FILE, MATTERBRIDGE_LOGGER_FILE, NODE_STORAGE_DIR, plg, } from '@matterbridge/types';
|
|
22
23
|
import { isBun } from '@matterbridge/utils/bun';
|
|
@@ -1126,11 +1127,12 @@ export class Frontend extends EventEmitter {
|
|
|
1126
1127
|
if (clusterName === 'doorLock' && attributeName === 'lockState')
|
|
1127
1128
|
attributes += `State: ${attributeValue === 1 ? 'Locked' : 'Not locked'} `;
|
|
1128
1129
|
if (clusterName === 'closureControl' && attributeName === 'overallCurrentState' && attributeValue === null)
|
|
1129
|
-
attributes += `Position: unknown Latch: unknown SecureState: unknown `;
|
|
1130
|
+
attributes += `Position: unknown Latch: unknown Speed: unknown SecureState: unknown `;
|
|
1130
1131
|
if (clusterName === 'closureControl' && attributeName === 'overallCurrentState' && isValidObject(attributeValue)) {
|
|
1131
1132
|
const overallCurrentState = attributeValue;
|
|
1132
1133
|
attributes += `Position: ${getEnumDescription(ClosureControl.CurrentPosition, overallCurrentState.position, { fallback: 'unknown' })} `;
|
|
1133
1134
|
attributes += `Latch: ${overallCurrentState.latch ?? 'unknown'} `;
|
|
1135
|
+
attributes += `Speed: ${getEnumDescription(ThreeLevelAuto, overallCurrentState.speed, { fallback: 'unknown' })} `;
|
|
1134
1136
|
attributes += `SecureState: ${overallCurrentState.secureState ?? 'unknown'} `;
|
|
1135
1137
|
}
|
|
1136
1138
|
if (clusterName === 'thermostat' && attributeName === 'localTemperature' && isValidNumber(attributeValue))
|
|
@@ -376,6 +376,13 @@ export type CommandHandlerDataMap = {
|
|
|
376
376
|
attributes: ClusterAttributeValues<(typeof ClosureControl)['attributes']>;
|
|
377
377
|
endpoint: MatterbridgeEndpoint;
|
|
378
378
|
};
|
|
379
|
+
'ClosureControl.calibrate': {
|
|
380
|
+
command: 'calibrate';
|
|
381
|
+
request: {};
|
|
382
|
+
cluster: 'closureControl';
|
|
383
|
+
attributes: ClusterAttributeValues<(typeof ClosureControl)['attributes']>;
|
|
384
|
+
endpoint: MatterbridgeEndpoint;
|
|
385
|
+
};
|
|
379
386
|
'setTarget': CommandHandlerData<'ClosureDimension.setTarget'>;
|
|
380
387
|
'ClosureDimension.setTarget': {
|
|
381
388
|
command: 'setTarget';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@matterbridge/core",
|
|
3
|
-
"version": "3.10.
|
|
3
|
+
"version": "3.10.7-dev-20260823-f911eb8",
|
|
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.
|
|
136
|
-
"@matterbridge/thread": "3.10.
|
|
137
|
-
"@matterbridge/types": "3.10.
|
|
138
|
-
"@matterbridge/utils": "3.10.
|
|
135
|
+
"@matterbridge/dgram": "3.10.7-dev-20260823-f911eb8",
|
|
136
|
+
"@matterbridge/thread": "3.10.7-dev-20260823-f911eb8",
|
|
137
|
+
"@matterbridge/types": "3.10.7-dev-20260823-f911eb8",
|
|
138
|
+
"@matterbridge/utils": "3.10.7-dev-20260823-f911eb8",
|
|
139
139
|
"escape-html": "1.0.3",
|
|
140
140
|
"express": "5.2.1",
|
|
141
141
|
"express-rate-limit": "8.6.2",
|