Skip to content

Commit

Permalink
Update 24.01.25 (#338)
Browse files Browse the repository at this point in the history
* Convenience methods to sync lighting classes

* Allow to turn on/off via dimmer

* move switch PRESS detection to events

* fix some node info

* Readme

* deps

---------

Co-authored-by: Bluefox <[email protected]>
  • Loading branch information
Apollon77 and GermanBluefox authored Jan 24, 2025
1 parent 94fa7e6 commit 988468a
Show file tree
Hide file tree
Showing 13 changed files with 163 additions and 38 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,13 @@ With the ioBroker Matter Adapter it is possible to map the following use cases:
-->

## Changelog

### __WORK IN PROGRESS__
* (@bluefox) Optimized UI
* (@Apollon77) Allows to turn light on/off via the dimming level as Zigbee adapter does
* (@Apollon77) Detects Switch changes via event which should be more reliable
* (@Apollon77) Optimizes some Node information

### 0.4.2 (2025-01-23)
* (@Apollon77) Added SmokeCO2Alarm -> FireAlarm to Controller device types
* (@Apollon77) Detects BLE only QR codes and respond with error message
Expand Down
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"dependencies": {
"@iobroker/adapter-core": "^3.2.3",
"@iobroker/i18n": "^0.3.1",
"@iobroker/dm-utils": "^1.0.6",
"@iobroker/dm-utils": "^1.0.7",
"@iobroker/type-detector": "^4.1.1",
"@matter/main": "0.12.0",
"@matter/nodejs": "0.12.0",
Expand Down
28 changes: 14 additions & 14 deletions src-admin/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions src-admin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
},
"dependencies": {
"@foxriver76/iob-component-lib": "^0.2.0",
"@iobroker/adapter-react-v5": "^7.4.16",
"@iobroker/dm-gui-components": "^7.4.16",
"@iobroker/adapter-react-v5": "^7.4.17",
"@iobroker/dm-gui-components": "^7.4.17",
"@iobroker/type-detector": "^4.1.1",
"@types/react-dom": "^18.3.5",
"@types/uuid": "^10.0.0",
Expand Down Expand Up @@ -51,4 +51,4 @@
}
]
]
}
}
1 change: 1 addition & 0 deletions src/lib/DeviceManagement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ class MatterAdapterDeviceManagement extends DeviceManagement<MatterAdapter> {
hasDetails: true,
actions: actions.length ? (actions as DeviceAction<'adapter'>[]) : undefined,
color,
headerTextColor: '#002346',
group: {
key: 'node',
name: this.#adapter.getText('Node'),
Expand Down
12 changes: 12 additions & 0 deletions src/lib/devices/Dimmer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,18 @@ export class Dimmer extends ElectricityDataDevice {
return !!this.#setLevelState;
}

getDimmer(): number | undefined {
return this.getLevel();
}

updateDimmer(value: number): Promise<void> {
return this.updateLevel(value);
}

setDimmer(value: number): Promise<void> {
return this.setLevel(value);
}

async updateLevel(value: number): Promise<void> {
if (!this.#setLevelState && !this.#getLevelState) {
throw new Error('Level state not found');
Expand Down
32 changes: 25 additions & 7 deletions src/matter/GeneralMatterNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1091,20 +1091,38 @@ export class GeneralMatterNode {
}

result.specification = {};
if (details.dataModelVersion) {
result.specification.dataModelVersion = details.dataModelVersion;
if (typeof details.dataModelRevision === 'number') {
result.specification.dataModelRevision = details.dataModelRevision;
}
if (typeof details.specificationVersion === 'number') {
result.specification.specificationVersion = SpecificationVersion.decode(details.specificationVersion);
} else if (details.specificationVersion === undefined) {
result.specification.specificationVersion = '< 1.3.0';
const { major, minor, patch } = SpecificationVersion.decode(details.specificationVersion);
result.specification.specificationVersion = `${major}.${minor}.${patch}`;
} else {
result.specification.specificationVersion = details.specificationVersion;
if (typeof details.dataModelRevision === 'number') {
if (details.dataModelRevision <= 16) {
result.specification.specificationVersion = '<1.2.0';
} else if (details.dataModelRevision === 17) {
result.specification.specificationVersion = '1.2.0';
} else {
result.specification.specificationVersion = 'unknown';
}
}
}
if (details.maxPathsPerInvoke) {
result.specification.maxPathsPerInvoke = details.maxPathsPerInvoke;
}
result.specification.capabilityMinima = JSON.stringify(details.capabilityMinima);
if (
details.capabilityMinima !== undefined &&
details.capabilityMinima !== null &&
typeof details.capabilityMinima === 'object'
) {
if ('caseSessionsPerFabric' in details.capabilityMinima) {
result.specification.sessionsPerFabric = details.capabilityMinima.caseSessionsPerFabric;
}
if ('subscriptionsPerFabric' in details.capabilityMinima) {
result.specification.subscriptionsPerFabric = details.capabilityMinima.subscriptionsPerFabric;
}
}
}

const rootEndpoint = this.node.getRootEndpoint();
Expand Down
30 changes: 28 additions & 2 deletions src/matter/to-iobroker/ColorTemperatureLightToIoBroker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,18 @@ export class ColorTemperatureLightToIoBroker extends GenericElectricityDataDevic
attributeName: 'onOff',
changeHandler: async value => {
if (value) {
if (this.#ioBrokerDevice.hasDimmer()) {
// Check if the Dimmer in ioBroker still matches the Device Dimmer and correct if needed
const currentLevel = await this.appEndpoint
.getClusterClient(LevelControl.Cluster)
?.getCurrentLevelAttribute();
if (typeof currentLevel === 'number' && currentLevel <= 1) {
const ioLevel = Math.round((currentLevel / 100) * 254);
if (ioLevel !== this.#ioBrokerDevice.getDimmer()) {
await this.#ioBrokerDevice.updateDimmer(ioLevel);
}
}
}
await this.appEndpoint.getClusterClient(OnOff.Complete)?.on();
} else {
await this.appEndpoint.getClusterClient(OnOff.Complete)?.off();
Expand All @@ -94,20 +106,31 @@ export class ColorTemperatureLightToIoBroker extends GenericElectricityDataDevic
clusterId: LevelControl.Cluster.id,
attributeName: 'currentLevel',
changeHandler: async value => {
if (value === 0) {
// ioBroker users expect that it turns off when level is set to 0
await this.#ioBrokerDevice.updateDimmer(0);
await this.appEndpoint.getClusterClient(OnOff.Complete)?.off();
return;
}
let level = Math.round((value / 100) * 254);
if (level < this.#minLevel) {
level = this.#minLevel;
} else if (level > this.#maxLevel) {
level = this.#maxLevel;
}
const transitionTime = this.ioBrokerDevice.getTransitionTime() ?? null;
const isOn = this.#ioBrokerDevice.getPower() ?? false;
const transitionTime = isOn ? (this.ioBrokerDevice.getTransitionTime() ?? null) : null;

await this.appEndpoint.getClusterClient(LevelControl.Complete)?.moveToLevel({
level,
transitionTime: transitionTime !== null ? Math.round(transitionTime / 100) : null,
optionsMask: { executeIfOff: true },
optionsOverride: { executeIfOff: true },
});

if (!isOn) {
await this.appEndpoint.getClusterClient(OnOff.Complete)?.on();
}
},
convertValue: value => Math.round((value / 254) * 100),
});
Expand All @@ -123,7 +146,10 @@ export class ColorTemperatureLightToIoBroker extends GenericElectricityDataDevic
} else if (colorTemperatureMireds > this.#colorTemperatureMaxMireds) {
colorTemperatureMireds = this.#colorTemperatureMaxMireds;
}
const transitionTime = Math.round((this.ioBrokerDevice.getTransitionTime() ?? 0) / 100);

const isOn = this.#ioBrokerDevice.getPower() ?? false;
const transitionTime = isOn ? Math.round((this.ioBrokerDevice.getTransitionTime() ?? 0) / 100) : 0;

await this.appEndpoint.getClusterClient(ColorControl.Complete)?.moveToColorTemperature({
colorTemperatureMireds,
transitionTime,
Expand Down
27 changes: 26 additions & 1 deletion src/matter/to-iobroker/DimmableToIoBroker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,18 @@ export class DimmableToIoBroker extends GenericElectricityDataDeviceToIoBroker {
attributeName: 'onOff',
changeHandler: async value => {
if (value) {
if (this.#ioBrokerDevice.hasDimmer()) {
// Check if the Dimmer in ioBroker still matches the Device Dimmer and correct if needed
const currentLevel = await this.appEndpoint
.getClusterClient(LevelControl.Cluster)
?.getCurrentLevelAttribute();
if (typeof currentLevel === 'number' && currentLevel <= 1) {
const ioLevel = Math.round((currentLevel / 100) * 254);
if (ioLevel !== this.#ioBrokerDevice.getDimmer()) {
await this.#ioBrokerDevice.updateDimmer(ioLevel);
}
}
}
await this.appEndpoint.getClusterClient(OnOff.Complete)?.on();
} else {
await this.appEndpoint.getClusterClient(OnOff.Complete)?.off();
Expand All @@ -82,19 +94,32 @@ export class DimmableToIoBroker extends GenericElectricityDataDeviceToIoBroker {
clusterId: LevelControl.Cluster.id,
attributeName: 'currentLevel',
changeHandler: async value => {
if (value === 0) {
// ioBroker users expect that it turns off when level is set to 0
await this.#ioBrokerDevice.updateDimmer(0);
await this.appEndpoint.getClusterClient(OnOff.Complete)?.off();
return;
}
let level = Math.round((value / 100) * 254);
if (level < this.#minLevel) {
level = this.#minLevel;
} else if (level > this.#maxLevel) {
level = this.#maxLevel;
}
const transitionTime = this.ioBrokerDevice.getTransitionTime() ?? null;

const isOn = this.#ioBrokerDevice.getPower() ?? false;
const transitionTime = isOn ? (this.ioBrokerDevice.getTransitionTime() ?? null) : null;

await this.appEndpoint.getClusterClient(LevelControl.Complete)?.moveToLevel({
level,
transitionTime: transitionTime !== null ? Math.round(transitionTime / 100) : null,
optionsMask: { executeIfOff: true },
optionsOverride: { executeIfOff: true },
});

if (!isOn) {
await this.appEndpoint.getClusterClient(OnOff.Complete)?.on();
}
},
convertValue: value => Math.round((value / 254) * 100),
});
Expand Down
Loading

0 comments on commit 988468a

Please sign in to comment.