@matterbridge/core 3.6.0-dev-20260302-e3a7eb0 → 3.6.0-dev-20260303-2f99eca

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.
@@ -0,0 +1,204 @@
1
+ import { MaybePromise } from '@matter/general';
2
+ import { ClusterBehavior } from '@matter/node';
3
+ import { ClosureDimension } from '../clusters/closure-dimension.js';
4
+ import { MatterbridgeEndpoint } from '../matterbridgeEndpoint.js';
5
+ export interface ClosurePanelOptions {
6
+ resolution?: number;
7
+ stepValue?: number;
8
+ }
9
+ declare const ClosureDimensionServerBase: ClusterBehavior.Type<import("@matter/types").ClusterComposer.Of<import("@matter/types").ClusterType.Of<{
10
+ readonly id: 261;
11
+ readonly name: "ClosureDimension";
12
+ readonly revision: 1;
13
+ readonly features: {
14
+ readonly positioning: import("@matter/types").BitFlag;
15
+ readonly motionLatching: import("@matter/types").BitFlag;
16
+ readonly unit: import("@matter/types").BitFlag;
17
+ readonly limitation: import("@matter/types").BitFlag;
18
+ readonly speed: import("@matter/types").BitFlag;
19
+ readonly translation: import("@matter/types").BitFlag;
20
+ readonly rotation: import("@matter/types").BitFlag;
21
+ readonly modulation: import("@matter/types").BitFlag;
22
+ };
23
+ readonly attributes: {
24
+ readonly currentState: import("@matter/types").Attribute<import("@matter/types").TypeFromFields<{
25
+ position: import("@matter/types").OptionalFieldType<number | null>;
26
+ latch: import("@matter/types").OptionalFieldType<boolean | null>;
27
+ speed: import("@matter/types").OptionalFieldType<import("@matter/types").ThreeLevelAuto>;
28
+ }> | null, any>;
29
+ readonly targetState: import("@matter/types").Attribute<import("@matter/types").TypeFromFields<{
30
+ position: import("@matter/types").OptionalFieldType<number | null>;
31
+ latch: import("@matter/types").OptionalFieldType<boolean | null>;
32
+ speed: import("@matter/types").OptionalFieldType<import("@matter/types").ThreeLevelAuto>;
33
+ }> | null, any>;
34
+ };
35
+ readonly commands: {
36
+ readonly setTarget: import("@matter/types").Command<import("@matter/types").TypeFromFields<{
37
+ position: import("@matter/types").OptionalFieldType<number>;
38
+ latch: import("@matter/types").OptionalFieldType<boolean>;
39
+ speed: import("@matter/types").OptionalFieldType<import("@matter/types").ThreeLevelAuto>;
40
+ }>, void, any>;
41
+ };
42
+ readonly extensions: readonly [{
43
+ readonly flags: {
44
+ readonly positioning: true;
45
+ };
46
+ readonly component: {
47
+ readonly attributes: {
48
+ readonly resolution: import("@matter/types").FixedAttribute<number, any>;
49
+ readonly stepValue: import("@matter/types").FixedAttribute<number, any>;
50
+ };
51
+ readonly commands: {
52
+ readonly step: import("@matter/types").Command<import("@matter/types").TypeFromFields<{
53
+ direction: import("@matter/types").FieldType<ClosureDimension.StepDirection>;
54
+ numberOfSteps: import("@matter/types").FieldType<number>;
55
+ speed: import("@matter/types").OptionalFieldType<import("@matter/types").ThreeLevelAuto>;
56
+ }>, void, any>;
57
+ };
58
+ };
59
+ }, {
60
+ readonly flags: {
61
+ readonly motionLatching: true;
62
+ };
63
+ readonly component: {
64
+ readonly attributes: {
65
+ readonly latchControlModes: import("@matter/types").FixedAttribute<import("@matter/types").TypeFromPartialBitSchema<{
66
+ remoteLatching: import("@matter/types").BitFlag;
67
+ remoteUnlatching: import("@matter/types").BitFlag;
68
+ }>, any>;
69
+ };
70
+ };
71
+ }, {
72
+ readonly flags: {
73
+ readonly unit: true;
74
+ };
75
+ readonly component: {
76
+ readonly attributes: {
77
+ readonly unit: import("@matter/types").FixedAttribute<ClosureDimension.ClosureUnit, any>;
78
+ readonly unitRange: import("@matter/types").Attribute<import("@matter/types").TypeFromFields<{
79
+ min: import("@matter/types").FieldType<number>;
80
+ max: import("@matter/types").FieldType<number>;
81
+ }> | null, any>;
82
+ };
83
+ };
84
+ }, {
85
+ readonly flags: {
86
+ readonly limitation: true;
87
+ };
88
+ readonly component: {
89
+ readonly attributes: {
90
+ readonly limitRange: import("@matter/types").Attribute<import("@matter/types").TypeFromFields<{
91
+ min: import("@matter/types").FieldType<number>;
92
+ max: import("@matter/types").FieldType<number>;
93
+ }>, any>;
94
+ };
95
+ };
96
+ }, {
97
+ readonly flags: {
98
+ readonly translation: true;
99
+ };
100
+ readonly component: {
101
+ readonly attributes: {
102
+ readonly translationDirection: import("@matter/types").FixedAttribute<ClosureDimension.TranslationDirection, any>;
103
+ };
104
+ };
105
+ }, {
106
+ readonly flags: {
107
+ readonly rotation: true;
108
+ };
109
+ readonly component: {
110
+ readonly attributes: {
111
+ readonly rotationAxis: import("@matter/types").FixedAttribute<ClosureDimension.RotationAxis, any>;
112
+ readonly overflow: import("@matter/types").FixedAttribute<ClosureDimension.Overflow, any>;
113
+ };
114
+ };
115
+ }, {
116
+ readonly flags: {
117
+ readonly modulation: true;
118
+ };
119
+ readonly component: {
120
+ readonly attributes: {
121
+ readonly modulationType: import("@matter/types").FixedAttribute<ClosureDimension.ModulationType, any>;
122
+ };
123
+ };
124
+ }, {
125
+ readonly flags: {
126
+ readonly positioning: false;
127
+ readonly motionLatching: false;
128
+ };
129
+ readonly component: false;
130
+ }, {
131
+ readonly flags: {
132
+ readonly unit: true;
133
+ readonly positioning: false;
134
+ };
135
+ readonly component: false;
136
+ }, {
137
+ readonly flags: {
138
+ readonly limitation: true;
139
+ readonly positioning: false;
140
+ };
141
+ readonly component: false;
142
+ }, {
143
+ readonly flags: {
144
+ readonly speed: true;
145
+ readonly positioning: false;
146
+ };
147
+ readonly component: false;
148
+ }, {
149
+ readonly flags: {
150
+ readonly translation: true;
151
+ readonly positioning: false;
152
+ };
153
+ readonly component: false;
154
+ }, {
155
+ readonly flags: {
156
+ readonly rotation: true;
157
+ readonly positioning: false;
158
+ };
159
+ readonly component: false;
160
+ }, {
161
+ readonly flags: {
162
+ readonly modulation: true;
163
+ readonly positioning: false;
164
+ };
165
+ readonly component: false;
166
+ }, {
167
+ readonly flags: {
168
+ readonly translation: true;
169
+ readonly rotation: true;
170
+ };
171
+ readonly component: false;
172
+ }, {
173
+ readonly flags: {
174
+ readonly translation: true;
175
+ readonly modulation: true;
176
+ };
177
+ readonly component: false;
178
+ }, {
179
+ readonly flags: {
180
+ readonly rotation: true;
181
+ readonly modulation: true;
182
+ };
183
+ readonly component: false;
184
+ }];
185
+ }>, readonly [ClosureDimension.Feature.Positioning]>, typeof ClusterBehavior, {
186
+ components: never[];
187
+ }>;
188
+ export declare namespace ClosureDimensionServer {
189
+ interface State {
190
+ currentState: ClosureDimension.DimensionState | null;
191
+ targetState: ClosureDimension.DimensionState | null;
192
+ resolution: number;
193
+ stepValue: number;
194
+ }
195
+ }
196
+ export declare class ClosureDimensionServer extends ClosureDimensionServerBase {
197
+ state: ClosureDimensionServer.State;
198
+ setTarget: (request: ClosureDimension.SetTargetRequest) => MaybePromise;
199
+ step: (request: ClosureDimension.StepRequest) => MaybePromise;
200
+ }
201
+ export declare class ClosurePanel extends MatterbridgeEndpoint {
202
+ constructor(name: string, serial: string, options?: ClosurePanelOptions);
203
+ }
204
+ export {};
@@ -0,0 +1,55 @@
1
+ import { ClusterBehavior } from '@matter/node';
2
+ import { ClosureDimension } from '../clusters/closure-dimension.js';
3
+ import { MatterbridgeServer } from '../matterbridgeBehaviors.js';
4
+ import { closurePanel } from '../matterbridgeDeviceTypes.js';
5
+ import { MatterbridgeEndpoint } from '../matterbridgeEndpoint.js';
6
+ import { createClusterSchema } from './customClusterSchema.js';
7
+ const ClosureDimensionCluster = ClosureDimension.Cluster.with(ClosureDimension.Feature.Positioning);
8
+ const ClosureDimensionServerBase = ClusterBehavior.for(ClosureDimensionCluster, createClusterSchema(ClosureDimensionCluster));
9
+ export class ClosureDimensionServer extends ClosureDimensionServerBase {
10
+ setTarget = (request) => {
11
+ const device = this.endpoint.stateOf(MatterbridgeServer);
12
+ device.log.info(`SetTarget (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
13
+ device.commandHandler.executeHandler('setTarget', { request, cluster: ClosureDimension.Cluster.id, attributes: this.state, endpoint: this.endpoint });
14
+ const previousTarget = this.state.targetState ?? {};
15
+ const nextTarget = {
16
+ ...previousTarget,
17
+ ...(request?.position !== undefined ? { position: request.position } : null),
18
+ ...(request?.latch !== undefined ? { latch: request.latch } : null),
19
+ ...(request?.speed !== undefined ? { speed: request.speed } : null),
20
+ };
21
+ this.state.targetState = nextTarget;
22
+ };
23
+ step = (request) => {
24
+ const device = this.endpoint.stateOf(MatterbridgeServer);
25
+ device.log.info(`Step (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
26
+ device.commandHandler.executeHandler('step', { request, cluster: ClosureDimension.Cluster.id, attributes: this.state, endpoint: this.endpoint });
27
+ const stepValue = this.state.stepValue;
28
+ const numberOfSteps = request.numberOfSteps;
29
+ const delta = stepValue * numberOfSteps;
30
+ const isIncrease = request.direction === ClosureDimension.StepDirection.Increase;
31
+ const previousCurrent = this.state.currentState ?? {};
32
+ const previousTarget = this.state.targetState ?? {};
33
+ const currentPosition = typeof previousCurrent.position === 'number' ? previousCurrent.position : typeof previousTarget.position === 'number' ? previousTarget.position : 0;
34
+ let nextPosition = isIncrease ? currentPosition + delta : currentPosition - delta;
35
+ nextPosition = Math.max(0, Math.min(10000, nextPosition));
36
+ this.state.currentState = {
37
+ ...previousCurrent,
38
+ position: nextPosition,
39
+ ...(request?.speed !== undefined ? { speed: request.speed } : null),
40
+ };
41
+ this.state.targetState = { ...previousTarget, position: nextPosition };
42
+ };
43
+ }
44
+ export class ClosurePanel extends MatterbridgeEndpoint {
45
+ constructor(name, serial, options = {}) {
46
+ super([closurePanel], { id: `${name.replaceAll(' ', '')}-${serial.replaceAll(' ', '')}` });
47
+ this.createDefaultBasicInformationClusterServer(name, serial, 0xfff1, 'Matterbridge', 0x8000, 'Matterbridge Closure Panel');
48
+ this.behaviors.require(ClosureDimensionServer, {
49
+ currentState: null,
50
+ targetState: null,
51
+ resolution: options.resolution ?? 1,
52
+ stepValue: options.stepValue ?? 1,
53
+ });
54
+ }
55
+ }
@@ -0,0 +1,22 @@
1
+ import { ClusterModel } from '../matter/export.js';
2
+ type AnyCluster = {
3
+ id: number;
4
+ name: string;
5
+ revision?: number;
6
+ supportedFeatures?: Record<string, boolean>;
7
+ attributes?: Record<string, {
8
+ id: number;
9
+ default?: unknown;
10
+ optional?: boolean;
11
+ }>;
12
+ commands?: Record<string, {
13
+ requestId: number;
14
+ optional?: boolean;
15
+ }>;
16
+ events?: Record<string, {
17
+ id: number;
18
+ optional?: boolean;
19
+ }>;
20
+ };
21
+ export declare function createClusterSchema(cluster: AnyCluster): ClusterModel;
22
+ export {};
@@ -0,0 +1,53 @@
1
+ import { AttributeElement, ClusterModel, CommandElement, EventElement, FieldElement } from '../matter/export.js';
2
+ export function createClusterSchema(cluster) {
3
+ const children = [];
4
+ const featureNames = Object.keys(cluster.supportedFeatures ?? {});
5
+ if (featureNames.length > 0) {
6
+ children.push(AttributeElement({
7
+ id: 0xfffc,
8
+ name: 'FeatureMap',
9
+ type: 'FeatureMap',
10
+ conformance: 'M',
11
+ }, ...featureNames.map((name, index) => FieldElement({
12
+ name,
13
+ id: index,
14
+ type: 'bool',
15
+ constraint: index,
16
+ }))));
17
+ }
18
+ for (const [name, attribute] of Object.entries(cluster.attributes ?? {})) {
19
+ children.push(AttributeElement({
20
+ id: attribute.id,
21
+ name,
22
+ type: 'any',
23
+ conformance: 'O',
24
+ }));
25
+ }
26
+ for (const [name, command] of Object.entries(cluster.commands ?? {})) {
27
+ const element = CommandElement({
28
+ id: command.requestId,
29
+ name,
30
+ type: 'any',
31
+ direction: 'request',
32
+ conformance: 'O',
33
+ });
34
+ element.operationalIsSupported = true;
35
+ children.push(element);
36
+ }
37
+ for (const [name, event] of Object.entries(cluster.events ?? {})) {
38
+ const element = EventElement({
39
+ id: event.id,
40
+ name,
41
+ type: 'any',
42
+ priority: name === 'operationalError' ? 'critical' : 'info',
43
+ conformance: 'O',
44
+ });
45
+ element.operationalIsSupported = true;
46
+ children.push(element);
47
+ }
48
+ return new ClusterModel({
49
+ id: cluster.id,
50
+ name: cluster.name,
51
+ revision: cluster.revision ?? 1,
52
+ }, ...children);
53
+ }
@@ -1,6 +1,10 @@
1
1
  export * from './basicVideoPlayer.js';
2
2
  export * from './castingVideoPlayer.js';
3
3
  export * from './speaker.js';
4
+ export * from './closure.js';
5
+ export * from './closurePanel.js';
6
+ export * from './irrigationSystem.js';
7
+ export * from './soilSensor.js';
4
8
  export * from './roboticVacuumCleaner.js';
5
9
  export * from './airConditioner.js';
6
10
  export * from './cooktop.js';
@@ -1,6 +1,10 @@
1
1
  export * from './basicVideoPlayer.js';
2
2
  export * from './castingVideoPlayer.js';
3
3
  export * from './speaker.js';
4
+ export * from './closure.js';
5
+ export * from './closurePanel.js';
6
+ export * from './irrigationSystem.js';
7
+ export * from './soilSensor.js';
4
8
  export * from './roboticVacuumCleaner.js';
5
9
  export * from './airConditioner.js';
6
10
  export * from './cooktop.js';
@@ -1,11 +1,12 @@
1
- import { NumberTag, PowerSourceTag } from '@matter/node';
1
+ import { AreaNamespaceTag, NumberTag, PowerSourceTag } from '@matter/node';
2
2
  import { DeviceEnergyManagement } from '@matter/types/clusters/device-energy-management';
3
3
  import { deviceEnergyManagement, electricalSensor, heatPump, powerSource, temperatureSensor, thermostatDevice } from '../matterbridgeDeviceTypes.js';
4
4
  import { MatterbridgeEndpoint } from '../matterbridgeEndpoint.js';
5
+ import { getSemtag } from '../matterbridgeEndpointHelpers.js';
5
6
  export class HeatPump extends MatterbridgeEndpoint {
6
7
  constructor(name, serial, voltage = null, current = null, power = null, energyImported = null, absMinPower = 0, absMaxPower = 0) {
7
8
  super([heatPump, powerSource, electricalSensor, deviceEnergyManagement], {
8
- tagList: [{ mfgCode: null, namespaceId: PowerSourceTag.Grid.namespaceId, tag: PowerSourceTag.Grid.tag, label: null }],
9
+ tagList: [getSemtag(PowerSourceTag.Grid)],
9
10
  id: `${name.replaceAll(' ', '')}-${serial.replaceAll(' ', '')}`,
10
11
  });
11
12
  this.createDefaultIdentifyClusterServer()
@@ -18,19 +19,26 @@ export class HeatPump extends MatterbridgeEndpoint {
18
19
  .createDefaultDeviceEnergyManagementModeClusterServer()
19
20
  .addRequiredClusterServers();
20
21
  this.addChildDeviceType('FlowTemperature', temperatureSensor, {
21
- tagList: [{ mfgCode: null, namespaceId: NumberTag.One.namespaceId, tag: NumberTag.One.tag, label: 'Flow' }],
22
+ tagList: [getSemtag(NumberTag.One, 'FlowTemperature')],
22
23
  })
23
24
  .createDefaultTemperatureMeasurementClusterServer(4500)
24
25
  .addRequiredClusterServers();
25
26
  this.addChildDeviceType('ReturnTemperature', temperatureSensor, {
26
- tagList: [{ mfgCode: null, namespaceId: NumberTag.Two.namespaceId, tag: NumberTag.Two.tag, label: 'Return' }],
27
+ tagList: [getSemtag(NumberTag.Two, 'ReturnTemperature')],
27
28
  })
28
29
  .createDefaultTemperatureMeasurementClusterServer(3500)
29
30
  .addRequiredClusterServers();
30
- this.addChildDeviceType('Thermostat', thermostatDevice, {
31
- tagList: [{ mfgCode: null, namespaceId: NumberTag.One.namespaceId, tag: NumberTag.One.tag, label: 'Main Thermostat' }],
31
+ this.addChildDeviceType('LivingThermostat', thermostatDevice, {
32
+ tagList: [getSemtag(NumberTag.One, 'LivingThermostat'), getSemtag(AreaNamespaceTag.LivingRoom)],
32
33
  })
33
- .createDefaultHeatingThermostatClusterServer()
34
- .addRequiredClusterServers();
34
+ .createDefaultThermostatClusterServer()
35
+ .addRequiredClusterServers()
36
+ .addUserLabel('room', 'Living Room');
37
+ this.addChildDeviceType('BedroomThermostat', thermostatDevice, {
38
+ tagList: [getSemtag(NumberTag.Two, 'BedroomThermostat'), getSemtag(AreaNamespaceTag.Bedroom)],
39
+ })
40
+ .createDefaultThermostatClusterServer()
41
+ .addRequiredClusterServers()
42
+ .addUserLabel('room', 'Bedroom');
35
43
  }
36
44
  }
@@ -0,0 +1,9 @@
1
+ import { OperationalState } from '@matter/types/clusters/operational-state';
2
+ import { MatterbridgeEndpoint } from '../matterbridgeEndpoint.js';
3
+ export interface IrrigationSystemOptions {
4
+ operationalState?: OperationalState.OperationalStateEnum;
5
+ flowMeasuredValue?: number | null;
6
+ }
7
+ export declare class IrrigationSystem extends MatterbridgeEndpoint {
8
+ constructor(name: string, serial: string, options?: IrrigationSystemOptions);
9
+ }
@@ -0,0 +1,12 @@
1
+ import { OperationalState } from '@matter/types/clusters/operational-state';
2
+ import { irrigationSystem } from '../matterbridgeDeviceTypes.js';
3
+ import { MatterbridgeEndpoint } from '../matterbridgeEndpoint.js';
4
+ export class IrrigationSystem extends MatterbridgeEndpoint {
5
+ constructor(name, serial, options = {}) {
6
+ super([irrigationSystem], { id: `${name.replaceAll(' ', '')}-${serial.replaceAll(' ', '')}` });
7
+ this.createDefaultIdentifyClusterServer();
8
+ this.createDefaultBasicInformationClusterServer(name, serial, 0xfff1, 'Matterbridge', 0x8000, 'Matterbridge Irrigation System');
9
+ this.createDefaultOperationalStateClusterServer(options.operationalState ?? OperationalState.OperationalStateEnum.Stopped);
10
+ this.createDefaultFlowMeasurementClusterServer(options.flowMeasuredValue ?? null);
11
+ }
12
+ }
@@ -0,0 +1,14 @@
1
+ import { ClusterBehavior } from '@matter/node';
2
+ import { SoilMeasurement } from '../clusters/soil-measurement.js';
3
+ import { MatterbridgeEndpoint } from '../matterbridgeEndpoint.js';
4
+ export interface SoilSensorOptions {
5
+ soilMoistureMeasuredValue?: number | null;
6
+ }
7
+ export declare const SoilMeasurementServer: ClusterBehavior.Type<SoilMeasurement.Cluster, typeof ClusterBehavior, {
8
+ components: never[];
9
+ }>;
10
+ export declare class SoilSensor extends MatterbridgeEndpoint {
11
+ constructor(name: string, serial: string, options?: SoilSensorOptions);
12
+ setSoilMoistureMeasuredValue(value: number | null): Promise<void>;
13
+ getSoilMoistureMeasuredValue(): number | null;
14
+ }
@@ -0,0 +1,30 @@
1
+ import { ClusterBehavior } from '@matter/node';
2
+ import { MeasurementType } from '@matter/types/globals';
3
+ import { SoilMeasurement } from '../clusters/soil-measurement.js';
4
+ import { soilSensor } from '../matterbridgeDeviceTypes.js';
5
+ import { MatterbridgeEndpoint } from '../matterbridgeEndpoint.js';
6
+ import { createClusterSchema } from './customClusterSchema.js';
7
+ export const SoilMeasurementServer = ClusterBehavior.for(SoilMeasurement.Cluster, createClusterSchema(SoilMeasurement.Cluster));
8
+ export class SoilSensor extends MatterbridgeEndpoint {
9
+ constructor(name, serial, options = {}) {
10
+ super([soilSensor], { id: `${name.replaceAll(' ', '')}-${serial.replaceAll(' ', '')}` });
11
+ this.createDefaultIdentifyClusterServer();
12
+ this.createDefaultBasicInformationClusterServer(name, serial, 0xfff1, 'Matterbridge', 0x8000, 'Matterbridge Soil Sensor');
13
+ this.behaviors.require(SoilMeasurementServer, {
14
+ soilMoistureMeasurementLimits: {
15
+ measurementType: MeasurementType.SoilMoisture,
16
+ measured: true,
17
+ minMeasuredValue: 0,
18
+ maxMeasuredValue: 100,
19
+ accuracyRanges: [{ rangeMin: 0, rangeMax: 100, fixedMax: 1 }],
20
+ },
21
+ soilMoistureMeasuredValue: options.soilMoistureMeasuredValue ?? null,
22
+ });
23
+ }
24
+ async setSoilMoistureMeasuredValue(value) {
25
+ await this.setAttribute(SoilMeasurement.Cluster.id, 'soilMoistureMeasuredValue', value);
26
+ }
27
+ getSoilMoistureMeasuredValue() {
28
+ return this.getAttribute(SoilMeasurement.Cluster.id, 'soilMoistureMeasuredValue');
29
+ }
30
+ }
@@ -1,4 +1,6 @@
1
+ import { Semtag } from '@matter/types/globals';
1
2
  import { MatterbridgeEndpoint } from '../matterbridgeEndpoint.js';
2
3
  export declare class SolarPower extends MatterbridgeEndpoint {
3
- constructor(name: string, serial: string, voltage?: number | bigint | null, current?: number | bigint | null, power?: number | bigint | null, energyExported?: number | bigint | null, absMinPower?: number, absMaxPower?: number);
4
+ constructor(name: string, serial: string, voltage?: number | bigint | null, current?: number | bigint | null, power?: number | bigint | null, energyExported?: number | bigint, absMinPower?: number, absMaxPower?: number);
5
+ addPanel(name: string, tag: Semtag, voltage?: number | bigint | null, current?: number | bigint | null, power?: number | bigint | null, energyExported?: number | bigint | null): MatterbridgeEndpoint;
4
6
  }
@@ -2,11 +2,12 @@ import { PowerSourceTag } from '@matter/node';
2
2
  import { DeviceEnergyManagement } from '@matter/types/clusters/device-energy-management';
3
3
  import { deviceEnergyManagement, electricalSensor, powerSource, solarPower } from '../matterbridgeDeviceTypes.js';
4
4
  import { MatterbridgeEndpoint } from '../matterbridgeEndpoint.js';
5
+ import { getSemtag } from '../matterbridgeEndpointHelpers.js';
5
6
  export class SolarPower extends MatterbridgeEndpoint {
6
- constructor(name, serial, voltage = null, current = null, power = null, energyExported = null, absMinPower = 0, absMaxPower = 0) {
7
+ constructor(name, serial, voltage = null, current = null, power = null, energyExported = 0, absMinPower = 0, absMaxPower = 0) {
7
8
  super([solarPower, powerSource, electricalSensor, deviceEnergyManagement], {
8
- tagList: [{ mfgCode: null, namespaceId: PowerSourceTag.Solar.namespaceId, tag: PowerSourceTag.Solar.tag, label: null }],
9
9
  id: `${name.replaceAll(' ', '')}-${serial.replaceAll(' ', '')}`,
10
+ tagList: [getSemtag(PowerSourceTag.Solar)],
10
11
  });
11
12
  this.createDefaultIdentifyClusterServer()
12
13
  .createDefaultBasicInformationClusterServer(name, serial, 0xfff1, 'Matterbridge', 0x8000, 'Matterbridge Solar Power')
@@ -18,4 +19,15 @@ export class SolarPower extends MatterbridgeEndpoint {
18
19
  .createDefaultDeviceEnergyManagementModeClusterServer()
19
20
  .addRequiredClusterServers();
20
21
  }
22
+ addPanel(name, tag, voltage = null, current = null, power = null, energyExported = null) {
23
+ const panel = this.addChildDeviceType(name, electricalSensor, {
24
+ tagList: [getSemtag(PowerSourceTag.Solar), getSemtag(tag)],
25
+ })
26
+ .createDefaultPowerTopologyClusterServer()
27
+ .createDefaultElectricalPowerMeasurementClusterServer(voltage, current, power)
28
+ .createDefaultElectricalEnergyMeasurementClusterServer(0, energyExported)
29
+ .addRequiredClusterServers();
30
+ panel.addUserLabel('panel', name.slice(0, 16));
31
+ return panel;
32
+ }
21
33
  }