@matterbridge/core 3.10.5-dev-20260807-79a10b4 → 3.10.5-dev-20260809-ffe76d7

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.
@@ -6,15 +6,15 @@ declare const MatterbridgeThermostatServer_base: import("@matter/node").ClusterB
6
6
  events: false;
7
7
  heating: true;
8
8
  localTemperatureNotExposed: false;
9
- matterScheduleConfiguration: false;
9
+ matterScheduleConfiguration: true;
10
10
  occupancy: false;
11
11
  presets: true;
12
12
  setback: false;
13
13
  thermostatSuggestions: false;
14
14
  }>, import("@matter/types").ClusterType.Concrete, typeof import("@matter/node/behaviors/thermostat").ThermostatBaseServer.Internal, "thermostat">;
15
15
  export declare class MatterbridgeThermostatServer extends MatterbridgeThermostatServer_base {
16
- initialize(): Promise<void>;
17
16
  setpointRaiseLower(request: Thermostat.SetpointRaiseLowerRequest): Promise<void>;
18
17
  setActivePresetRequest(request: Thermostat.SetActivePresetRequest): Promise<void>;
18
+ setActiveScheduleRequest(request: Thermostat.SetActiveScheduleRequest): Promise<void>;
19
19
  }
20
20
  export {};
@@ -1,18 +1,9 @@
1
+ import { Bytes } from '@matter/general';
1
2
  import { ThermostatServer } from '@matter/node/behaviors/thermostat';
3
+ import { StatusResponse } from '@matter/types';
2
4
  import { Thermostat } from '@matter/types/clusters/thermostat';
3
5
  import { MatterbridgeServer } from './matterbridgeServer.js';
