Skip to content

Commit

Permalink
refactor: use custom homeAssistantBehavior for better state management
Browse files Browse the repository at this point in the history
  • Loading branch information
t0bst4r committed Nov 4, 2024
1 parent f88add6 commit 2dbc4e5
Show file tree
Hide file tree
Showing 46 changed files with 639 additions and 915 deletions.
4 changes: 2 additions & 2 deletions apps/home-assistant-matter-hub/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@
"pack": "mkdir -p pack && npm pack --pack-destination pack --json | jq -r .[0].filename > pack/package-name.txt"
},
"dependencies": {
"@project-chip/matter.js": "~0.10.6",
"@project-chip/matter-node.js": "~0.10.6",
"@project-chip/matter.js": "~0.11.2",
"@project-chip/matter-node.js": "~0.11.2",
"ajv": "^8.17.1",
"chalk": "^5.3.0",
"color": "^4.2.3",
Expand Down
101 changes: 86 additions & 15 deletions package-lock.json

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

4 changes: 2 additions & 2 deletions packages/backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
},
"dependencies": {
"@home-assistant-matter-hub/common": "*",
"@project-chip/matter.js": "~0.10.6",
"@project-chip/matter-node.js": "~0.10.6",
"@project-chip/matter.js": "~0.11.2",
"@project-chip/matter-node.js": "~0.11.2",
"ajv": "^8.17.1",
"chalk": "^5.3.0",
"express": "^4.21.1",
Expand Down
56 changes: 30 additions & 26 deletions packages/backend/src/matter/behaviors/basic-information-server.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,35 @@
import { BridgedDeviceBasicInformationServer as Base } from "@project-chip/matter.js/behavior/definitions/bridged-device-basic-information";
import {
BridgeBasicInformation,
HomeAssistantEntityState,
} from "@home-assistant-matter-hub/common";
import { Behavior } from "@project-chip/matter.js/behavior";
import { BridgedDeviceBasicInformationServer as Base } from "@project-chip/matter.js/behaviors/bridged-device-basic-information";
import crypto from "node:crypto";
import { HomeAssistantBehavior } from "../custom-behaviors/home-assistant-behavior.js";
import { VendorId } from "@project-chip/matter.js/datatype";

export class BasicInformationServer extends Base {}

export namespace BasicInformationServer {
export function createState(
basicInformation: BridgeBasicInformation,
state: HomeAssistantEntityState,
): Behavior.Options<typeof BasicInformationServer> {
return {
vendorId: basicInformation.vendorId,
vendorName: maxLengthOrHash(basicInformation.vendorName, 32),
productName: maxLengthOrHash(basicInformation.productName, 32),
productLabel: maxLengthOrHash(basicInformation.productLabel, 64),
hardwareVersion: basicInformation.hardwareVersion,
softwareVersion: basicInformation.softwareVersion,
nodeLabel: maxLengthOrHash(
state.attributes.friendly_name ?? "Unknown Entity",
32,
),
reachable: true,
};
export class BasicInformationServer extends Base {
override async initialize(): Promise<void> {
await super.initialize();
const homeAssistant = await this.agent.load(HomeAssistantBehavior);
const homeAssistantInfo = homeAssistant.state;
this.state.vendorId = VendorId(homeAssistantInfo.basicInformation.vendorId);
this.state.vendorName = maxLengthOrHash(
homeAssistantInfo.basicInformation.vendorName,
32,
);
this.state.productName = maxLengthOrHash(
homeAssistantInfo.basicInformation.productName,
32,
);
this.state.productLabel = maxLengthOrHash(
homeAssistantInfo.basicInformation.productLabel,
64,
);
this.state.hardwareVersion =
homeAssistantInfo.basicInformation.hardwareVersion;
this.state.softwareVersion =
homeAssistantInfo.basicInformation.softwareVersion;
this.state.nodeLabel = maxLengthOrHash(
homeAssistantInfo.entity.attributes.friendly_name ?? "Unknown Entity",
32,
);
this.state.reachable = true;
}
}

Expand Down
27 changes: 10 additions & 17 deletions packages/backend/src/matter/behaviors/boolean-state-server.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import { haMixin } from "../mixins/ha-mixin.js";
import { BooleanStateServer as Base } from "@project-chip/matter.js/behaviors/boolean-state";
import { HomeAssistantEntityState } from "@home-assistant-matter-hub/common";
import { Behavior } from "@project-chip/matter.js/behavior";
import { HomeAssistantBehavior } from "../custom-behaviors/home-assistant-behavior.js";

export function BooleanStateServer(inverted: boolean) {
return class Type extends haMixin("BooleanState", Base) {
override initialize(options?: {}) {
this.endpoint.entityState.subscribe(this.update.bind(this));
return super.initialize(options);
return class Type extends Base {
override async initialize() {
super.initialize();
const homeAssistant = await this.agent.load(HomeAssistantBehavior);
this.state.stateValue = getStateValue(
inverted,
homeAssistant.state.entity,
);
// TODO: subscribe to HA state changes
}

private async update(state: HomeAssistantEntityState) {
Expand All @@ -29,14 +33,3 @@ function getStateValue(
const isOn = state.state !== "off";
return inverted ? !isOn : isOn;
}

export namespace BooleanStateServer {
export function createState(
inverted: boolean,
state: HomeAssistantEntityState,
): Behavior.Options<typeof Base> {
return {
stateValue: getStateValue(inverted, state),
};
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { haMixin } from "../mixins/ha-mixin.js";
import {
ColorConverter,
HomeAssistantEntityState,
Expand All @@ -7,15 +6,37 @@ import {
} from "@home-assistant-matter-hub/common";
import { ColorControlServer as Base } from "@project-chip/matter.js/behaviors/color-control";
import { ColorControl } from "@project-chip/matter.js/cluster";
import { Behavior } from "@project-chip/matter.js/behavior";
import { HomeAssistantBehavior } from "../custom-behaviors/home-assistant-behavior.js";

export class ColorTemperatureControlServer extends haMixin(
"ColorControl",
Base.with("ColorTemperature"),
export class ColorTemperatureControlServer extends Base.with(
"ColorTemperature",
) {
override initialize() {
super.initialize();
this.endpoint.entityState.subscribe(this.update.bind(this));
override async initialize() {
await super.initialize();

const homeAssistant = await this.agent.load(HomeAssistantBehavior);
const state = homeAssistant.state
.entity as HomeAssistantEntityState<LightDeviceAttributes>;
const minKelvin = state.attributes.min_color_temp_kelvin ?? 1500;

const maxKelvin = state.attributes.max_color_temp_kelvin ?? 8000;
this.state.coupleColorTempToLevelMinMireds =
ColorConverter.temperatureKelvinToMireds(maxKelvin);
this.state.colorTempPhysicalMinMireds =
ColorConverter.temperatureKelvinToMireds(maxKelvin);
this.state.colorTempPhysicalMaxMireds =
ColorConverter.temperatureKelvinToMireds(minKelvin);
this.state.startUpColorTemperatureMireds =
ColorConverter.temperatureKelvinToMireds(
state.attributes.color_temp_kelvin ?? maxKelvin,
);
if (state.attributes.color_temp_kelvin) {
this.state.colorTemperatureMireds =
ColorConverter.temperatureKelvinToMireds(
state.attributes.color_temp_kelvin,
);
}
// TODO: subscribe to HA state changes
}

protected async update(
Expand All @@ -41,47 +62,23 @@ export class ColorTemperatureControlServer extends haMixin(
override async moveToColorTemperature(
request: ColorControl.MoveToColorTemperatureRequest,
) {
const homeAssistant = this.agent.get(HomeAssistantBehavior);
const targetKelvin = ColorConverter.temperatureMiredsToKelvin(
request.colorTemperatureMireds,
);
await super.moveToColorTemperature({
...request,
transitionTime: request.transitionTime ?? 1,
});
await this.callAction(
await homeAssistant.callAction(
"light",
"turn_on",
{
color_temp_kelvin: targetKelvin,
},
{
entity_id: this.entity.entity_id,
entity_id: homeAssistant.state.entity.entity_id,
},
);
}
}

export namespace ColorTemperatureControlServer {
export function createState(
state: HomeAssistantEntityState<LightDeviceAttributes>,
): Behavior.Options<typeof ColorTemperatureControlServer> {
const minKelvin = state.attributes.min_color_temp_kelvin ?? 1500;
const maxKelvin = state.attributes.max_color_temp_kelvin ?? 8000;
return {
coupleColorTempToLevelMinMireds:
ColorConverter.temperatureKelvinToMireds(maxKelvin),
colorTempPhysicalMinMireds:
ColorConverter.temperatureKelvinToMireds(maxKelvin),
colorTempPhysicalMaxMireds:
ColorConverter.temperatureKelvinToMireds(minKelvin),
startUpColorTemperatureMireds: ColorConverter.temperatureKelvinToMireds(
state.attributes.color_temp_kelvin ?? maxKelvin,
),
colorTemperatureMireds: state.attributes.color_temp_kelvin
? ColorConverter.temperatureKelvinToMireds(
state.attributes.color_temp_kelvin,
)
: undefined,
};
}
}
Loading

0 comments on commit 2dbc4e5

Please sign in to comment.