mirror of
https://github.com/danieldemus/openhab-addons
synced 2026-07-29 12:34:21 +02:00
[matter] Matter.js 0.17 Bridge Fixes (#20913)
* [matter] Matter.js 0.17 Bridge Fixes Updates our bridge to support 0.17 changes to the bridge. Fixes #20910 Signed-off-by: Dan Cunningham <dan@digitaldan.com> * PR feedback Signed-off-by: Dan Cunningham <dan@digitaldan.com> --------- Signed-off-by: Dan Cunningham <dan@digitaldan.com>
This commit is contained in:
+14
-6
@@ -1,7 +1,10 @@
|
||||
import { Logger } from "@matter/main";
|
||||
import { DoorLockServer } from "@matter/main/behaviors";
|
||||
import { DoorLock } from "@matter/main/clusters";
|
||||
import { DeviceFunctions } from "../DeviceFunctions";
|
||||
|
||||
const logger = Logger.get("CustomDoorLockServer");
|
||||
|
||||
export class CustomDoorLockServer extends DoorLockServer {
|
||||
static readonly DEFAULTS = {
|
||||
lockState: 0,
|
||||
@@ -26,15 +29,20 @@ export class CustomDoorLockServer extends DoorLockServer {
|
||||
}
|
||||
|
||||
/**
|
||||
* For Lock/Unlock, we need to wait for the state update to be sent to the bridge controller if the state is not already the desired state.
|
||||
* Locks can often take a while to lock/unlock so we need to wait longer for the state update to be sent to the bridge controller.
|
||||
* Waits for openHAB to confirm the new lockState (longer timeout since locks can be slow).
|
||||
*/
|
||||
private async sendLockState(lockState: DoorLock.LockState) {
|
||||
this.env.get(DeviceFunctions).sendAttributeChangedEvent(this.endpoint.id, "doorLock", "lockState", lockState);
|
||||
if (this.endpoint.stateOf(CustomDoorLockServer).lockState !== lockState) {
|
||||
const result = await this.env
|
||||
.get(DeviceFunctions)
|
||||
.waitForStateUpdate(this.endpoint.id, "doorLock", "lockState", 30000);
|
||||
if (this.state.lockState !== lockState) {
|
||||
let result: DoorLock.LockState | undefined;
|
||||
try {
|
||||
result = await this.env
|
||||
.get(DeviceFunctions)
|
||||
.waitForStateUpdate(this.endpoint.id, "doorLock", "lockState", 30000);
|
||||
} catch {
|
||||
logger.debug(`No lockState confirmation from openHAB for ${this.endpoint.id}, proceeding`);
|
||||
return;
|
||||
}
|
||||
if (result !== lockState) {
|
||||
throw new Error("Lock state failed", { cause: result });
|
||||
}
|
||||
|
||||
+11
-5
@@ -1,8 +1,10 @@
|
||||
import { MaybePromise } from "@matter/main";
|
||||
import { Logger, MaybePromise } from "@matter/main";
|
||||
import { LevelControlServer } from "@matter/main/behaviors";
|
||||
import { LevelControl } from "@matter/main/clusters";
|
||||
import { DeviceFunctions } from "../DeviceFunctions";
|
||||
|
||||
const logger = Logger.get("CustomLevelControlServer");
|
||||
|
||||
export class CustomLevelControlServer extends LevelControlServer {
|
||||
static readonly DEFAULTS = { currentLevel: 254 } as const;
|
||||
|
||||
@@ -28,10 +30,14 @@ export class CustomLevelControlServer extends LevelControlServer {
|
||||
this.env
|
||||
.get(DeviceFunctions)
|
||||
.sendAttributeChangedEvent(this.endpoint.id, "levelControl", "currentLevel", level);
|
||||
if (this.endpoint.stateOf(CustomLevelControlServer).currentLevel !== level) {
|
||||
await this.env
|
||||
.get(DeviceFunctions)
|
||||
.waitForStateUpdate(this.endpoint.id, "levelControl", "currentLevel", 15000);
|
||||
if (this.state.currentLevel !== level) {
|
||||
try {
|
||||
await this.env
|
||||
.get(DeviceFunctions)
|
||||
.waitForStateUpdate(this.endpoint.id, "levelControl", "currentLevel", 15000);
|
||||
} catch {
|
||||
logger.debug(`No currentLevel confirmation from openHAB for ${this.endpoint.id}, proceeding`);
|
||||
}
|
||||
}
|
||||
return super.moveToLevelLogic(level, transitionTime, withOnOff, options);
|
||||
}
|
||||
|
||||
+11
-4
@@ -1,7 +1,10 @@
|
||||
import { Logger } from "@matter/main";
|
||||
import { ModeSelect } from "@matter/main/clusters";
|
||||
import { ModeSelectServer } from "@matter/node/behaviors";
|
||||
import { DeviceFunctions } from "../DeviceFunctions";
|
||||
|
||||
const logger = Logger.get("CustomModeSelectServer");
|
||||
|
||||
export class CustomModeSelectServer extends ModeSelectServer {
|
||||
static readonly DEFAULTS = {
|
||||
modeSelect: {
|
||||
@@ -13,10 +16,14 @@ export class CustomModeSelectServer extends ModeSelectServer {
|
||||
this.env
|
||||
.get(DeviceFunctions)
|
||||
.sendAttributeChangedEvent(this.endpoint.id, "modeSelect", "currentMode", request.newMode);
|
||||
if (this.endpoint.stateOf(CustomModeSelectServer).currentMode !== request.newMode) {
|
||||
await this.env
|
||||
.get(DeviceFunctions)
|
||||
.waitForStateUpdate(this.endpoint.id, "modeSelect", "currentMode", 15000);
|
||||
if (this.state.currentMode !== request.newMode) {
|
||||
try {
|
||||
await this.env
|
||||
.get(DeviceFunctions)
|
||||
.waitForStateUpdate(this.endpoint.id, "modeSelect", "currentMode", 15000);
|
||||
} catch {
|
||||
logger.debug(`No currentMode confirmation from openHAB for ${this.endpoint.id}, proceeding`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+14
-7
@@ -1,6 +1,9 @@
|
||||
import { Logger } from "@matter/main";
|
||||
import { OnOffServer } from "@matter/main/behaviors";
|
||||
import { DeviceFunctions } from "../DeviceFunctions";
|
||||
|
||||
const logger = Logger.get("CustomOnOffServer");
|
||||
|
||||
/**
|
||||
* This class is used to send on/off events to the bridge.
|
||||
* The OnOff state will not be set until openHAB sends a state change event.
|
||||
@@ -10,7 +13,7 @@ export class CustomOnOffServer extends OnOffServer {
|
||||
|
||||
override async on() {
|
||||
// we only wait for ON/OFF if waiting for a different state
|
||||
if (this.endpoint.stateOf(CustomOnOffServer).onOff !== true) {
|
||||
if (this.state.onOff !== true) {
|
||||
await this.sendOnOffAndWait(true);
|
||||
} else {
|
||||
this.sendOnOff(true);
|
||||
@@ -18,7 +21,7 @@ export class CustomOnOffServer extends OnOffServer {
|
||||
return super.on();
|
||||
}
|
||||
override async off() {
|
||||
if (this.endpoint.stateOf(CustomOnOffServer).onOff !== false) {
|
||||
if (this.state.onOff !== false) {
|
||||
await this.sendOnOffAndWait(false);
|
||||
} else {
|
||||
this.sendOnOff(false);
|
||||
@@ -32,11 +35,15 @@ export class CustomOnOffServer extends OnOffServer {
|
||||
|
||||
protected async sendOnOffAndWait(onOff: boolean) {
|
||||
this.sendOnOff(onOff);
|
||||
const result = await this.env
|
||||
.get(DeviceFunctions)
|
||||
.waitForStateUpdate(this.endpoint.id, "onOff", "onOff", 15000);
|
||||
if (result !== onOff) {
|
||||
throw new Error("On/Off failed", { cause: result });
|
||||
try {
|
||||
const result = await this.env
|
||||
.get(DeviceFunctions)
|
||||
.waitForStateUpdate(this.endpoint.id, "onOff", "onOff", 5000);
|
||||
if (result !== onOff) {
|
||||
logger.debug(`onOff confirmation for ${this.endpoint.id} returned ${result}, expected ${onOff}`);
|
||||
}
|
||||
} catch {
|
||||
logger.debug(`No onOff confirmation from openHAB for ${this.endpoint.id}, proceeding`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+18
-20
@@ -94,32 +94,30 @@ public class DimmableLightDevice extends BaseDevice {
|
||||
public void updateState(Item item, State state) {
|
||||
List<AttributeState> states = new ArrayList<>();
|
||||
if (state instanceof HSBType hsb) {
|
||||
boolean on = hsb.getBrightness().intValue() > 0;
|
||||
lastLevel = ValueUtils.percentToLevel(hsb.getBrightness());
|
||||
lastOnOffState = lastLevel > 0 ? OnOffType.ON : OnOffType.OFF;
|
||||
states.add(new AttributeState(LevelControlCluster.CLUSTER_PREFIX,
|
||||
LevelControlCluster.ATTRIBUTE_CURRENT_LEVEL, lastLevel));
|
||||
states.add(new AttributeState(OnOffCluster.CLUSTER_PREFIX, OnOffCluster.ATTRIBUTE_ON_OFF,
|
||||
hsb.getBrightness().intValue() > 0));
|
||||
} else if (state instanceof PercentType percentType) {
|
||||
lastLevel = ValueUtils.percentToLevel(percentType);
|
||||
lastOnOffState = lastLevel > 0 ? OnOffType.ON : OnOffType.OFF;
|
||||
states.add(new AttributeState(OnOffCluster.CLUSTER_PREFIX, OnOffCluster.ATTRIBUTE_ON_OFF,
|
||||
percentType.intValue() > 0));
|
||||
if (percentType.intValue() > 0) {
|
||||
lastOnOffState = on ? OnOffType.ON : OnOffType.OFF;
|
||||
states.add(new AttributeState(OnOffCluster.CLUSTER_PREFIX, OnOffCluster.ATTRIBUTE_ON_OFF, on));
|
||||
if (on) {
|
||||
states.add(new AttributeState(LevelControlCluster.CLUSTER_PREFIX,
|
||||
LevelControlCluster.ATTRIBUTE_CURRENT_LEVEL, lastLevel));
|
||||
lastOnOffState = OnOffType.ON;
|
||||
} else {
|
||||
}
|
||||
} else if (state instanceof PercentType percentType) {
|
||||
boolean on = percentType.intValue() > 0;
|
||||
lastLevel = ValueUtils.percentToLevel(percentType);
|
||||
lastOnOffState = on ? OnOffType.ON : OnOffType.OFF;
|
||||
states.add(new AttributeState(OnOffCluster.CLUSTER_PREFIX, OnOffCluster.ATTRIBUTE_ON_OFF, on));
|
||||
if (on) {
|
||||
states.add(new AttributeState(LevelControlCluster.CLUSTER_PREFIX,
|
||||
LevelControlCluster.ATTRIBUTE_CURRENT_LEVEL, 0));
|
||||
lastOnOffState = OnOffType.OFF;
|
||||
LevelControlCluster.ATTRIBUTE_CURRENT_LEVEL, lastLevel));
|
||||
}
|
||||
} else if (state instanceof OnOffType onOffType) {
|
||||
states.add(new AttributeState(OnOffCluster.CLUSTER_PREFIX, OnOffCluster.ATTRIBUTE_ON_OFF,
|
||||
onOffType == OnOffType.ON));
|
||||
int level = onOffType == OnOffType.ON ? (lastLevel == 0 ? 1 : lastLevel) : 0;
|
||||
states.add(new AttributeState(LevelControlCluster.CLUSTER_PREFIX,
|
||||
LevelControlCluster.ATTRIBUTE_CURRENT_LEVEL, level));
|
||||
boolean on = onOffType == OnOffType.ON;
|
||||
states.add(new AttributeState(OnOffCluster.CLUSTER_PREFIX, OnOffCluster.ATTRIBUTE_ON_OFF, on));
|
||||
if (on) {
|
||||
states.add(new AttributeState(LevelControlCluster.CLUSTER_PREFIX,
|
||||
LevelControlCluster.ATTRIBUTE_CURRENT_LEVEL, lastLevel == 0 ? 1 : lastLevel));
|
||||
}
|
||||
lastOnOffState = onOffType;
|
||||
}
|
||||
if (!states.isEmpty()) {
|
||||
|
||||
-1
@@ -154,7 +154,6 @@ class DimmableLightDeviceTest {
|
||||
dimmerDevice.updateState(dimmerItem, PercentType.ZERO);
|
||||
expectedStates.clear();
|
||||
expectedStates.add(new AttributeState("onOff", "onOff", false));
|
||||
expectedStates.add(new AttributeState("levelControl", "currentLevel", 0));
|
||||
verify(client).setEndpointStates(any(), eq(expectedStates));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user