4
- export class MatterbridgeThermostatServer extends ThermostatServer.with(Thermostat.Feature.Cooling, Thermostat.Feature.Heating, Thermostat.Feature.AutoMode, Thermostat.Feature.Presets) {
5
- async initialize() {
6
- await super.initialize();
7
- this.endpoint.construction.onSuccess(async () => {
8
- const device = this.endpoint.stateOf(MatterbridgeServer);
9
- device.log.debug(`Removing atomic commands (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
10
- await this.endpoint.setStateOf(ThermostatServer, {
11
- acceptedCommandList: [0],
12
- generatedCommandList: [],
13
- });
14
- });
15
- }
6
+ export class MatterbridgeThermostatServer extends ThermostatServer.with(Thermostat.Feature.Cooling, Thermostat.Feature.Heating, Thermostat.Feature.AutoMode, Thermostat.Feature.Presets, Thermostat.Feature.MatterScheduleConfiguration) {
16
7
  async setpointRaiseLower(request) {
17
8
  const device = this.endpoint.stateOf(MatterbridgeServer);
18
9
  device.log.info(`Setting setpoint by ${request.amount} in mode ${request.mode} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
@@ -45,4 +36,23 @@ export class MatterbridgeThermostatServer extends ThermostatServer.with(Thermost
45
36
  const activePresetHandle = this.state.activePresetHandle ? `0x${Buffer.from(this.state.activePresetHandle).toString('hex')}` : 'null';
46
37
  device.log.debug(`MatterbridgeThermostatServer: setActivePresetRequest completed with activePresetHandle: ${activePresetHandle} occupiedHeatingSetpoint: ${this.state.occupiedHeatingSetpoint} occupiedCoolingSetpoint: ${this.state.occupiedCoolingSetpoint}`);
47
38
  }
39
+ async setActiveScheduleRequest(request) {
40
+ const device = this.endpoint.stateOf(MatterbridgeServer);
41
+ const scheduleHandle = `0x${Buffer.from(request.scheduleHandle).toString('hex')}`;
42
+ device.log.info(`Setting schedule to ${scheduleHandle} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
43
+ await device.commandHandler.executeHandler('Thermostat.setActiveScheduleRequest', {
44
+ command: 'setActiveScheduleRequest',
45
+ request,
46
+ cluster: ThermostatServer.id,
47
+ attributes: this.state,
48
+ endpoint: this.endpoint,
49
+ context: this.context,
50
+ });
51
+ const schedule = this.state.schedules.find((s) => s.scheduleHandle !== null && Bytes.areEqual(s.scheduleHandle, request.scheduleHandle));
52
+ if (schedule === undefined) {
53
+ throw new StatusResponse.InvalidCommandError('Requested ScheduleHandle not found');
54
+ }
55
+ this.state.activeScheduleHandle = Uint8Array.from(request.scheduleHandle);
56
+ device.log.debug(`MatterbridgeThermostatServer: setActiveScheduleRequest completed with activeScheduleHandle: ${scheduleHandle}`);
57
+ }
48
58
  }
@@ -2,7 +2,7 @@ import { ClosureControlServer } from '@matter/node/behaviors/closure-control';
2
2
  import { ClosureControl } from '@matter/types/clusters/closure-control';
3
3
  import type { Semtag } from '@matter/types/globals';
4
4
  import { MatterbridgeEndpoint } from '../matterbridgeEndpoint.js';
5
- import { type ClosurePanelOptions } from './closurePanel.js';
5
+ import { type ClosureDimensionType, type ClosurePanelOptions } from './closurePanel.js';
6
6
  declare const MatterbridgeClosureControlServer_base: import("@matter/node").ClusterBehavior.Type<typeof ClosureControlServer, import("@matter/types").ClusterType.WithSupportedFeatures<ClosureControl, {
7
7
  calibration: false;
8
8
  instantaneous: false;
@@ -30,6 +30,6 @@ export interface ClosureOptions {
30
30
  export declare class Closure extends MatterbridgeEndpoint {
31
31
  constructor(name: string, serial: string, options?: ClosureOptions);
32
32
  getMainState(): ClosureControl.MainState | undefined;
33
- addPanel(name: string, tagList: Semtag[], options?: Pick<ClosurePanelOptions, 'currentState' | 'targetState' | 'resolution' | 'stepValue' | 'latchControlModes'>): MatterbridgeEndpoint;
33
+ addPanel(name: string, tagList: Semtag[], dimensionType: ClosureDimensionType, options?: Omit<ClosurePanelOptions, 'tagList'>): MatterbridgeEndpoint;
34
34
  }
35
35
  export {};
@@ -4,7 +4,7 @@ import { ThreeLevelAuto } from '@matter/types/globals';
4
4
  import { MatterbridgeServer } from '../behaviors/matterbridgeServer.js';
5
5
  import { closure, closurePanel } from '../matterbridgeDeviceTypes.js';
6
6
  import { MatterbridgeEndpoint } from '../matterbridgeEndpoint.js';
7
- import { MatterbridgeClosureDimensionServer } from './closurePanel.js';
7
+ import { createClosureDimensionClusterServer } from './closurePanel.js';
8
8
  export class MatterbridgeClosureControlServer extends ClosureControlServer.with(ClosureControl.Feature.Positioning, ClosureControl.Feature.MotionLatching, ClosureControl.Feature.Speed) {
9
9
  moveTo = async (request) => {
10
10
  const device = this.endpoint.stateOf(MatterbridgeServer);
@@ -21,10 +21,15 @@ export class MatterbridgeClosureControlServer extends ClosureControlServer.with(
21
21
  ...previousTarget,
22
22
  ...(request?.position !== undefined ? { position: request.position } : null),
23
23
  ...(request?.latch !== undefined ? { latch: request.latch } : null),
24
- speed: request?.speed ?? previousTarget.speed ?? ThreeLevelAuto.Auto,
24
+ speed: request?.speed ?? ThreeLevelAuto.Auto,
25
25
  };
26
26
  this.state.overallTargetState = nextTarget;
27
- this.state.mainState = ClosureControl.MainState.Moving;
27
+ const currentState = this.state.overallCurrentState;
28
+ const isAtTarget = currentState !== null &&
29
+ (nextTarget.position === undefined || nextTarget.position === currentState.position) &&
30
+ (nextTarget.latch === undefined || nextTarget.latch === currentState.latch) &&
31
+ nextTarget.speed === currentState.speed;
32
+ this.state.mainState = isAtTarget ? ClosureControl.MainState.Stopped : ClosureControl.MainState.Moving;
28
33
  };
29
34
  stop = async () => {
30
35
  const device = this.endpoint.stateOf(MatterbridgeServer);
@@ -65,15 +70,9 @@ export class Closure extends MatterbridgeEndpoint {
65
70
  getMainState() {
66
71
  return this.getAttribute(ClosureControlServer, 'mainState');
67
72
  }
68
- addPanel(name, tagList, options = {}) {
73
+ addPanel(name, tagList, dimensionType, options = {}) {
69
74
  const panel = this.addChildDeviceType(name, closurePanel, { tagList });
70
- panel.behaviors.require(MatterbridgeClosureDimensionServer, {
71
- currentState: options.currentState ?? { position: 0, latch: true, speed: ThreeLevelAuto.Auto },
72
- targetState: options.targetState ?? { position: 0, latch: true, speed: ThreeLevelAuto.Auto },
73
- resolution: options.resolution ?? 1,
74
- stepValue: options.stepValue ?? 1,
75
- latchControlModes: options.latchControlModes ?? { remoteLatching: true, remoteUnlatching: true },
76
- });
75
+ createClosureDimensionClusterServer(panel, dimensionType, options);
77
76
  return panel;
78
77
  }
79
78
  }
@@ -2,6 +2,7 @@ import { ClosureDimensionServer } from '@matter/node/behaviors/closure-dimension
2
2
  import { ClosureDimension } from '@matter/types/clusters/closure-dimension';
3
3
  import type { Semtag } from '@matter/types/globals';
4
4
  import { MatterbridgeEndpoint } from '../matterbridgeEndpoint.js';
5
+ export type ClosureDimensionType = 'lift' | 'tilt' | 'modulation';
5
6
  declare const MatterbridgeClosureDimensionServer_base: import("@matter/node").ClusterBehavior.Type<typeof ClosureDimensionServer, import("@matter/types").ClusterType.WithSupportedFeatures<ClosureDimension, {
6
7
  limitation: false;
7
8
  modulation: false;
@@ -22,9 +23,14 @@ export interface ClosurePanelOptions {
22
23
  resolution?: number;
23
24
  stepValue?: number;
24
25
  latchControlModes?: ClosureDimension.LatchControlModes;
26
+ translationDirection?: ClosureDimension.TranslationDirection;
27
+ rotationAxis?: ClosureDimension.RotationAxis;
28
+ overflow?: ClosureDimension.Overflow;
29
+ modulationType?: ClosureDimension.ModulationType;
25
30
  tagList?: Semtag[];
26
31
  }
27
32
  export declare class ClosurePanel extends MatterbridgeEndpoint {
28
- constructor(name: string, serial: string, options?: ClosurePanelOptions);
33
+ constructor(name: string, serial: string, dimensionType: ClosureDimensionType, options?: ClosurePanelOptions);
29
34
  }
35
+ export declare function createClosureDimensionClusterServer(endpoint: MatterbridgeEndpoint, dimensionType: ClosureDimensionType, options: ClosurePanelOptions): MatterbridgeEndpoint;
30
36
  export {};
@@ -20,7 +20,7 @@ export class MatterbridgeClosureDimensionServer extends ClosureDimensionServer.w
20
20
  ...previousTarget,
21
21
  ...(request?.position !== undefined ? { position: request.position } : null),
22
22
  ...(request?.latch !== undefined ? { latch: request.latch } : null),
23
- speed: request?.speed ?? previousTarget.speed ?? ThreeLevelAuto.Auto,
23
+ speed: request?.speed ?? ThreeLevelAuto.Auto,
24
24
  };
25
25
  this.state.targetState = nextTarget;
26
26
  };
@@ -53,15 +53,38 @@ export class MatterbridgeClosureDimensionServer extends ClosureDimensionServer.w
53
53
  };
54
54
  }
55
55
  export class ClosurePanel extends MatterbridgeEndpoint {
56
- constructor(name, serial, options = {}) {
56
+ constructor(name, serial, dimensionType, options = {}) {
57
57
  super([closurePanel], { id: `${name.replaceAll(' ', '')}-${serial.replaceAll(' ', '')}`, tagList: options.tagList });
58
58
  this.createDefaultBasicInformationClusterServer(name, serial, 0xfff1, 'Matterbridge', 0x8000, 'Matterbridge Closure Panel');
59
- this.behaviors.require(MatterbridgeClosureDimensionServer, {
60
- currentState: options.currentState ?? { position: 0, latch: true, speed: ThreeLevelAuto.Auto },
61
- targetState: options.targetState ?? { position: 0, latch: true, speed: ThreeLevelAuto.Auto },
62
- resolution: options.resolution ?? 1,
63
- stepValue: options.stepValue ?? 1,
64
- latchControlModes: options.latchControlModes ?? { remoteLatching: true, remoteUnlatching: true },
59
+ createClosureDimensionClusterServer(this, dimensionType, options);
60
+ }
61
+ }
62
+ export function createClosureDimensionClusterServer(endpoint, dimensionType, options) {
63
+ const commonOptions = {
64
+ currentState: options.currentState ?? { position: 0, latch: true, speed: ThreeLevelAuto.Auto },
65
+ targetState: options.targetState ?? { position: 0, latch: true, speed: ThreeLevelAuto.Auto },
66
+ resolution: options.resolution ?? 1,
67
+ stepValue: options.stepValue ?? 1,
68
+ latchControlModes: options.latchControlModes ?? { remoteLatching: true, remoteUnlatching: true },
69
+ };
70
+ if (dimensionType === 'lift') {
71
+ endpoint.behaviors.require(MatterbridgeClosureDimensionServer.with(ClosureDimension.Feature.Positioning, ClosureDimension.Feature.MotionLatching, ClosureDimension.Feature.Speed, ClosureDimension.Feature.Translation), {
72
+ ...commonOptions,
73
+ translationDirection: options.translationDirection ?? ClosureDimension.TranslationDirection.Downward,
74
+ });
75
+ }
76
+ else if (dimensionType === 'tilt') {
77
+ endpoint.behaviors.require(MatterbridgeClosureDimensionServer.with(ClosureDimension.Feature.Positioning, ClosureDimension.Feature.MotionLatching, ClosureDimension.Feature.Speed, ClosureDimension.Feature.Rotation), {
78
+ ...commonOptions,
79
+ rotationAxis: options.rotationAxis ?? ClosureDimension.RotationAxis.CenteredHorizontal,
80
+ overflow: options.overflow ?? ClosureDimension.Overflow.NoOverflow,
81
+ });
82
+ }
83
+ else {
84
+ endpoint.behaviors.require(MatterbridgeClosureDimensionServer.with(ClosureDimension.Feature.Positioning, ClosureDimension.Feature.MotionLatching, ClosureDimension.Feature.Speed, ClosureDimension.Feature.Modulation), {
85
+ ...commonOptions,
86
+ modulationType: options.modulationType ?? ClosureDimension.ModulationType.SlatsOrientation,
65
87
  });
66
88
  }
89
+ return endpoint;
67
90
  }
@@ -2,7 +2,6 @@ import { OperationalState } from '@matter/types/clusters/operational-state';
2
2
  import type { Semtag } from '@matter/types/globals';
3
3
  import { MatterbridgeEndpoint } from '../matterbridgeEndpoint.js';
4
4
  export interface IrrigationSystemOptions {
5
- singleZone?: boolean;
6
5
  batteryPowered?: boolean;
7
6
  operationalState?: OperationalState.OperationalStateEnum;
8
7
  flowMeasuredValue?: number | null;
@@ -5,8 +5,7 @@ import { MatterbridgeEndpoint } from '../matterbridgeEndpoint.js';
5
5
  import { getSemtag } from '../matterbridgeEndpointHelpers.js';
6
6
  export class IrrigationSystem extends MatterbridgeEndpoint {
7
7
  constructor(name, serial, options = {}) {
8
- const deviceTypes = options.singleZone ? [irrigationSystem, waterValve, powerSource] : [irrigationSystem, powerSource];
9
- super(deviceTypes, { id: `${name.replaceAll(' ', '')}-${serial.replaceAll(' ', '')}` });
8
+ super([irrigationSystem, powerSource], { id: `${name.replaceAll(' ', '')}-${serial.replaceAll(' ', '')}` });
10
9
  this.createDefaultIdentifyClusterServer();
11
10
  this.createDefaultBasicInformationClusterServer(name, serial, 0xfff1, 'Matterbridge', 0x8000, 'Matterbridge Irrigation System');
12
11
  if (options.batteryPowered) {
@@ -18,9 +17,6 @@ export class IrrigationSystem extends MatterbridgeEndpoint {
18
17
  this.createDefaultOperationalStateClusterServer(options.operationalState ?? OperationalState.OperationalStateEnum.Stopped);
19
18
  if (options.flowMeasuredValue !== undefined)
20
19
  this.createDefaultFlowMeasurementClusterServer(options.flowMeasuredValue);
21
- if (options.singleZone) {
22
- this.createDefaultValveConfigurationAndControlClusterServer();
23
- }
24
20
  this.addRequiredClusterServers();
25
21
  }
26
22
  addZone(tag) {
@@ -3,14 +3,14 @@ import { MicrowaveOvenControl } from '@matter/types/clusters/microwave-oven-cont
3
3
  import { MicrowaveOvenMode } from '@matter/types/clusters/microwave-oven-mode';
4
4
  import { MatterbridgeEndpoint } from '../matterbridgeEndpoint.js';
5
5
  export declare class MicrowaveOven extends MatterbridgeEndpoint {
6
- constructor(name: string, serial: string, currentMode?: number, supportedModes?: MicrowaveOvenMode.ModeOption[], selectedWattIndex?: number, supportedWatts?: number[], cookTime?: number, maxCookTime?: number);
6
+ constructor(name: string, serial: string, currentMode?: number, supportedModes?: MicrowaveOvenMode.ModeOption[], powerSetting?: number, minPower?: number, maxPower?: number, powerStep?: number, cookTime?: number, maxCookTime?: number);
7
7
  createDefaultMicrowaveOvenModeClusterServer(currentMode: number, supportedModes: MicrowaveOvenMode.ModeOption[]): this;
8
- createDefaultMicrowaveOvenControlClusterServer(selectedWattIndex: number, supportedWatts: number[], cookTime: number, maxCookTime: number): this;
8
+ createDefaultMicrowaveOvenControlClusterServer(powerSetting: number, minPower: number, maxPower: number, powerStep: number, cookTime: number, maxCookTime: number): this;
9
9
  }
10
10
  declare const MatterbridgeMicrowaveOvenControlServer_base: import("@matter/node").ClusterBehavior.Type<typeof MicrowaveOvenControlServer, import("@matter/types").ClusterType.WithSupportedFeatures<MicrowaveOvenControl, {
11
- powerAsNumber: false;
12
- powerInWatts: true;
13
- powerNumberLimits: false;
11
+ powerAsNumber: true;
12
+ powerInWatts: false;
13
+ powerNumberLimits: true;
14
14
  }>, import("@matter/types").ClusterType.Concrete, new () => {}, "microwaveOvenControl">;
15
15
  export declare class MatterbridgeMicrowaveOvenControlServer extends MatterbridgeMicrowaveOvenControlServer_base {
16
16
  initialize(): Promise<void>;
@@ -16,14 +16,14 @@ export class MicrowaveOven extends MatterbridgeEndpoint {
16
16
  { label: 'Max', mode: 5, modeTags: [{ value: MicrowaveOvenMode.ModeTag.Max }] },
17
17
  { label: 'Normal', mode: 6, modeTags: [{ value: MicrowaveOvenMode.ModeTag.Normal }] },
18
18
  { label: 'Defrost', mode: 7, modeTags: [{ value: MicrowaveOvenMode.ModeTag.Defrost }] },
19
- ], selectedWattIndex = 5, supportedWatts = [100, 200, 300, 400, 500, 600, 700, 800, 900, 1000], cookTime = 60, maxCookTime = 3600) {
19
+ ], powerSetting = 100, minPower = 10, maxPower = 100, powerStep = 10, cookTime = 60, maxCookTime = 3600) {
20
20
  super([microwaveOven, powerSource], { id: `${name.replaceAll(' ', '')}-${serial.replaceAll(' ', '')}` });
21
21
  this.createDefaultIdentifyClusterServer();
22
22
  this.createDefaultBasicInformationClusterServer(name, serial, 0xfff1, 'Matterbridge', 0x8000, 'Microwave Oven');
23
23
  this.createDefaultPowerSourceWiredClusterServer();
24
24
  this.createDefaultOperationalStateClusterServer(OperationalState.OperationalStateEnum.Stopped);
25
25
  this.createDefaultMicrowaveOvenModeClusterServer(currentMode, supportedModes);
26
- this.createDefaultMicrowaveOvenControlClusterServer(selectedWattIndex, supportedWatts, cookTime, maxCookTime);
26
+ this.createDefaultMicrowaveOvenControlClusterServer(powerSetting, minPower, maxPower, powerStep, cookTime, maxCookTime);
27
27
  }
28
28
  createDefaultMicrowaveOvenModeClusterServer(currentMode, supportedModes) {
29
29
  this.behaviors.require(MicrowaveOvenModeServer, {
@@ -32,17 +32,19 @@ export class MicrowaveOven extends MatterbridgeEndpoint {
32
32
  });
33
33
  return this;
34
34
  }
35
- createDefaultMicrowaveOvenControlClusterServer(selectedWattIndex, supportedWatts, cookTime, maxCookTime) {
36
- this.behaviors.require(MatterbridgeMicrowaveOvenControlServer.with(MicrowaveOvenControl.Feature.PowerInWatts), {
37
- supportedWatts,
38
- selectedWattIndex,
35
+ createDefaultMicrowaveOvenControlClusterServer(powerSetting, minPower, maxPower, powerStep, cookTime, maxCookTime) {
36
+ this.behaviors.require(MatterbridgeMicrowaveOvenControlServer.with(MicrowaveOvenControl.Feature.PowerAsNumber, MicrowaveOvenControl.Feature.PowerNumberLimits), {
37
+ powerSetting,
38
+ minPower,
39
+ maxPower,
40
+ powerStep,
39
41
  cookTime,
40
42
  maxCookTime,
41
43
  });
42
44
  return this;
43
45
  }
44
46
  }
45
- export class MatterbridgeMicrowaveOvenControlServer extends MicrowaveOvenControlServer.with(MicrowaveOvenControl.Feature.PowerInWatts) {
47
+ export class MatterbridgeMicrowaveOvenControlServer extends MicrowaveOvenControlServer.with(MicrowaveOvenControl.Feature.PowerAsNumber, MicrowaveOvenControl.Feature.PowerNumberLimits) {
46
48
  async initialize() {
47
49
  await super.initialize();
48
50
  const device = this.endpoint.stateOf(MatterbridgeServer);
@@ -76,13 +78,13 @@ export class MatterbridgeMicrowaveOvenControlServer extends MicrowaveOvenControl
76
78
  device.log.info(`MatterbridgeMicrowaveOvenControlServer: setCookingParameters called with no cookTime so set to 30sec.`);
77
79
  this.state.cookTime = 30;
78
80
  }
79
- if (request.wattSettingIndex !== undefined && request.wattSettingIndex >= 0 && request.wattSettingIndex < this.state.supportedWatts.length) {
80
- device.log.info(`MatterbridgeMicrowaveOvenControlServer: setCookingParameters called setting selectedWattIndex to ${request.wattSettingIndex}`);
81
- this.state.selectedWattIndex = request.wattSettingIndex;
81
+ if (request.powerSetting !== undefined && request.powerSetting >= this.state.minPower && request.powerSetting <= this.state.maxPower) {
82
+ device.log.info(`MatterbridgeMicrowaveOvenControlServer: setCookingParameters called setting powerSetting to ${request.powerSetting}`);
83
+ this.state.powerSetting = request.powerSetting;
82
84
  }
83
85
  else {
84
- device.log.info(`MatterbridgeMicrowaveOvenControlServer: setCookingParameters called with no wattSettingIndex so set to the highest Watt setting for the selected CookMode`);
85
- this.state.selectedWattIndex = this.state.supportedWatts.length - 1;
86
+ device.log.info(`MatterbridgeMicrowaveOvenControlServer: setCookingParameters called with no powerSetting so set to maxPower`);
87
+ this.state.powerSetting = this.state.maxPower;
86
88
  }
87
89
  if (request.startAfterSetting === true) {
88
90
  device.log.info(`MatterbridgeMicrowaveOvenControlServer: setCookingParameters called setting startAfterSetting = true`);
@@ -175,6 +175,7 @@ export declare class MatterbridgeEndpoint extends Endpoint {
175
175
  createDefaultThermostatClusterServer(localTemperature?: number, occupiedHeatingSetpoint?: number, occupiedCoolingSetpoint?: number, minSetpointDeadBand?: number, minHeatSetpointLimit?: number, maxHeatSetpointLimit?: number, minCoolSetpointLimit?: number, maxCoolSetpointLimit?: number, unoccupiedHeatingSetpoint?: number, unoccupiedCoolingSetpoint?: number, occupied?: boolean, outdoorTemperature?: number | null): this;
176
176
  createDefaultHeatingThermostatClusterServer(localTemperature?: number, occupiedHeatingSetpoint?: number, minHeatSetpointLimit?: number, maxHeatSetpointLimit?: number, unoccupiedHeatingSetpoint?: number, occupied?: boolean, outdoorTemperature?: number | null): this;
177
177
  createDefaultPresetsThermostatClusterServer(localTemperature?: number, occupiedHeatingSetpoint?: number, occupiedCoolingSetpoint?: number, minSetpointDeadBand?: number, minHeatSetpointLimit?: number, maxHeatSetpointLimit?: number, minCoolSetpointLimit?: number, maxCoolSetpointLimit?: number, unoccupiedHeatingSetpoint?: number, unoccupiedCoolingSetpoint?: number, occupied?: boolean, outdoorTemperature?: number | null, activePresetHandle?: Uint8Array | null, presets?: Thermostat.Preset[], presetTypes?: Thermostat.PresetType[]): this;
178
+ createDefaultSchedulesThermostatClusterServer(localTemperature?: number, occupiedHeatingSetpoint?: number, occupiedCoolingSetpoint?: number, minSetpointDeadBand?: number, minHeatSetpointLimit?: number, maxHeatSetpointLimit?: number, minCoolSetpointLimit?: number, maxCoolSetpointLimit?: number, unoccupiedHeatingSetpoint?: number, unoccupiedCoolingSetpoint?: number, occupied?: boolean, outdoorTemperature?: number | null, activeScheduleHandle?: Uint8Array | null, schedules?: Thermostat.Schedule[], scheduleTypes?: Thermostat.ScheduleType[], numberOfScheduleTransitions?: number, numberOfScheduleTransitionPerDay?: number | null): this;
178
179
  createDefaultCoolingThermostatClusterServer(localTemperature?: number, occupiedCoolingSetpoint?: number, minCoolSetpointLimit?: number, maxCoolSetpointLimit?: number, unoccupiedCoolingSetpoint?: number, occupied?: boolean, outdoorTemperature?: number | null): this;
179
180
  createDefaultThermostatUserInterfaceConfigurationClusterServer(temperatureDisplayMode?: ThermostatUserInterfaceConfiguration.TemperatureDisplayMode, keypadLockout?: ThermostatUserInterfaceConfiguration.KeypadLockout, scheduleProgrammingVisibility?: ThermostatUserInterfaceConfiguration.ScheduleProgrammingVisibility): this;
180
181
  createDefaultFanControlClusterServer(fanMode?: FanControl.FanMode, fanModeSequence?: FanControl.FanModeSequence, percentSetting?: number, percentCurrent?: number): this;
@@ -992,7 +992,7 @@ export class MatterbridgeEndpoint extends Endpoint {
992
992
  ...(occupied !== undefined ? { unoccupiedCoolingSetpoint: unoccupiedCoolingSetpoint !== undefined ? unoccupiedCoolingSetpoint * 100 : 2700 } : {}),
993
993
  ...(occupied !== undefined ? { occupancy: { occupied } } : {}),
994
994
  ...(occupied !== undefined ? { externallyMeasuredOccupancy: true } : {}),
995
- numberOfPresets: Math.max(Array.isArray(presets) ? presets.length : 0, 10),
995
+ numberOfPresets: Math.max(Array.isArray(presets) ? presets.length : 0, Array.isArray(presetTypes) ? Math.max(0, ...presetTypes.map((pt) => pt.numberOfPresets ?? 0)) : 0, 1),
996
996
  activePresetHandle: activePresetHandle ? Uint8Array.from([activePresetHandle]) : null,
997
997
  presets: (presets ?? []).map((p) => ({
998
998
  presetHandle: p.presetHandle ? Uint8Array.from(p.presetHandle) : null,
@@ -1010,6 +1010,55 @@ export class MatterbridgeEndpoint extends Endpoint {
1010
1010
  });
1011
1011
  return this;
1012
1012
  }
1013
+ createDefaultSchedulesThermostatClusterServer(localTemperature = 23, occupiedHeatingSetpoint = 21, occupiedCoolingSetpoint = 25, minSetpointDeadBand = 0, minHeatSetpointLimit = 0, maxHeatSetpointLimit = 50, minCoolSetpointLimit = 0, maxCoolSetpointLimit = 50, unoccupiedHeatingSetpoint, unoccupiedCoolingSetpoint, occupied, outdoorTemperature, activeScheduleHandle = null, schedules = [], scheduleTypes = [
1014
+ {
1015
+ systemMode: Thermostat.SystemMode.Auto,
1016
+ numberOfSchedules: 10,
1017
+ scheduleTypeFeatures: { supportsSetpoints: true, supportsNames: true, supportsPresets: false, supportsOff: false },
1018
+ },
1019
+ ], numberOfScheduleTransitions = 10, numberOfScheduleTransitionPerDay = null) {
1020
+ this.behaviors.require(MatterbridgeThermostatServer.with(Thermostat.Feature.Heating, Thermostat.Feature.Cooling, Thermostat.Feature.AutoMode, ...(occupied !== undefined ? [Thermostat.Feature.Occupancy] : []), Thermostat.Feature.MatterScheduleConfiguration), {
1021
+ localTemperature: localTemperature * 100,
1022
+ externalMeasuredIndoorTemperature: localTemperature * 100,
1023
+ ...(outdoorTemperature !== undefined ? { outdoorTemperature: outdoorTemperature !== null ? outdoorTemperature * 100 : outdoorTemperature } : {}),
1024
+ systemMode: Thermostat.SystemMode.Auto,
1025
+ controlSequenceOfOperation: Thermostat.ControlSequenceOfOperation.CoolingAndHeating,
1026
+ occupiedHeatingSetpoint: occupiedHeatingSetpoint * 100,
1027
+ minHeatSetpointLimit: minHeatSetpointLimit * 100,
1028
+ maxHeatSetpointLimit: maxHeatSetpointLimit * 100,
1029
+ absMinHeatSetpointLimit: minHeatSetpointLimit * 100,
1030
+ absMaxHeatSetpointLimit: maxHeatSetpointLimit * 100,
1031
+ occupiedCoolingSetpoint: occupiedCoolingSetpoint * 100,
1032
+ minCoolSetpointLimit: minCoolSetpointLimit * 100,
1033
+ maxCoolSetpointLimit: maxCoolSetpointLimit * 100,
1034
+ absMinCoolSetpointLimit: minCoolSetpointLimit * 100,
1035
+ absMaxCoolSetpointLimit: maxCoolSetpointLimit * 100,
1036
+ minSetpointDeadBand: minSetpointDeadBand * 10,
1037
+ thermostatRunningMode: Thermostat.ThermostatRunningMode.Off,
1038
+ ...(occupied !== undefined ? { unoccupiedHeatingSetpoint: unoccupiedHeatingSetpoint !== undefined ? unoccupiedHeatingSetpoint * 100 : 1900 } : {}),
1039
+ ...(occupied !== undefined ? { unoccupiedCoolingSetpoint: unoccupiedCoolingSetpoint !== undefined ? unoccupiedCoolingSetpoint * 100 : 2700 } : {}),
1040
+ ...(occupied !== undefined ? { occupancy: { occupied } } : {}),
1041
+ ...(occupied !== undefined ? { externallyMeasuredOccupancy: true } : {}),
1042
+ numberOfSchedules: Math.max(Array.isArray(schedules) ? schedules.length : 0, Array.isArray(scheduleTypes) ? Math.max(0, ...scheduleTypes.map((st) => st.numberOfSchedules ?? 0)) : 0, 1),
1043
+ numberOfScheduleTransitions,
1044
+ numberOfScheduleTransitionPerDay,
1045
+ activeScheduleHandle: activeScheduleHandle ? Uint8Array.from(activeScheduleHandle) : null,
1046
+ schedules: (schedules ?? []).map((s) => ({
1047
+ scheduleHandle: s.scheduleHandle ? Uint8Array.from(s.scheduleHandle) : null,
1048
+ systemMode: s.systemMode,
1049
+ name: s.name,
1050
+ presetHandle: s.presetHandle ? Uint8Array.from(s.presetHandle) : undefined,
1051
+ transitions: s.transitions ?? [],
1052
+ builtIn: s.builtIn ?? true,
1053
+ })),
1054
+ scheduleTypes: (scheduleTypes ?? []).map((st) => ({
1055
+ ...st,
1056
+ numberOfSchedules: st.numberOfSchedules ?? 0,
1057
+ scheduleTypeFeatures: st.scheduleTypeFeatures ?? { supportsSetpoints: true, supportsNames: true, supportsPresets: false, supportsOff: false },
1058
+ })),
1059
+ });
1060
+ return this;
1061
+ }
1013
1062
  createDefaultCoolingThermostatClusterServer(localTemperature = 23, occupiedCoolingSetpoint = 25, minCoolSetpointLimit = 0, maxCoolSetpointLimit = 50, unoccupiedCoolingSetpoint, occupied, outdoorTemperature) {
1014
1063
  this.behaviors.require(MatterbridgeThermostatServer.with(Thermostat.Feature.Cooling, ...(occupied !== undefined ? [Thermostat.Feature.Occupancy] : [])), {
1015
1064
  localTemperature: localTemperature * 100,
@@ -457,6 +457,7 @@ export type CommandHandlerDataMap = {
457
457
  };
458
458
  'setpointRaiseLower': CommandHandlerData<'Thermostat.setpointRaiseLower'>;
459
459
  'setActivePresetRequest': CommandHandlerData<'Thermostat.setActivePresetRequest'>;
460
+ 'setActiveScheduleRequest': CommandHandlerData<'Thermostat.setActiveScheduleRequest'>;
460
461
  'Thermostat.setpointRaiseLower': {
461
462
  command: 'setpointRaiseLower';
462
463
  request: Thermostat.SetpointRaiseLowerRequest;
@@ -471,6 +472,13 @@ export type CommandHandlerDataMap = {
471
472
  attributes: ClusterAttributeValues<(typeof Thermostat)['attributes']>;
472
473
  endpoint: MatterbridgeEndpoint;
473
474
  };
475
+ 'Thermostat.setActiveScheduleRequest': {
476
+ command: 'setActiveScheduleRequest';
477
+ request: Thermostat.SetActiveScheduleRequest;
478
+ cluster: 'thermostat';
479
+ attributes: ClusterAttributeValues<(typeof Thermostat)['attributes']>;
480
+ endpoint: MatterbridgeEndpoint;
481
+ };
474
482
  'step': CommandHandlerData<'FanControl.step'>;
475
483
  'FanControl.step': {
476
484
  command: 'step';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@matterbridge/core",
3
- "version": "3.10.5-dev-20260807-79a10b4",
3
+ "version": "3.10.5-dev-20260809-ffe76d7",
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.5-dev-20260807-79a10b4",
136
- "@matterbridge/thread": "3.10.5-dev-20260807-79a10b4",
137
- "@matterbridge/types": "3.10.5-dev-20260807-79a10b4",
138
- "@matterbridge/utils": "3.10.5-dev-20260807-79a10b4",
135
+ "@matterbridge/dgram": "3.10.5-dev-20260809-ffe76d7",
136
+ "@matterbridge/thread": "3.10.5-dev-20260809-ffe76d7",
137
+ "@matterbridge/types": "3.10.5-dev-20260809-ffe76d7",
138
+ "@matterbridge/utils": "3.10.5-dev-20260809-ffe76d7",
139
139
  "escape-html": "1.0.3",
140
140
  "express": "5.2.1",
141
141
  "express-rate-limit": "8.6.2",