@matterbridge/core 3.10.7-dev-20260825-7ebac36 → 3.10.7-dev-20260827-957ddcc
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/booleanStateConfigurationServer.js +7 -7
- package/dist/chipTests.js +92 -0
- package/dist/demoDevices.js +160 -7
- package/dist/devices/dishwasher.d.ts +4 -0
- package/dist/devices/dishwasher.js +10 -5
- package/dist/devices/laundryWasher.d.ts +11 -1
- package/dist/devices/laundryWasher.js +18 -9
- package/dist/devices/microwaveOven.d.ts +1 -1
- package/dist/devices/microwaveOven.js +10 -2
- package/dist/devices/oven.d.ts +9 -1
- package/dist/devices/oven.js +22 -3
- package/dist/devices/refrigerator.d.ts +4 -0
- package/dist/devices/refrigerator.js +18 -3
- package/dist/devices/roboticVacuumCleaner.d.ts +14 -1
- package/dist/devices/roboticVacuumCleaner.js +104 -14
- package/package.json +5 -5
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { BooleanStateConfigurationServer } from '@matter/node/behaviors/boolean-state-configuration';
|
|
2
2
|
import { Status, StatusResponseError } from '@matter/types';
|
|
3
3
|
import { BooleanStateConfiguration } from '@matter/types/clusters/boolean-state-configuration';
|
|
4
|
-
import { debugStringify } from 'node-ansi-logger';
|
|
4
|
+
import { debugStringify, nf } from 'node-ansi-logger';
|
|
5
5
|
import { MatterbridgeServer } from './matterbridgeServer.js';
|
|
6
6
|
export class MatterbridgeBooleanStateConfigurationServer extends BooleanStateConfigurationServer.with(BooleanStateConfiguration.Feature.Visual, BooleanStateConfiguration.Feature.Audible, BooleanStateConfiguration.Feature.AlarmSuppress, BooleanStateConfiguration.Feature.SensitivityLevel, BooleanStateConfiguration.Feature.FaultEvents) {
|
|
7
7
|
initialize() {
|
|
@@ -44,7 +44,7 @@ export class MatterbridgeBooleanStateConfigurationServer extends BooleanStateCon
|
|
|
44
44
|
}
|
|
45
45
|
#assertAlarmModesSupported(alarms) {
|
|
46
46
|
if ([Boolean(alarms.visual && !this.state.alarmsSupported.visual), Boolean(alarms.audible && !this.state.alarmsSupported.audible)].some(Boolean)) {
|
|
47
|
-
throw new StatusResponseError(
|
|
47
|
+
throw new StatusResponseError(`MatterbridgeBooleanStateConfigurationServer: requested alarm mode is not supported (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`, Status.ConstraintError);
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
#assertSuppressAlarmAllowed(alarmsToSuppress) {
|
|
@@ -52,12 +52,12 @@ export class MatterbridgeBooleanStateConfigurationServer extends BooleanStateCon
|
|
|
52
52
|
Boolean(alarmsToSuppress.visual && (!this.state.alarmsActive.visual || !this.state.alarmsEnabled?.visual)),
|
|
53
53
|
Boolean(alarmsToSuppress.audible && (!this.state.alarmsActive.audible || !this.state.alarmsEnabled?.audible)),
|
|
54
54
|
].some(Boolean)) {
|
|
55
|
-
throw new StatusResponseError(
|
|
55
|
+
throw new StatusResponseError(`MatterbridgeBooleanStateConfigurationServer: requested alarm mode is not active (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`, Status.InvalidInState);
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
async suppressAlarm(request) {
|
|
59
59
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
60
|
-
device.log.info(`
|
|
60
|
+
device.log.info(`MatterbridgeBooleanStateConfigurationServer: suppressing alarm ${debugStringify(request.alarmsToSuppress)}${nf} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
61
61
|
await device.commandHandler.executeHandler('BooleanStateConfiguration.suppressAlarm', {
|
|
62
62
|
command: 'suppressAlarm',
|
|
63
63
|
request,
|
|
@@ -69,11 +69,11 @@ export class MatterbridgeBooleanStateConfigurationServer extends BooleanStateCon
|
|
|
69
69
|
this.#assertAlarmModesSupported(request.alarmsToSuppress);
|
|
70
70
|
this.#assertSuppressAlarmAllowed(request.alarmsToSuppress);
|
|
71
71
|
this.state.alarmsSuppressed = this.#mergeAlarmsSuppressed(request.alarmsToSuppress);
|
|
72
|
-
device.log.debug(`MatterbridgeBooleanStateConfigurationServer: suppressAlarm called`);
|
|
72
|
+
device.log.debug(`MatterbridgeBooleanStateConfigurationServer: suppressAlarm called (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
73
73
|
}
|
|
74
74
|
async enableDisableAlarm(request) {
|
|
75
75
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
76
|
-
device.log.info(`
|
|
76
|
+
device.log.info(`MatterbridgeBooleanStateConfigurationServer: enabling/disabling alarm ${debugStringify(request.alarmsToEnableDisable)}${nf} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
77
77
|
await device.commandHandler.executeHandler('BooleanStateConfiguration.enableDisableAlarm', {
|
|
78
78
|
command: 'enableDisableAlarm',
|
|
79
79
|
request,
|
|
@@ -84,6 +84,6 @@ export class MatterbridgeBooleanStateConfigurationServer extends BooleanStateCon
|
|
|
84
84
|
});
|
|
85
85
|
this.#assertAlarmModesSupported(request.alarmsToEnableDisable);
|
|
86
86
|
this.#applyAlarmsEnabled(request.alarmsToEnableDisable);
|
|
87
|
-
device.log.debug(`MatterbridgeBooleanStateConfigurationServer: enableDisableAlarm called`);
|
|
87
|
+
device.log.debug(`MatterbridgeBooleanStateConfigurationServer: enableDisableAlarm called (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
88
88
|
}
|
|
89
89
|
}
|
package/dist/chipTests.js
CHANGED
|
@@ -11,9 +11,14 @@ import { DeviceEnergyManagement } from '@matter/types/clusters/device-energy-man
|
|
|
11
11
|
import { ElectricalEnergyMeasurement } from '@matter/types/clusters/electrical-energy-measurement';
|
|
12
12
|
import { ElectricalPowerMeasurement } from '@matter/types/clusters/electrical-power-measurement';
|
|
13
13
|
import { OperationalState } from '@matter/types/clusters/operational-state';
|
|
14
|
+
import { RefrigeratorAlarm } from '@matter/types/clusters/refrigerator-alarm';
|
|
15
|
+
import { RvcOperationalState } from '@matter/types/clusters/rvc-operational-state';
|
|
16
|
+
import { RvcRunMode } from '@matter/types/clusters/rvc-run-mode';
|
|
14
17
|
import { SmokeCoAlarm } from '@matter/types/clusters/smoke-co-alarm';
|
|
15
18
|
import { MatterbridgeOccupancySensingServer } from './behaviors/occupancySensingServer.js';
|
|
16
19
|
import { cliEmitter } from './cliEmitter.js';
|
|
20
|
+
import { MatterbridgeRefrigeratorAlarmServer } from './devices/refrigerator.js';
|
|
21
|
+
import { MatterbridgeRvcOperationalStateServer, MatterbridgeRvcRunModeServer } from './devices/roboticVacuumCleaner.js';
|
|
17
22
|
import { MatterbridgeEndpoint } from './matterbridgeEndpoint.js';
|
|
18
23
|
const chipTestAppPipePath = '/tmp/matterbridge-chip-test-app-pipe';
|
|
19
24
|
const chipTestValidEventTrigger = 0xfffffffffff10000n;
|
|
@@ -564,6 +569,73 @@ async function handleChipTestAppPipeCommand(matterbridge, command) {
|
|
|
564
569
|
return;
|
|
565
570
|
}
|
|
566
571
|
switch (command.Name) {
|
|
572
|
+
case 'Reset': {
|
|
573
|
+
if (!endpoint.behaviors.has(MatterbridgeRvcRunModeServer) || !endpoint.behaviors.has(MatterbridgeRvcOperationalStateServer)) {
|
|
574
|
+
matterbridge.log.warn(`Ignoring RVC Reset CHIP test app pipe command on non-RVC endpoint ${endpointId}`);
|
|
575
|
+
return;
|
|
576
|
+
}
|
|
577
|
+
const runModeState = endpoint.stateOf(MatterbridgeRvcRunModeServer);
|
|
578
|
+
const idleMode = runModeState.supportedModes.find((mode) => mode.modeTags.some((tag) => tag.value === RvcRunMode.ModeTag.Idle));
|
|
579
|
+
if (!idleMode) {
|
|
580
|
+
matterbridge.log.warn(`Ignoring RVC Reset CHIP test app pipe command because endpoint ${endpointId} has no Idle run mode`);
|
|
581
|
+
return;
|
|
582
|
+
}
|
|
583
|
+
await endpoint.setStateOf(MatterbridgeRvcRunModeServer, { currentMode: idleMode.mode });
|
|
584
|
+
await endpoint.setStateOf(MatterbridgeRvcOperationalStateServer, {
|
|
585
|
+
operationalState: RvcOperationalState.OperationalState.Stopped,
|
|
586
|
+
operationalError: { errorStateId: RvcOperationalState.ErrorState.NoError, errorStateDetails: 'Fully operational' },
|
|
587
|
+
});
|
|
588
|
+
matterbridge.log.info(`CHIP test app pipe reset RVC endpoint ${endpointId}`);
|
|
589
|
+
return;
|
|
590
|
+
}
|
|
591
|
+
case 'ErrorEvent': {
|
|
592
|
+
const errorStates = {
|
|
593
|
+
UnableToStartOrResume: RvcOperationalState.ErrorState.UnableToStartOrResume,
|
|
594
|
+
UnableToCompleteOperation: RvcOperationalState.ErrorState.UnableToCompleteOperation,
|
|
595
|
+
CommandInvalidInState: RvcOperationalState.ErrorState.CommandInvalidInState,
|
|
596
|
+
FailedToFindChargingDock: RvcOperationalState.ErrorState.FailedToFindChargingDock,
|
|
597
|
+
Stuck: RvcOperationalState.ErrorState.Stuck,
|
|
598
|
+
DustBinMissing: RvcOperationalState.ErrorState.DustBinMissing,
|
|
599
|
+
DustBinFull: RvcOperationalState.ErrorState.DustBinFull,
|
|
600
|
+
WaterTankEmpty: RvcOperationalState.ErrorState.WaterTankEmpty,
|
|
601
|
+
WaterTankMissing: RvcOperationalState.ErrorState.WaterTankMissing,
|
|
602
|
+
WaterTankLidOpen: RvcOperationalState.ErrorState.WaterTankLidOpen,
|
|
603
|
+
MopCleaningPadMissing: RvcOperationalState.ErrorState.MopCleaningPadMissing,
|
|
604
|
+
BatteryLow: RvcOperationalState.ErrorState.LowBattery,
|
|
605
|
+
CannotReachTargetArea: RvcOperationalState.ErrorState.CannotReachTargetArea,
|
|
606
|
+
DirtyWaterTankFull: RvcOperationalState.ErrorState.DirtyWaterTankFull,
|
|
607
|
+
DirtyWaterTankMissing: RvcOperationalState.ErrorState.DirtyWaterTankMissing,
|
|
608
|
+
WheelsJammed: RvcOperationalState.ErrorState.WheelsJammed,
|
|
609
|
+
BrushJammed: RvcOperationalState.ErrorState.BrushJammed,
|
|
610
|
+
NavigationSensorObscured: RvcOperationalState.ErrorState.NavigationSensorObscured,
|
|
611
|
+
};
|
|
612
|
+
const errorStateId = command.Error === undefined ? undefined : errorStates[command.Error];
|
|
613
|
+
if (errorStateId === undefined) {
|
|
614
|
+
matterbridge.log.warn(`Ignoring unsupported RVC ErrorEvent CHIP test app pipe command: ${JSON.stringify(command)}`);
|
|
615
|
+
return;
|
|
616
|
+
}
|
|
617
|
+
await endpoint.setStateOf(MatterbridgeRvcOperationalStateServer, {
|
|
618
|
+
operationalState: RvcOperationalState.OperationalState.Error,
|
|
619
|
+
operationalError: { errorStateId, errorStateDetails: 'Simulated CHIP test fault' },
|
|
620
|
+
});
|
|
621
|
+
matterbridge.log.info(`CHIP test app pipe set RVC OperationalError to ${command.Error} on endpoint ${endpointId}`);
|
|
622
|
+
return;
|
|
623
|
+
}
|
|
624
|
+
case 'ChargerFound':
|
|
625
|
+
case 'Charging':
|
|
626
|
+
await endpoint.setStateOf(MatterbridgeRvcOperationalStateServer, { operationalState: RvcOperationalState.OperationalState.Charging });
|
|
627
|
+
matterbridge.log.info(`CHIP test app pipe set RVC OperationalState to Charging on endpoint ${endpointId}`);
|
|
628
|
+
return;
|
|
629
|
+
case 'Charged':
|
|
630
|
+
case 'Docked': {
|
|
631
|
+
const runModeState = endpoint.stateOf(MatterbridgeRvcRunModeServer);
|
|
632
|
+
const idleMode = runModeState.supportedModes.find((mode) => mode.modeTags.some((tag) => tag.value === RvcRunMode.ModeTag.Idle));
|
|
633
|
+
if (idleMode)
|
|
634
|
+
await endpoint.setStateOf(MatterbridgeRvcRunModeServer, { currentMode: idleMode.mode });
|
|
635
|
+
await endpoint.setStateOf(MatterbridgeRvcOperationalStateServer, { operationalState: RvcOperationalState.OperationalState.Docked });
|
|
636
|
+
matterbridge.log.info(`CHIP test app pipe set RVC OperationalState to Docked on endpoint ${endpointId}`);
|
|
637
|
+
return;
|
|
638
|
+
}
|
|
567
639
|
case 'SetBooleanState':
|
|
568
640
|
await endpoint.setStateOf(endpoint.behaviors.supported.booleanState, { stateValue: Boolean(command.NewState) });
|
|
569
641
|
matterbridge.log.info(`CHIP test app pipe set BooleanState.StateValue to ${Boolean(command.NewState)} on endpoint ${endpointId}`);
|
|
@@ -580,6 +652,26 @@ async function handleChipTestAppPipeCommand(matterbridge, command) {
|
|
|
580
652
|
await endpoint.setStateOf(endpoint.behaviors.supported.soilMeasurement, { soilMoistureMeasuredValue: command.SoilMoistureValue ?? null });
|
|
581
653
|
matterbridge.log.info(`CHIP test app pipe set SoilMeasurement.SoilMoistureMeasuredValue to ${command.SoilMoistureValue ?? null} on endpoint ${endpointId}`);
|
|
582
654
|
return;
|
|
655
|
+
case 'SetRefrigeratorDoorStatus': {
|
|
656
|
+
const doorOpen = Boolean(command.DoorOpen);
|
|
657
|
+
const wasDoorOpen = Boolean(endpoint.stateOf(MatterbridgeRefrigeratorAlarmServer).state.doorOpen);
|
|
658
|
+
await endpoint.setCluster(RefrigeratorAlarm, { state: { doorOpen } }, matterbridge.log);
|
|
659
|
+
await endpoint.triggerEvent('RefrigeratorAlarm', 'notify', {
|
|
660
|
+
active: { doorOpen: doorOpen && !wasDoorOpen },
|
|
661
|
+
inactive: { doorOpen: !doorOpen && wasDoorOpen },
|
|
662
|
+
state: { doorOpen },
|
|
663
|
+
mask: endpoint.stateOf(MatterbridgeRefrigeratorAlarmServer).mask,
|
|
664
|
+
}, matterbridge.log);
|
|
665
|
+
matterbridge.log.info(`CHIP test app pipe set RefrigeratorAlarm.State.DoorOpen to ${doorOpen} on endpoint ${endpointId}`);
|
|
666
|
+
return;
|
|
667
|
+
}
|
|
668
|
+
case 'ModeChange':
|
|
669
|
+
if (command.Device === 'DishWasher' && command.Type === 'ToggleFailTransition') {
|
|
670
|
+
matterbridge.log.info(`CHIP test app pipe prepared DishwasherMode for a successful transition on endpoint ${endpointId}`);
|
|
671
|
+
return;
|
|
672
|
+
}
|
|
673
|
+
matterbridge.log.warn(`Ignoring unsupported ModeChange CHIP test app pipe command: ${JSON.stringify(command)}`);
|
|
674
|
+
return;
|
|
583
675
|
case 'OperationalStateChange':
|
|
584
676
|
switch (command.Operation) {
|
|
585
677
|
case 'Stop':
|
package/dist/demoDevices.js
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
1
3
|
import { ClosureTag, ClosureWindowTag, CommonNumberTag, CommonPositionTag, RefrigeratorTag } from '@matter/node';
|
|
2
4
|
import { AirQuality } from '@matter/types/clusters/air-quality';
|
|
3
5
|
import { FanControl } from '@matter/types/clusters/fan-control';
|
|
4
6
|
import { PowerSource } from '@matter/types/clusters/power-source';
|
|
7
|
+
import { ResourceMonitoring } from '@matter/types/clusters/resource-monitoring';
|
|
8
|
+
import { RvcCleanMode } from '@matter/types/clusters/rvc-clean-mode';
|
|
9
|
+
import { RvcRunMode } from '@matter/types/clusters/rvc-run-mode';
|
|
5
10
|
import { EndpointNumber } from '@matter/types/datatype';
|
|
11
|
+
import { getErrorMessage } from '@matterbridge/utils/error';
|
|
6
12
|
import { AirConditioner } from './devices/airConditioner.js';
|
|
7
13
|
import { BasicVideoPlayer } from './devices/basicVideoPlayer.js';
|
|
8
14
|
import { CastingVideoClient } from './devices/castingVideoClient.js';
|
|
@@ -24,32 +30,138 @@ import { VideoRemoteControl } from './devices/videoRemoteControl.js';
|
|
|
24
30
|
import { getSupportedDeviceType } from './matterbridgeDeviceTypes.js';
|
|
25
31
|
import { MatterbridgeEndpoint } from './matterbridgeEndpoint.js';
|
|
26
32
|
import { getSemtag } from './matterbridgeEndpointHelpers.js';
|
|
33
|
+
const demoPluginName = 'matterbridge-demo-devices';
|
|
34
|
+
const demoPluginType = 'DynamicPlatform';
|
|
35
|
+
const demoPluginVersion = '1.0.0';
|
|
36
|
+
const demoPluginSchema = {
|
|
37
|
+
title: 'Matterbridge Demo Devices',
|
|
38
|
+
description: `${demoPluginName} v. ${demoPluginVersion} by Matterbridge`,
|
|
39
|
+
type: 'object',
|
|
40
|
+
properties: {
|
|
41
|
+
name: {
|
|
42
|
+
'description': 'Plugin name',
|
|
43
|
+
'type': 'string',
|
|
44
|
+
'readOnly': true,
|
|
45
|
+
'ui:widget': 'hidden',
|
|
46
|
+
},
|
|
47
|
+
type: {
|
|
48
|
+
'description': 'Plugin type',
|
|
49
|
+
'type': 'string',
|
|
50
|
+
'readOnly': true,
|
|
51
|
+
'ui:widget': 'hidden',
|
|
52
|
+
},
|
|
53
|
+
version: {
|
|
54
|
+
'description': 'Plugin version',
|
|
55
|
+
'type': 'string',
|
|
56
|
+
'readOnly': true,
|
|
57
|
+
'default': demoPluginVersion,
|
|
58
|
+
'ui:widget': 'hidden',
|
|
59
|
+
},
|
|
60
|
+
whiteList: {
|
|
61
|
+
description: 'Only the devices in the list will be exposed. If the list is empty, all devices will be exposed.',
|
|
62
|
+
type: 'array',
|
|
63
|
+
items: { type: 'string' },
|
|
64
|
+
default: [],
|
|
65
|
+
uniqueItems: true,
|
|
66
|
+
selectFrom: 'name',
|
|
67
|
+
},
|
|
68
|
+
blackList: {
|
|
69
|
+
description: 'The devices in the list will not be exposed. If the list is empty, no devices will be excluded.',
|
|
70
|
+
type: 'array',
|
|
71
|
+
items: { type: 'string' },
|
|
72
|
+
default: [],
|
|
73
|
+
uniqueItems: true,
|
|
74
|
+
selectFrom: 'name',
|
|
75
|
+
},
|
|
76
|
+
debug: {
|
|
77
|
+
description: 'Enable debug logging for the plugin.',
|
|
78
|
+
type: 'boolean',
|
|
79
|
+
default: false,
|
|
80
|
+
},
|
|
81
|
+
unregisterOnShutdown: {
|
|
82
|
+
description: 'Unregister all devices when the plugin is stopped.',
|
|
83
|
+
type: 'boolean',
|
|
84
|
+
default: false,
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
};
|
|
27
88
|
export async function createDemoDevices(matterbridge) {
|
|
28
|
-
if (matterbridge.bridgeMode !== 'bridge'
|
|
89
|
+
if (matterbridge.bridgeMode !== 'bridge') {
|
|
90
|
+
matterbridge.log.error('Demo devices can only be created in bridge mode');
|
|
29
91
|
return;
|
|
92
|
+
}
|
|
30
93
|
const serverNode = matterbridge.serverNode;
|
|
31
94
|
const aggregator = matterbridge.aggregatorNode;
|
|
32
95
|
if (!serverNode || !aggregator) {
|
|
33
96
|
matterbridge.log.error('Demo devices can only be created when the server node and aggregator node are available');
|
|
34
97
|
return;
|
|
35
98
|
}
|
|
99
|
+
const configFile = path.join(matterbridge.matterbridgeDirectory, `${demoPluginName}.config.json`);
|
|
100
|
+
const schemaFile = path.join(matterbridge.matterbridgeDirectory, `${demoPluginName}.schema.json`);
|
|
101
|
+
const defaultConfig = {
|
|
102
|
+
name: demoPluginName,
|
|
103
|
+
type: demoPluginType,
|
|
104
|
+
version: demoPluginVersion,
|
|
105
|
+
debug: false,
|
|
106
|
+
unregisterOnShutdown: false,
|
|
107
|
+
whiteList: [],
|
|
108
|
+
blackList: [],
|
|
109
|
+
};
|
|
110
|
+
let config = defaultConfig;
|
|
111
|
+
try {
|
|
112
|
+
const storedConfig = JSON.parse(await readFile(configFile, 'utf8'));
|
|
113
|
+
config = {
|
|
114
|
+
...defaultConfig,
|
|
115
|
+
...storedConfig,
|
|
116
|
+
name: demoPluginName,
|
|
117
|
+
type: demoPluginType,
|
|
118
|
+
version: demoPluginVersion,
|
|
119
|
+
whiteList: Array.isArray(storedConfig.whiteList) ? storedConfig.whiteList : [],
|
|
120
|
+
blackList: Array.isArray(storedConfig.blackList) ? storedConfig.blackList : [],
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
if (error.code !== 'ENOENT')
|
|
125
|
+
matterbridge.log.error(`Failed to read demo devices config ${configFile}: ${getErrorMessage(error)}`);
|
|
126
|
+
}
|
|
127
|
+
try {
|
|
128
|
+
await writeFile(configFile, JSON.stringify(config, null, 2), 'utf8');
|
|
129
|
+
await writeFile(schemaFile, JSON.stringify(demoPluginSchema, null, 2), 'utf8');
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
matterbridge.log.error(`Failed to write demo devices config or schema: ${getErrorMessage(error)}`);
|
|
133
|
+
}
|
|
36
134
|
let ep;
|
|
37
135
|
matterbridge.plugins.set({
|
|
38
|
-
name:
|
|
136
|
+
name: demoPluginName,
|
|
39
137
|
path: '',
|
|
40
|
-
type:
|
|
41
|
-
version:
|
|
138
|
+
type: demoPluginType,
|
|
139
|
+
version: demoPluginVersion,
|
|
42
140
|
description: 'Matterbridge demo devices',
|
|
43
141
|
author: 'Matterbridge',
|
|
44
142
|
enabled: false,
|
|
45
143
|
private: true,
|
|
46
144
|
registeredDevices: 0,
|
|
145
|
+
configJson: config,
|
|
146
|
+
schemaJson: demoPluginSchema,
|
|
147
|
+
hasWhiteList: true,
|
|
148
|
+
hasBlackList: true,
|
|
47
149
|
});
|
|
48
150
|
const registerDevice = async (device, deviceName, serialNumber) => {
|
|
151
|
+
const whiteList = config.whiteList;
|
|
152
|
+
const blackList = config.blackList;
|
|
153
|
+
if (blackList.includes(deviceName)) {
|
|
154
|
+
matterbridge.log.info(`Skipping demo device ${deviceName} because it is in the blacklist`);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
if (whiteList.length > 0 && !whiteList.includes(deviceName)) {
|
|
158
|
+
matterbridge.log.info(`Skipping demo device ${deviceName} because it is not in the whitelist`);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
49
161
|
device.createDefaultBridgedDeviceBasicInformationClusterServer(deviceName, serialNumber);
|
|
50
162
|
device.addRequiredClusters();
|
|
51
|
-
device.plugin =
|
|
52
|
-
await matterbridge.addBridgedEndpoint(
|
|
163
|
+
device.plugin = demoPluginName;
|
|
164
|
+
await matterbridge.addBridgedEndpoint(demoPluginName, device);
|
|
53
165
|
};
|
|
54
166
|
const bridgedNode = getSupportedDeviceType('BridgedNode');
|
|
55
167
|
const powerSource = getSupportedDeviceType('PowerSource');
|
|
@@ -353,14 +465,37 @@ export async function createDemoDevices(matterbridge) {
|
|
|
353
465
|
id: 'RoboticVacuumCleaner',
|
|
354
466
|
number: EndpointNumber(12_01),
|
|
355
467
|
tagList: [getSemtag(CommonNumberTag.One)],
|
|
468
|
+
currentRunMode: 0,
|
|
469
|
+
supportedRunModes: [
|
|
470
|
+
{ label: 'Idle', mode: 0, modeTags: [{ value: RvcRunMode.ModeTag.Idle }] },
|
|
471
|
+
{ label: 'Cleaning', mode: 1, modeTags: [{ value: RvcRunMode.ModeTag.Cleaning }] },
|
|
472
|
+
{ label: 'Mapping', mode: 2, modeTags: [{ value: RvcRunMode.ModeTag.Mapping }] },
|
|
473
|
+
{ label: 'SpotCleaning', mode: 3, modeTags: [{ value: RvcRunMode.ModeTag.Cleaning }, { value: RvcRunMode.ModeTag.Max }] },
|
|
474
|
+
],
|
|
475
|
+
currentCleanMode: 1,
|
|
476
|
+
supportedCleanModes: [
|
|
477
|
+
{ label: 'Vacuum', mode: 1, modeTags: [{ value: RvcCleanMode.ModeTag.Vacuum }] },
|
|
478
|
+
{ label: 'Mop', mode: 2, modeTags: [{ value: RvcCleanMode.ModeTag.Mop }] },
|
|
479
|
+
{ label: 'DeepClean', mode: 3, modeTags: [{ value: RvcCleanMode.ModeTag.DeepClean }] },
|
|
480
|
+
],
|
|
356
481
|
});
|
|
357
482
|
await registerDevice(ep, 'Robotic Vacuum Cleaner', 'ROBOTIC-12-01');
|
|
358
|
-
ep = new LaundryWasher('Laundry Washer', 'APPLIANCE-13-01', {
|
|
483
|
+
ep = new LaundryWasher('Laundry Washer Level Temperature', 'APPLIANCE-13-01', {
|
|
359
484
|
id: 'LaundryWasher',
|
|
360
485
|
number: EndpointNumber(13_01),
|
|
361
486
|
tagList: [getSemtag(CommonNumberTag.One)],
|
|
362
487
|
});
|
|
363
488
|
await registerDevice(ep, 'Laundry Washer', 'APPLIANCE-13-01');
|
|
489
|
+
ep = new LaundryWasher('Laundry Washer Number Temperature', 'APPLIANCE-13-01-2', {
|
|
490
|
+
id: 'LaundryWasherNumberTemperature',
|
|
491
|
+
number: EndpointNumber(13_01_2),
|
|
492
|
+
tagList: [getSemtag(CommonNumberTag.Two)],
|
|
493
|
+
temperatureSetpoint: 40 * 100,
|
|
494
|
+
minTemperature: 30 * 100,
|
|
495
|
+
maxTemperature: 60 * 100,
|
|
496
|
+
step: 10 * 100,
|
|
497
|
+
});
|
|
498
|
+
await registerDevice(ep, 'Laundry Washer Number Temperature', 'APPLIANCE-13-01-2');
|
|
364
499
|
const refrigeratorDevice = new Refrigerator('Refrigerator', 'APPLIANCE-13-02', {
|
|
365
500
|
id: 'Refrigerator',
|
|
366
501
|
number: EndpointNumber(13_02),
|
|
@@ -461,6 +596,24 @@ export async function createDemoDevices(matterbridge) {
|
|
|
461
596
|
id: 'ExtractorHood',
|
|
462
597
|
number: EndpointNumber(13_10),
|
|
463
598
|
tagList: [getSemtag(CommonNumberTag.One)],
|
|
599
|
+
hepaCondition: 30,
|
|
600
|
+
hepaChangeIndication: ResourceMonitoring.ChangeIndication.Warning,
|
|
601
|
+
hepaLastChangedTime: 1_735_689_600,
|
|
602
|
+
hepaReplacementProductList: [
|
|
603
|
+
{
|
|
604
|
+
productIdentifierType: ResourceMonitoring.ProductIdentifierType.Upc,
|
|
605
|
+
productIdentifierValue: '012345678905',
|
|
606
|
+
},
|
|
607
|
+
],
|
|
608
|
+
activatedCarbonCondition: 30,
|
|
609
|
+
activatedCarbonChangeIndication: ResourceMonitoring.ChangeIndication.Warning,
|
|
610
|
+
activatedCarbonLastChangedTime: 1_735_689_600,
|
|
611
|
+
activatedCarbonReplacementProductList: [
|
|
612
|
+
{
|
|
613
|
+
productIdentifierType: ResourceMonitoring.ProductIdentifierType.Ean,
|
|
614
|
+
productIdentifierValue: '4006381333931',
|
|
615
|
+
},
|
|
616
|
+
],
|
|
464
617
|
});
|
|
465
618
|
await registerDevice(ep, 'Extractor Hood', 'APPLIANCE-13-10');
|
|
466
619
|
ep = new MicrowaveOven('Microwave Oven', 'APPLIANCE-13-11', {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { DishwasherAlarmServer } from '@matter/node/behaviors/dishwasher-alarm';
|
|
1
2
|
import { DishwasherModeServer } from '@matter/node/behaviors/dishwasher-mode';
|
|
2
3
|
import type { EndpointNumber } from '@matter/types';
|
|
3
4
|
import { DishwasherMode } from '@matter/types/clusters/dishwasher-mode';
|
|
@@ -31,3 +32,6 @@ export declare class MatterbridgeDishwasherModeServer extends DishwasherModeServ
|
|
|
31
32
|
protected handleOnOffChange(onOff: boolean): void;
|
|
32
33
|
changeToMode(request: ModeBase.ChangeToModeRequest): Promise<ModeBase.ChangeToModeResponse>;
|
|
33
34
|
}
|
|
35
|
+
export declare class MatterbridgeDishwasherAlarmServer extends DishwasherAlarmServer {
|
|
36
|
+
static readonly schema: import("@matter/model").ClusterModel;
|
|
37
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AttributeElement, EventElement, FieldElement } from '@matter/model';
|
|
1
2
|
import { DishwasherAlarmServer } from '@matter/node/behaviors/dishwasher-alarm';
|
|
2
3
|
import { DishwasherModeServer } from '@matter/node/behaviors/dishwasher-mode';
|
|
3
4
|
import { DishwasherMode } from '@matter/types/clusters/dishwasher-mode';
|
|
@@ -53,10 +54,10 @@ export class Dishwasher extends MatterbridgeEndpoint {
|
|
|
53
54
|
return this;
|
|
54
55
|
}
|
|
55
56
|
createDefaultDishwasherAlarmClusterServer() {
|
|
56
|
-
this.behaviors.require(
|
|
57
|
-
mask: { inflowError:
|
|
57
|
+
this.behaviors.require(MatterbridgeDishwasherAlarmServer, {
|
|
58
|
+
mask: { inflowError: false, drainError: false, doorError: true, tempTooLow: false, tempTooHigh: false, waterLevelError: false },
|
|
58
59
|
state: { inflowError: false, drainError: false, doorError: false, tempTooLow: false, tempTooHigh: false, waterLevelError: false },
|
|
59
|
-
supported: { inflowError:
|
|
60
|
+
supported: { inflowError: false, drainError: false, doorError: true, tempTooLow: false, tempTooHigh: false, waterLevelError: false },
|
|
60
61
|
});
|
|
61
62
|
return this;
|
|
62
63
|
}
|
|
@@ -92,8 +93,12 @@ export class MatterbridgeDishwasherModeServer extends DishwasherModeServer {
|
|
|
92
93
|
return { status: ModeBase.ModeChangeStatus.Success, statusText: 'Success' };
|
|
93
94
|
}
|
|
94
95
|
else {
|
|
95
|
-
device.log.error(`DishwasherModeServer: changeToMode called with
|
|
96
|
-
return { status: ModeBase.ModeChangeStatus.
|
|
96
|
+
device.log.error(`DishwasherModeServer: changeToMode called with unsupported mode ${request.newMode}`);
|
|
97
|
+
return { status: ModeBase.ModeChangeStatus.UnsupportedMode, statusText: '' };
|
|
97
98
|
}
|
|
98
99
|
}
|
|
99
100
|
}
|
|
101
|
+
const MatterbridgeDishwasherAlarmSchema = DishwasherAlarmServer.schema.extend({}, AttributeElement({ name: 'Mask', id: 0x0000, type: 'AlarmBitmap', access: 'R V', conformance: 'M' }), AttributeElement({ name: 'State', id: 0x0002, type: 'AlarmBitmap', access: 'R V', conformance: 'M' }), AttributeElement({ name: 'Supported', id: 0x0003, type: 'AlarmBitmap', access: 'R V', conformance: 'M', quality: 'F' }), EventElement({ name: 'Notify', id: 0x0000, access: 'V', conformance: 'M', priority: 'info' }, FieldElement({ name: 'Active', id: 0x0000, type: 'AlarmBitmap', conformance: 'M' }), FieldElement({ name: 'Inactive', id: 0x0001, type: 'AlarmBitmap', conformance: 'M' }), FieldElement({ name: 'State', id: 0x0002, type: 'AlarmBitmap', conformance: 'M' }), FieldElement({ name: 'Mask', id: 0x0003, type: 'AlarmBitmap', conformance: 'M' })));
|
|
102
|
+
export class MatterbridgeDishwasherAlarmServer extends DishwasherAlarmServer {
|
|
103
|
+
static schema = MatterbridgeDishwasherAlarmSchema;
|
|
104
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { LaundryWasherControlsServer } from '@matter/node/behaviors/laundry-washer-controls';
|
|
1
2
|
import { LaundryWasherModeServer } from '@matter/node/behaviors/laundry-washer-mode';
|
|
2
|
-
import type
|
|
3
|
+
import { type EndpointNumber } from '@matter/types';
|
|
3
4
|
import { LaundryWasherControls } from '@matter/types/clusters/laundry-washer-controls';
|
|
4
5
|
import { LaundryWasherMode } from '@matter/types/clusters/laundry-washer-mode';
|
|
5
6
|
import { ModeBase } from '@matter/types/clusters/mode-base';
|
|
@@ -31,8 +32,17 @@ export declare class LaundryWasher extends MatterbridgeEndpoint {
|
|
|
31
32
|
createDefaultLaundryWasherModeClusterServer(currentMode?: number, supportedModes?: LaundryWasherMode.ModeOption[]): this;
|
|
32
33
|
createDefaultLaundryWasherControlsClusterServer(spinSpeedCurrent?: number, spinSpeeds?: string[], numberOfRinses?: LaundryWasherControls.NumberOfRinses, supportedRinses?: LaundryWasherControls.NumberOfRinses[]): this;
|
|
33
34
|
}
|
|
35
|
+
declare const MatterbridgeLaundryWasherControlsServer_base: import("@matter/node").ClusterBehavior.Type<typeof LaundryWasherControlsServer, import("@matter/types").ClusterType.WithSupportedFeatures<LaundryWasherControls, {
|
|
36
|
+
rinse: true;
|
|
37
|
+
spin: true;
|
|
38
|
+
}>, import("@matter/types").ClusterType.Concrete, new () => {}, "laundryWasherControls">;
|
|
39
|
+
export declare class MatterbridgeLaundryWasherControlsServer extends MatterbridgeLaundryWasherControlsServer_base {
|
|
40
|
+
#private;
|
|
41
|
+
initialize(): void;
|
|
42
|
+
}
|
|
34
43
|
export declare class MatterbridgeLaundryWasherModeServer extends LaundryWasherModeServer {
|
|
35
44
|
initialize(): void;
|
|
36
45
|
protected handleOnOffChange(onOff: boolean): void;
|
|
37
46
|
changeToMode(request: ModeBase.ChangeToModeRequest): Promise<ModeBase.ChangeToModeResponse>;
|
|
38
47
|
}
|
|
48
|
+
export {};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { LaundryWasherControlsServer } from '@matter/node/behaviors/laundry-washer-controls';
|
|
2
2
|
import { LaundryWasherModeServer } from '@matter/node/behaviors/laundry-washer-mode';
|
|
3
|
+
import { Status, StatusResponseError } from '@matter/types';
|
|
3
4
|
import { LaundryWasherControls } from '@matter/types/clusters/laundry-washer-controls';
|
|
4
5
|
import { LaundryWasherMode } from '@matter/types/clusters/laundry-washer-mode';
|
|
5
6
|
import { ModeBase } from '@matter/types/clusters/mode-base';
|
|
@@ -64,7 +65,7 @@ export class LaundryWasher extends MatterbridgeEndpoint {
|
|
|
64
65
|
LaundryWasherControls.NumberOfRinses.Max,
|
|
65
66
|
LaundryWasherControls.NumberOfRinses.Extra,
|
|
66
67
|
]) {
|
|
67
|
-
this.behaviors.require(
|
|
68
|
+
this.behaviors.require(MatterbridgeLaundryWasherControlsServer, {
|
|
68
69
|
spinSpeeds,
|
|
69
70
|
spinSpeedCurrent,
|
|
70
71
|
supportedRinses,
|
|
@@ -73,6 +74,16 @@ export class LaundryWasher extends MatterbridgeEndpoint {
|
|
|
73
74
|
return this;
|
|
74
75
|
}
|
|
75
76
|
}
|
|
77
|
+
export class MatterbridgeLaundryWasherControlsServer extends LaundryWasherControlsServer.with(LaundryWasherControls.Feature.Spin, LaundryWasherControls.Feature.Rinse) {
|
|
78
|
+
initialize() {
|
|
79
|
+
this.reactTo(this.events.spinSpeedCurrent$Changing, this.#validateSpinSpeedCurrent);
|
|
80
|
+
}
|
|
81
|
+
#validateSpinSpeedCurrent(spinSpeedCurrent) {
|
|
82
|
+
if (spinSpeedCurrent !== null && spinSpeedCurrent >= this.state.spinSpeeds.length) {
|
|
83
|
+
throw new StatusResponseError(`SpinSpeedCurrent ${spinSpeedCurrent} is not a valid SpinSpeeds index`, Status.ConstraintError);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
76
87
|
export class MatterbridgeLaundryWasherModeServer extends LaundryWasherModeServer {
|
|
77
88
|
initialize() {
|
|
78
89
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
@@ -98,14 +109,12 @@ export class MatterbridgeLaundryWasherModeServer extends LaundryWasherModeServer
|
|
|
98
109
|
endpoint: this.endpoint,
|
|
99
110
|
});
|
|
100
111
|
const supportedMode = this.state.supportedModes.find((supportedMode) => supportedMode.mode === request.newMode);
|
|
101
|
-
if (supportedMode) {
|
|
102
|
-
device.log.
|
|
103
|
-
|
|
104
|
-
return { status: ModeBase.ModeChangeStatus.Success, statusText: 'Success' };
|
|
105
|
-
}
|
|
106
|
-
else {
|
|
107
|
-
device.log.error(`MatterbridgeLaundryWasherModeServer: changeToMode called with invalid mode ${request.newMode}`);
|
|
108
|
-
return { status: ModeBase.ModeChangeStatus.InvalidInMode, statusText: 'Invalid mode' };
|
|
112
|
+
if (!supportedMode) {
|
|
113
|
+
device.log.error(`MatterbridgeLaundryWasherModeServer: changeToMode called with unsupported mode ${request.newMode}`);
|
|
114
|
+
return { status: ModeBase.ModeChangeStatus.UnsupportedMode, statusText: '' };
|
|
109
115
|
}
|
|
116
|
+
device.log.debug(`MatterbridgeLaundryWasherModeServer: changeToMode called with mode ${supportedMode.mode} => ${supportedMode.label}`);
|
|
117
|
+
this.state.currentMode = request.newMode;
|
|
118
|
+
return { status: ModeBase.ModeChangeStatus.Success, statusText: 'Success' };
|
|
110
119
|
}
|
|
111
120
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { MicrowaveOvenControlServer } from '@matter/node/behaviors/microwave-oven-control';
|
|
2
|
-
import type
|
|
2
|
+
import { type EndpointNumber } from '@matter/types';
|
|
3
3
|
import { MicrowaveOvenControl } from '@matter/types/clusters/microwave-oven-control';
|
|
4
4
|
import { MicrowaveOvenMode } from '@matter/types/clusters/microwave-oven-mode';
|
|
5
5
|
import type { Semtag } from '@matter/types/globals';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { MicrowaveOvenControlServer } from '@matter/node/behaviors/microwave-oven-control';
|
|
2
2
|
import { MicrowaveOvenModeServer } from '@matter/node/behaviors/microwave-oven-mode';
|
|
3
|
+
import { Status, StatusResponseError } from '@matter/types';
|
|
3
4
|
import { MicrowaveOvenControl } from '@matter/types/clusters/microwave-oven-control';
|
|
4
5
|
import { MicrowaveOvenMode } from '@matter/types/clusters/microwave-oven-mode';
|
|
5
6
|
import { OperationalState } from '@matter/types/clusters/operational-state';
|
|
@@ -62,6 +63,13 @@ export class MatterbridgeMicrowaveOvenControlServer extends MicrowaveOvenControl
|
|
|
62
63
|
async setCookingParameters(request) {
|
|
63
64
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
64
65
|
device.log.info(`MatterbridgeMicrowaveOvenControlServer: setCookingParameters (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
66
|
+
if (request.cookTime !== undefined && (request.cookTime < 1 || request.cookTime > this.state.maxCookTime)) {
|
|
67
|
+
throw new StatusResponseError(`CookTime ${request.cookTime} must be between 1 and MaxCookTime ${this.state.maxCookTime}`, Status.ConstraintError);
|
|
68
|
+
}
|
|
69
|
+
if (request.powerSetting !== undefined &&
|
|
70
|
+
(request.powerSetting < this.state.minPower || request.powerSetting > this.state.maxPower || (request.powerSetting - this.state.minPower) % this.state.powerStep !== 0)) {
|
|
71
|
+
throw new StatusResponseError(`PowerSetting ${request.powerSetting} must be between MinPower ${this.state.minPower} and MaxPower ${this.state.maxPower} in steps of ${this.state.powerStep}`, Status.ConstraintError);
|
|
72
|
+
}
|
|
65
73
|
await device.commandHandler.executeHandler('MicrowaveOvenControl.setCookingParameters', {
|
|
66
74
|
command: 'setCookingParameters',
|
|
67
75
|
request,
|
|
@@ -79,7 +87,7 @@ export class MatterbridgeMicrowaveOvenControlServer extends MicrowaveOvenControl
|
|
|
79
87
|
const normalMode = supportedModes.find((mode) => mode.modeTags.some((tag) => tag.value === MicrowaveOvenMode.ModeTag.Normal));
|
|
80
88
|
await this.endpoint.setStateOf(MicrowaveOvenModeServer, { currentMode: normalMode?.mode });
|
|
81
89
|
}
|
|
82
|
-
if (request.cookTime !== undefined
|
|
90
|
+
if (request.cookTime !== undefined) {
|
|
83
91
|
device.log.info(`MatterbridgeMicrowaveOvenControlServer: setCookingParameters called setting cookTime to ${request.cookTime}`);
|
|
84
92
|
this.state.cookTime = request.cookTime;
|
|
85
93
|
}
|
|
@@ -87,7 +95,7 @@ export class MatterbridgeMicrowaveOvenControlServer extends MicrowaveOvenControl
|
|
|
87
95
|
device.log.info(`MatterbridgeMicrowaveOvenControlServer: setCookingParameters called with no cookTime so set to 30sec.`);
|
|
88
96
|
this.state.cookTime = 30;
|
|
89
97
|
}
|
|
90
|
-
if (request.powerSetting !== undefined
|
|
98
|
+
if (request.powerSetting !== undefined) {
|
|
91
99
|
device.log.info(`MatterbridgeMicrowaveOvenControlServer: setCookingParameters called setting powerSetting to ${request.powerSetting}`);
|
|
92
100
|
this.state.powerSetting = request.powerSetting;
|
|
93
101
|
}
|
package/dist/devices/oven.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { ModeBase } from '@matter/types/clusters/mode-base';
|
|
|
6
6
|
import { OperationalState } from '@matter/types/clusters/operational-state';
|
|
7
7
|
import { OvenMode } from '@matter/types/clusters/oven-mode';
|
|
8
8
|
import { MatterbridgeEndpoint } from '../matterbridgeEndpoint.js';
|
|
9
|
+
declare const MatterbridgeOvenCavityOperationalStateServerBase: import("@matter/node").ClusterBehavior.Type<typeof OvenCavityOperationalStateServer, import("@matter/types").ClusterType.WithEnabledAttributes<import("@matter/types").ClusterType.WithEnabledEvents<import("@matter/types/clusters/oven-cavity-operational-state").OvenCavityOperationalState, "operationCompletion">, never>, import("@matter/types").ClusterType.Concrete, new () => {}, "ovenCavityOperationalState">;
|
|
9
10
|
export interface OvenOptions {
|
|
10
11
|
mode?: 'server' | 'matter';
|
|
11
12
|
id?: string;
|
|
@@ -38,8 +39,15 @@ export declare class MatterbridgeOvenModeServer extends OvenModeServer {
|
|
|
38
39
|
initialize(): void;
|
|
39
40
|
changeToMode(request: ModeBase.ChangeToModeRequest): MaybePromise<ModeBase.ChangeToModeResponse>;
|
|
40
41
|
}
|
|
41
|
-
export declare class MatterbridgeOvenCavityOperationalStateServer extends
|
|
42
|
+
export declare class MatterbridgeOvenCavityOperationalStateServer extends MatterbridgeOvenCavityOperationalStateServerBase {
|
|
43
|
+
protected internal: MatterbridgeOvenCavityOperationalStateServer.Internal;
|
|
42
44
|
initialize(): void;
|
|
43
45
|
stop(): MaybePromise<OperationalState.OperationalCommandResponse>;
|
|
44
46
|
start(): MaybePromise<OperationalState.OperationalCommandResponse>;
|
|
45
47
|
}
|
|
48
|
+
export declare namespace MatterbridgeOvenCavityOperationalStateServer {
|
|
49
|
+
class Internal extends MatterbridgeOvenCavityOperationalStateServerBase.Internal {
|
|
50
|
+
operationStartedAt: number | undefined;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
export {};
|
package/dist/devices/oven.js
CHANGED
|
@@ -8,6 +8,7 @@ import { MatterbridgeServer } from '../behaviors/matterbridgeServer.js';
|
|
|
8
8
|
import { oven, powerSource, temperatureControlledCabinetHeater } from '../matterbridgeDeviceTypes.js';
|
|
9
9
|
import { MatterbridgeEndpoint } from '../matterbridgeEndpoint.js';
|
|
10
10
|
import { createNumberTemperatureControlClusterServer } from './temperatureControl.js';
|
|
11
|
+
const MatterbridgeOvenCavityOperationalStateServerBase = OvenCavityOperationalStateServer.enable({ events: { operationCompletion: true } });
|
|
11
12
|
export class Oven extends MatterbridgeEndpoint {
|
|
12
13
|
constructor(name, serial, options = {}) {
|
|
13
14
|
super([oven, powerSource], {
|
|
@@ -71,6 +72,7 @@ export class Oven extends MatterbridgeEndpoint {
|
|
|
71
72
|
operationalStateList: [
|
|
72
73
|
{ operationalStateId: OperationalState.OperationalStateEnum.Stopped },
|
|
73
74
|
{ operationalStateId: OperationalState.OperationalStateEnum.Running },
|
|
75
|
+
{ operationalStateId: OperationalState.OperationalStateEnum.Paused },
|
|
74
76
|
{ operationalStateId: OperationalState.OperationalStateEnum.Error },
|
|
75
77
|
],
|
|
76
78
|
operationalState,
|
|
@@ -93,21 +95,31 @@ export class MatterbridgeOvenModeServer extends OvenModeServer {
|
|
|
93
95
|
return { status: ModeBase.ModeChangeStatus.Success, statusText: 'Success' };
|
|
94
96
|
}
|
|
95
97
|
else {
|
|
96
|
-
device.log.error(`MatterbridgeOvenModeServer: changeToMode (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber}) called with
|
|
97
|
-
return { status: ModeBase.ModeChangeStatus.
|
|
98
|
+
device.log.error(`MatterbridgeOvenModeServer: changeToMode (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber}) called with unsupported mode ${request.newMode}`);
|
|
99
|
+
return { status: ModeBase.ModeChangeStatus.UnsupportedMode, statusText: '' };
|
|
98
100
|
}
|
|
99
101
|
}
|
|
100
102
|
}
|
|
101
|
-
export class MatterbridgeOvenCavityOperationalStateServer extends
|
|
103
|
+
export class MatterbridgeOvenCavityOperationalStateServer extends MatterbridgeOvenCavityOperationalStateServerBase {
|
|
102
104
|
initialize() {
|
|
103
105
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
104
106
|
device.log.info('MatterbridgeOvenCavityOperationalStateServer initialized: setting operational state to Stopped and operational error to No error');
|
|
105
107
|
this.state.operationalState = OperationalState.OperationalStateEnum.Stopped;
|
|
106
108
|
this.state.operationalError = { errorStateId: OperationalState.ErrorState.NoError, errorStateDetails: 'Fully operational' };
|
|
109
|
+
super.initialize();
|
|
107
110
|
}
|
|
108
111
|
stop() {
|
|
109
112
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
110
113
|
device.log.info(`MatterbridgeOvenCavityOperationalStateServer: stop (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber}) called setting operational state to Stopped and operational error to No error`);
|
|
114
|
+
if (this.internal.operationStartedAt !== undefined) {
|
|
115
|
+
const totalOperationalTime = Math.round((Date.now() - this.internal.operationStartedAt) / 1000);
|
|
116
|
+
this.events.operationCompletion.emit({
|
|
117
|
+
completionErrorCode: this.state.operationalError.errorStateId,
|
|
118
|
+
totalOperationalTime,
|
|
119
|
+
pausedTime: 0,
|
|
120
|
+
}, this.context);
|
|
121
|
+
this.internal.operationStartedAt = undefined;
|
|
122
|
+
}
|
|
111
123
|
this.state.operationalState = OperationalState.OperationalStateEnum.Stopped;
|
|
112
124
|
this.state.operationalError = { errorStateId: OperationalState.ErrorState.NoError, errorStateDetails: 'Fully operational' };
|
|
113
125
|
return {
|
|
@@ -117,6 +129,7 @@ export class MatterbridgeOvenCavityOperationalStateServer extends OvenCavityOper
|
|
|
117
129
|
start() {
|
|
118
130
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
119
131
|
device.log.info(`MatterbridgeOvenCavityOperationalStateServer: start (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber}) called setting operational state to Running and operational error to No error`);
|
|
132
|
+
this.internal.operationStartedAt ??= Date.now();
|
|
120
133
|
this.state.operationalState = OperationalState.OperationalStateEnum.Running;
|
|
121
134
|
this.state.operationalError = { errorStateId: OperationalState.ErrorState.NoError, errorStateDetails: 'Fully operational' };
|
|
122
135
|
return {
|
|
@@ -124,3 +137,9 @@ export class MatterbridgeOvenCavityOperationalStateServer extends OvenCavityOper
|
|
|
124
137
|
};
|
|
125
138
|
}
|
|
126
139
|
}
|
|
140
|
+
(function (MatterbridgeOvenCavityOperationalStateServer) {
|
|
141
|
+
class Internal extends MatterbridgeOvenCavityOperationalStateServerBase.Internal {
|
|
142
|
+
operationStartedAt;
|
|
143
|
+
}
|
|
144
|
+
MatterbridgeOvenCavityOperationalStateServer.Internal = Internal;
|
|
145
|
+
})(MatterbridgeOvenCavityOperationalStateServer || (MatterbridgeOvenCavityOperationalStateServer = {}));
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { MaybePromise } from '@matter/general';
|
|
2
|
+
import { RefrigeratorAlarmServer } from '@matter/node/behaviors/refrigerator-alarm';
|
|
2
3
|
import { RefrigeratorAndTemperatureControlledCabinetModeServer } from '@matter/node/behaviors/refrigerator-and-temperature-controlled-cabinet-mode';
|
|
3
4
|
import type { EndpointNumber, Semtag } from '@matter/types';
|
|
4
5
|
import { ModeBase } from '@matter/types/clusters/mode-base';
|
|
@@ -36,3 +37,6 @@ export declare class MatterbridgeRefrigeratorAndTemperatureControlledCabinetMode
|
|
|
36
37
|
initialize(): void;
|
|
37
38
|
changeToMode(request: ModeBase.ChangeToModeRequest): MaybePromise<ModeBase.ChangeToModeResponse>;
|
|
38
39
|
}
|
|
40
|
+
export declare class MatterbridgeRefrigeratorAlarmServer extends RefrigeratorAlarmServer {
|
|
41
|
+
static readonly schema: import("@matter/model").ClusterModel;
|
|
42
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AttributeElement, EventElement, FieldElement } from '@matter/model';
|
|
1
2
|
import { RefrigeratorAlarmServer } from '@matter/node/behaviors/refrigerator-alarm';
|
|
2
3
|
import { RefrigeratorAndTemperatureControlledCabinetModeServer } from '@matter/node/behaviors/refrigerator-and-temperature-controlled-cabinet-mode';
|
|
3
4
|
import { ModeBase } from '@matter/types/clusters/mode-base';
|
|
@@ -46,7 +47,7 @@ export class Refrigerator extends MatterbridgeEndpoint {
|
|
|
46
47
|
return endpoint;
|
|
47
48
|
}
|
|
48
49
|
createDefaultRefrigeratorAlarmClusterServer(endpoint, doorOpen = false) {
|
|
49
|
-
endpoint.behaviors.require(
|
|
50
|
+
endpoint.behaviors.require(MatterbridgeRefrigeratorAlarmServer, {
|
|
50
51
|
mask: { doorOpen: true },
|
|
51
52
|
supported: { doorOpen: true },
|
|
52
53
|
state: { doorOpen },
|
|
@@ -59,10 +60,20 @@ export class Refrigerator extends MatterbridgeEndpoint {
|
|
|
59
60
|
}
|
|
60
61
|
async triggerDoorOpenState(doorOpen) {
|
|
61
62
|
if (doorOpen) {
|
|
62
|
-
await this.triggerEvent('RefrigeratorAlarm', 'notify', {
|
|
63
|
+
await this.triggerEvent('RefrigeratorAlarm', 'notify', {
|
|
64
|
+
active: { doorOpen: true },
|
|
65
|
+
inactive: { doorOpen: false },
|
|
66
|
+
state: { doorOpen: true },
|
|
67
|
+
mask: { doorOpen: true },
|
|
68
|
+
}, this.log);
|
|
63
69
|
}
|
|
64
70
|
else {
|
|
65
|
-
await this.triggerEvent('RefrigeratorAlarm', 'notify', {
|
|
71
|
+
await this.triggerEvent('RefrigeratorAlarm', 'notify', {
|
|
72
|
+
active: { doorOpen: false },
|
|
73
|
+
inactive: { doorOpen: true },
|
|
74
|
+
state: { doorOpen: false },
|
|
75
|
+
mask: { doorOpen: true },
|
|
76
|
+
}, this.log);
|
|
66
77
|
}
|
|
67
78
|
return this;
|
|
68
79
|
}
|
|
@@ -86,3 +97,7 @@ export class MatterbridgeRefrigeratorAndTemperatureControlledCabinetModeServer e
|
|
|
86
97
|
}
|
|
87
98
|
}
|
|
88
99
|
}
|
|
100
|
+
const MatterbridgeRefrigeratorAlarmSchema = RefrigeratorAlarmServer.schema.extend({}, AttributeElement({ name: 'Mask', id: 0x0000, type: 'AlarmBitmap', access: 'R V', conformance: 'M' }), AttributeElement({ name: 'State', id: 0x0002, type: 'AlarmBitmap', access: 'R V', conformance: 'M' }), AttributeElement({ name: 'Supported', id: 0x0003, type: 'AlarmBitmap', access: 'R V', conformance: 'M', quality: 'F' }), EventElement({ name: 'Notify', id: 0x0000, access: 'V', conformance: 'M', priority: 'info' }, FieldElement({ name: 'Active', id: 0x0000, type: 'AlarmBitmap', conformance: 'M' }), FieldElement({ name: 'Inactive', id: 0x0001, type: 'AlarmBitmap', conformance: 'M' }), FieldElement({ name: 'State', id: 0x0002, type: 'AlarmBitmap', conformance: 'M' }), FieldElement({ name: 'Mask', id: 0x0003, type: 'AlarmBitmap', conformance: 'M' })));
|
|
101
|
+
export class MatterbridgeRefrigeratorAlarmServer extends RefrigeratorAlarmServer {
|
|
102
|
+
static schema = MatterbridgeRefrigeratorAlarmSchema;
|
|
103
|
+
}
|
|
@@ -10,6 +10,7 @@ import { RvcRunMode } from '@matter/types/clusters/rvc-run-mode';
|
|
|
10
10
|
import { ServiceArea } from '@matter/types/clusters/service-area';
|
|
11
11
|
import type { Semtag } from '@matter/types/globals';
|
|
12
12
|
import { MatterbridgeEndpoint } from '../matterbridgeEndpoint.js';
|
|
13
|
+
declare const MatterbridgeRvcOperationalStateServerBase: import("@matter/node").ClusterBehavior.Type<typeof RvcOperationalStateServer, import("@matter/types").ClusterType.WithEnabledAttributes<import("@matter/types").ClusterType.WithEnabledEvents<RvcOperationalState, "operationCompletion">, "countdownTime">, import("@matter/types").ClusterType.Concrete, new () => {}, "rvcOperationalState">;
|
|
13
14
|
export interface RoboticVacuumCleanerOptions {
|
|
14
15
|
mode?: 'server' | 'matter';
|
|
15
16
|
id?: string;
|
|
@@ -42,8 +43,20 @@ export declare class MatterbridgeRvcRunModeServer extends RvcRunModeServer {
|
|
|
42
43
|
export declare class MatterbridgeRvcCleanModeServer extends RvcCleanModeServer {
|
|
43
44
|
changeToMode(request: ModeBase.ChangeToModeRequest): Promise<ModeBase.ChangeToModeResponse>;
|
|
44
45
|
}
|
|
45
|
-
export declare class MatterbridgeRvcOperationalStateServer extends
|
|
46
|
+
export declare class MatterbridgeRvcOperationalStateServer extends MatterbridgeRvcOperationalStateServerBase {
|
|
47
|
+
protected internal: MatterbridgeRvcOperationalStateServer.Internal;
|
|
48
|
+
beginOperation(): void;
|
|
49
|
+
completeOperation(): void;
|
|
46
50
|
pause(): Promise<OperationalState.OperationalCommandResponse>;
|
|
47
51
|
resume(): Promise<OperationalState.OperationalCommandResponse>;
|
|
48
52
|
goHome(): Promise<OperationalState.OperationalCommandResponse>;
|
|
49
53
|
}
|
|
54
|
+
export declare namespace MatterbridgeRvcOperationalStateServer {
|
|
55
|
+
class Internal extends MatterbridgeRvcOperationalStateServerBase.Internal {
|
|
56
|
+
operationalStateBeforePause: RvcOperationalState.OperationalState | OperationalState.OperationalStateEnum;
|
|
57
|
+
operationStartedAt: number | undefined;
|
|
58
|
+
pausedAccumulatedMs: number;
|
|
59
|
+
pausedSinceMs: number | undefined;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
export {};
|
|
@@ -13,6 +13,10 @@ import { MatterbridgeServer } from '../behaviors/matterbridgeServer.js';
|
|
|
13
13
|
import { MatterbridgeServiceAreaServer } from '../behaviors/serviceAreaServer.js';
|
|
14
14
|
import { powerSource, roboticVacuumCleaner } from '../matterbridgeDeviceTypes.js';
|
|
15
15
|
import { MatterbridgeEndpoint } from '../matterbridgeEndpoint.js';
|
|
16
|
+
const MatterbridgeRvcOperationalStateServerBase = RvcOperationalStateServer.enable({
|
|
17
|
+
attributes: { countdownTime: true },
|
|
18
|
+
events: { operationCompletion: true },
|
|
19
|
+
});
|
|
16
20
|
export class RoboticVacuumCleaner extends MatterbridgeEndpoint {
|
|
17
21
|
constructor(name, serial, modeOrOptions, currentRunMode, supportedRunModes, currentCleanMode, supportedCleanModes, currentPhase = null, phaseList = null, operationalState, operationalStateList, supportedAreas, selectedAreas, currentArea, supportedMaps) {
|
|
18
22
|
const options = typeof modeOrOptions === 'object'
|
|
@@ -104,6 +108,7 @@ export class RoboticVacuumCleaner extends MatterbridgeEndpoint {
|
|
|
104
108
|
this.behaviors.require(MatterbridgeRvcOperationalStateServer, {
|
|
105
109
|
phaseList,
|
|
106
110
|
currentPhase,
|
|
111
|
+
countdownTime: null,
|
|
107
112
|
operationalStateList: operationalStateList ?? [
|
|
108
113
|
{ operationalStateId: RvcOperationalState.OperationalState.Stopped },
|
|
109
114
|
{ operationalStateId: RvcOperationalState.OperationalState.Running },
|
|
@@ -135,19 +140,34 @@ export class MatterbridgeRvcRunModeServer extends RvcRunModeServer {
|
|
|
135
140
|
device.log.error(`MatterbridgeRvcRunModeServer changeToMode called with unsupported newMode: ${request.newMode}`);
|
|
136
141
|
return { status: ModeBase.ModeChangeStatus.UnsupportedMode, statusText: 'Unsupported mode' };
|
|
137
142
|
}
|
|
143
|
+
const currentIsIdle = this.state.supportedModes.some((mode) => mode.mode === this.state.currentMode && mode.modeTags.some((tag) => tag.value === RvcRunMode.ModeTag.Idle));
|
|
144
|
+
const requestedIsIdle = supported.modeTags.some((tag) => tag.value === RvcRunMode.ModeTag.Idle);
|
|
145
|
+
if (request.newMode !== this.state.currentMode && !this.features.directModeChange && !currentIsIdle && !requestedIsIdle) {
|
|
146
|
+
device.log.debug(`MatterbridgeRvcRunModeServer changeToMode rejected direct non-Idle mode change from ${this.state.currentMode} to ${request.newMode}`);
|
|
147
|
+
return { status: ModeBase.ModeChangeStatus.InvalidInMode, statusText: 'Direct mode change is not supported while operating' };
|
|
148
|
+
}
|
|
149
|
+
if (request.newMode === this.state.currentMode) {
|
|
150
|
+
return { status: ModeBase.ModeChangeStatus.Success, statusText: 'Already in requested mode' };
|
|
151
|
+
}
|
|
138
152
|
this.state.currentMode = request.newMode;
|
|
139
153
|
if (supported.modeTags.find((tag) => tag.value === RvcRunMode.ModeTag.Cleaning)) {
|
|
140
154
|
device.log.debug('MatterbridgeRvcRunModeServer changeToMode called with newMode Cleaning => Running');
|
|
141
|
-
this.agent.get(MatterbridgeRvcOperationalStateServer)
|
|
155
|
+
const operationalState = this.agent.get(MatterbridgeRvcOperationalStateServer);
|
|
156
|
+
operationalState.beginOperation();
|
|
157
|
+
operationalState.state.operationalState = RvcOperationalState.OperationalState.Running;
|
|
142
158
|
return { status: ModeBase.ModeChangeStatus.Success, statusText: 'Running' };
|
|
143
159
|
}
|
|
144
160
|
else if (supported.modeTags.find((tag) => tag.value === RvcRunMode.ModeTag.Idle)) {
|
|
145
|
-
device.log.debug('MatterbridgeRvcRunModeServer changeToMode called with newMode Idle =>
|
|
146
|
-
this.agent.get(MatterbridgeRvcOperationalStateServer)
|
|
147
|
-
|
|
161
|
+
device.log.debug('MatterbridgeRvcRunModeServer changeToMode called with newMode Idle => SeekingCharger');
|
|
162
|
+
const operationalState = this.agent.get(MatterbridgeRvcOperationalStateServer);
|
|
163
|
+
operationalState.completeOperation();
|
|
164
|
+
operationalState.state.operationalState = RvcOperationalState.OperationalState.SeekingCharger;
|
|
165
|
+
return { status: ModeBase.ModeChangeStatus.Success, statusText: 'Seeking charger' };
|
|
148
166
|
}
|
|
149
167
|
device.log.debug(`MatterbridgeRvcRunModeServer changeToMode called with newMode ${request.newMode} => ${supported.label}`);
|
|
150
|
-
this.agent.get(MatterbridgeRvcOperationalStateServer)
|
|
168
|
+
const operationalState = this.agent.get(MatterbridgeRvcOperationalStateServer);
|
|
169
|
+
operationalState.beginOperation();
|
|
170
|
+
operationalState.state.operationalState = RvcOperationalState.OperationalState.Running;
|
|
151
171
|
return { status: ModeBase.ModeChangeStatus.Success, statusText: 'Success' };
|
|
152
172
|
}
|
|
153
173
|
}
|
|
@@ -167,12 +187,40 @@ export class MatterbridgeRvcCleanModeServer extends RvcCleanModeServer {
|
|
|
167
187
|
device.log.error(`MatterbridgeRvcCleanModeServer changeToMode called with unsupported newMode: ${request.newMode}`);
|
|
168
188
|
return { status: ModeBase.ModeChangeStatus.UnsupportedMode, statusText: 'Unsupported mode' };
|
|
169
189
|
}
|
|
190
|
+
if (request.newMode === this.state.currentMode) {
|
|
191
|
+
return { status: ModeBase.ModeChangeStatus.Success, statusText: 'Already in requested mode' };
|
|
192
|
+
}
|
|
193
|
+
const runModeState = this.agent.get(MatterbridgeRvcRunModeServer).state;
|
|
194
|
+
const runModeIsIdle = runModeState.supportedModes.some((mode) => mode.mode === runModeState.currentMode && mode.modeTags.some((tag) => tag.value === RvcRunMode.ModeTag.Idle));
|
|
195
|
+
if (!this.features.directModeChange && !runModeIsIdle) {
|
|
196
|
+
device.log.debug(`MatterbridgeRvcCleanModeServer changeToMode rejected while RVC Run Mode ${runModeState.currentMode} is non-Idle`);
|
|
197
|
+
return { status: ModeBase.ModeChangeStatus.InvalidInMode, statusText: 'Clean mode cannot change while operating' };
|
|
198
|
+
}
|
|
170
199
|
this.state.currentMode = request.newMode;
|
|
171
200
|
device.log.debug(`MatterbridgeRvcCleanModeServer changeToMode called with newMode ${request.newMode} => ${supported.label}`);
|
|
172
201
|
return { status: ModeBase.ModeChangeStatus.Success, statusText: 'Success' };
|
|
173
202
|
}
|
|
174
203
|
}
|
|
175
|
-
export class MatterbridgeRvcOperationalStateServer extends
|
|
204
|
+
export class MatterbridgeRvcOperationalStateServer extends MatterbridgeRvcOperationalStateServerBase {
|
|
205
|
+
beginOperation() {
|
|
206
|
+
if (this.internal.operationStartedAt === undefined) {
|
|
207
|
+
this.internal.operationStartedAt = Date.now();
|
|
208
|
+
this.internal.pausedAccumulatedMs = 0;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
completeOperation() {
|
|
212
|
+
if (this.internal.operationStartedAt === undefined)
|
|
213
|
+
return;
|
|
214
|
+
if (this.internal.pausedSinceMs !== undefined) {
|
|
215
|
+
this.internal.pausedAccumulatedMs += Date.now() - this.internal.pausedSinceMs;
|
|
216
|
+
this.internal.pausedSinceMs = undefined;
|
|
217
|
+
}
|
|
218
|
+
const totalOperationalTime = Math.round((Date.now() - this.internal.operationStartedAt) / 1000);
|
|
219
|
+
const pausedTime = Math.round(this.internal.pausedAccumulatedMs / 1000);
|
|
220
|
+
this.events.operationCompletion.emit({ completionErrorCode: OperationalState.ErrorState.NoError, totalOperationalTime, pausedTime }, this.context);
|
|
221
|
+
this.internal.operationStartedAt = undefined;
|
|
222
|
+
this.internal.pausedAccumulatedMs = 0;
|
|
223
|
+
}
|
|
176
224
|
async pause() {
|
|
177
225
|
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
178
226
|
device.log.info(`Pause (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
|
|
@@ -183,8 +231,17 @@ export class MatterbridgeRvcOperationalStateServer extends RvcOperationalStateSe
|
|
|
183
231
|
attributes: this.state,
|
|
184
232
|
endpoint: this.endpoint,
|
|
185
233
|
});
|
|
186
|
-
|
|
187
|
-
|
|
234
|
+
if (this.state.operationalState === RvcOperationalState.OperationalState.Paused) {
|
|
235
|
+
return { commandResponseState: { errorStateId: OperationalState.ErrorState.NoError, errorStateDetails: 'Already paused' } };
|
|
236
|
+
}
|
|
237
|
+
if (this.state.operationalState !== RvcOperationalState.OperationalState.Running && this.state.operationalState !== RvcOperationalState.OperationalState.SeekingCharger) {
|
|
238
|
+
return {
|
|
239
|
+
commandResponseState: { errorStateId: OperationalState.ErrorState.CommandInvalidInState, errorStateDetails: 'Not Pause-compatible in the current operational state' },
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
device.log.debug('MatterbridgeRvcOperationalStateServer: pause called setting operational state to Paused');
|
|
243
|
+
this.internal.operationalStateBeforePause = this.state.operationalState;
|
|
244
|
+
this.internal.pausedSinceMs = Date.now();
|
|
188
245
|
this.state.operationalState = RvcOperationalState.OperationalState.Paused;
|
|
189
246
|
this.state.operationalError = { errorStateId: RvcOperationalState.ErrorState.NoError, errorStateDetails: 'Fully operational' };
|
|
190
247
|
return {
|
|
@@ -201,9 +258,20 @@ export class MatterbridgeRvcOperationalStateServer extends RvcOperationalStateSe
|
|
|
201
258
|
attributes: this.state,
|
|
202
259
|
endpoint: this.endpoint,
|
|
203
260
|
});
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
261
|
+
if (this.state.operationalState === RvcOperationalState.OperationalState.Running) {
|
|
262
|
+
return { commandResponseState: { errorStateId: OperationalState.ErrorState.NoError, errorStateDetails: 'Already running' } };
|
|
263
|
+
}
|
|
264
|
+
if (this.state.operationalState !== RvcOperationalState.OperationalState.Paused) {
|
|
265
|
+
return {
|
|
266
|
+
commandResponseState: { errorStateId: OperationalState.ErrorState.CommandInvalidInState, errorStateDetails: 'Not Resume-compatible in the current operational state' },
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
device.log.debug(`MatterbridgeRvcOperationalStateServer: resume called restoring operational state to ${this.internal.operationalStateBeforePause}`);
|
|
270
|
+
if (this.internal.pausedSinceMs !== undefined) {
|
|
271
|
+
this.internal.pausedAccumulatedMs += Date.now() - this.internal.pausedSinceMs;
|
|
272
|
+
this.internal.pausedSinceMs = undefined;
|
|
273
|
+
}
|
|
274
|
+
this.state.operationalState = this.internal.operationalStateBeforePause;
|
|
207
275
|
this.state.operationalError = { errorStateId: RvcOperationalState.ErrorState.NoError, errorStateDetails: 'Fully operational' };
|
|
208
276
|
return {
|
|
209
277
|
commandResponseState: { errorStateId: OperationalState.ErrorState.NoError, errorStateDetails: 'Fully operational' },
|
|
@@ -219,12 +287,34 @@ export class MatterbridgeRvcOperationalStateServer extends RvcOperationalStateSe
|
|
|
219
287
|
attributes: this.state,
|
|
220
288
|
endpoint: this.endpoint,
|
|
221
289
|
});
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
290
|
+
if (this.state.operationalState === RvcOperationalState.OperationalState.SeekingCharger) {
|
|
291
|
+
return { commandResponseState: { errorStateId: OperationalState.ErrorState.NoError, errorStateDetails: 'Already seeking charger' } };
|
|
292
|
+
}
|
|
293
|
+
if (this.state.operationalState === RvcOperationalState.OperationalState.Error ||
|
|
294
|
+
this.state.operationalState === RvcOperationalState.OperationalState.Charging ||
|
|
295
|
+
this.state.operationalState === RvcOperationalState.OperationalState.Docked ||
|
|
296
|
+
this.state.operationalState === RvcOperationalState.OperationalState.EmptyingDustBin ||
|
|
297
|
+
this.state.operationalState === RvcOperationalState.OperationalState.CleaningMop ||
|
|
298
|
+
this.state.operationalState === RvcOperationalState.OperationalState.FillingWaterTank ||
|
|
299
|
+
this.state.operationalState === RvcOperationalState.OperationalState.UpdatingMaps) {
|
|
300
|
+
return {
|
|
301
|
+
commandResponseState: { errorStateId: OperationalState.ErrorState.CommandInvalidInState, errorStateDetails: 'Cannot seek the charger in the current operational state' },
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
device.log.debug('MatterbridgeRvcOperationalStateServer: goHome called setting operational state to SeekingCharger');
|
|
305
|
+
this.state.operationalState = RvcOperationalState.OperationalState.SeekingCharger;
|
|
225
306
|
this.state.operationalError = { errorStateId: RvcOperationalState.ErrorState.NoError, errorStateDetails: 'Fully operational' };
|
|
226
307
|
return {
|
|
227
308
|
commandResponseState: { errorStateId: OperationalState.ErrorState.NoError, errorStateDetails: 'Fully operational' },
|
|
228
309
|
};
|
|
229
310
|
}
|
|
230
311
|
}
|
|
312
|
+
(function (MatterbridgeRvcOperationalStateServer) {
|
|
313
|
+
class Internal extends MatterbridgeRvcOperationalStateServerBase.Internal {
|
|
314
|
+
operationalStateBeforePause = RvcOperationalState.OperationalState.Running;
|
|
315
|
+
operationStartedAt;
|
|
316
|
+
pausedAccumulatedMs = 0;
|
|
317
|
+
pausedSinceMs;
|
|
318
|
+
}
|
|
319
|
+
MatterbridgeRvcOperationalStateServer.Internal = Internal;
|
|
320
|
+
})(MatterbridgeRvcOperationalStateServer || (MatterbridgeRvcOperationalStateServer = {}));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@matterbridge/core",
|
|
3
|
-
"version": "3.10.7-dev-
|
|
3
|
+
"version": "3.10.7-dev-20260827-957ddcc",
|
|
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.7-dev-
|
|
136
|
-
"@matterbridge/thread": "3.10.7-dev-
|
|
137
|
-
"@matterbridge/types": "3.10.7-dev-
|
|
138
|
-
"@matterbridge/utils": "3.10.7-dev-
|
|
135
|
+
"@matterbridge/dgram": "3.10.7-dev-20260827-957ddcc",
|
|
136
|
+
"@matterbridge/thread": "3.10.7-dev-20260827-957ddcc",
|
|
137
|
+
"@matterbridge/types": "3.10.7-dev-20260827-957ddcc",
|
|
138
|
+
"@matterbridge/utils": "3.10.7-dev-20260827-957ddcc",
|
|
139
139
|
"escape-html": "1.0.3",
|
|
140
140
|
"express": "5.2.1",
|
|
141
141
|
"express-rate-limit": "8.6.2",
|