Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions src/controller/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1091,11 +1091,9 @@ export class Controller extends events.EventEmitter<ControllerEventMap> {

endpoint.saveClusterAttributeKeyValue(frame.cluster.ID, data);
}
} else {
if (frame.header.isSpecific) {
type = `command${command.name.charAt(0).toUpperCase()}${command.name.slice(1)}`;
data = frame.payload;
}
} else if (frame.header.isSpecific) {
type = `command${command.name.charAt(0).toUpperCase()}${command.name.slice(1)}`;
data = frame.payload;
}
} else {
type = "raw";
Expand Down
112 changes: 110 additions & 2 deletions src/controller/helpers/zclFrameConverter.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import {logger} from "../../utils/logger";
import * as Zcl from "../../zspec/zcl";
import type {TFoundation} from "../../zspec/zcl/definition/clusters-types";
import type {Cluster, CustomClusters} from "../../zspec/zcl/definition/tstype";
import type {Cluster, CustomClusters, ExtensionFieldSet} from "../../zspec/zcl/definition/tstype";
import type {Scene} from "../model/endpoint";
import type {ClusterOrRawWriteAttributes, TCustomCluster} from "../tstype";

const NS = "zh:controller:zcl";
Expand Down Expand Up @@ -61,4 +62,111 @@ function attributeList(frame: Zcl.Frame, deviceManufacturerID: number | undefine
return payload;
}

export {attributeKeyValue, attributeList};
// to/from: first in list is always expected, after can be omitted but has to remain sequentially valid, hence stop on first undefined
// we expect that if a cluster is present, at least one value should be too (though use fallback just in case)
// XXX: use non-value instead of `0` for fallback? (edge-case)
function sceneFromExtensionFieldSets(extFieldSets: ExtensionFieldSet[]): Scene["state"] {
const sceneState: Scene["state"] = {};

for (const set of extFieldSets) {
const clusterId = set.clstId;

switch (clusterId) {
case Zcl.Clusters.genOnOff.ID: {
sceneState.genOnOff = {onOff: (set.extField[0] as number | undefined) ?? 0};

break;
}

case Zcl.Clusters.genLevelCtrl.ID: {
sceneState.genLevelCtrl = {currentLevel: (set.extField[0] as number | undefined) ?? 0};

break;
}

case Zcl.Clusters.closuresWindowCovering.ID: {
const state: Scene["state"]["closuresWindowCovering"] = {currentPositionLiftPercentage: (set.extField[0] as number | undefined) ?? 0};
const currentPositionTiltPercentage = set.extField[1] as number | undefined;

if (currentPositionTiltPercentage !== undefined) {
state.currentPositionTiltPercentage = currentPositionTiltPercentage;
}

sceneState.closuresWindowCovering = state;

break;
}

case Zcl.Clusters.barrierControl.ID: {
sceneState.barrierControl = {barrierPosition: (set.extField[0] as number | undefined) ?? 0};

break;
}

case Zcl.Clusters.hvacThermostat.ID: {
const state: Scene["state"]["hvacThermostat"] = {occupiedCoolingSetpoint: (set.extField[0] as number | undefined) ?? 0};
const occupiedHeatingSetpoint = set.extField[1] as number | undefined;

if (occupiedHeatingSetpoint !== undefined) {
state.occupiedHeatingSetpoint = occupiedHeatingSetpoint;
const systemMode = set.extField[2] as number | undefined;

if (systemMode !== undefined) {
state.systemMode = systemMode;
}
}

sceneState.hvacThermostat = state;

break;
}

case Zcl.Clusters.lightingColorCtrl.ID: {
const state: Scene["state"]["lightingColorCtrl"] = {currentX: (set.extField[0] as number | undefined) ?? 0};
const currentY = set.extField[1] as number | undefined;

if (currentY !== undefined) {
state.currentY = currentY;
const enhancedCurrentHue = set.extField[2] as number | undefined;

if (enhancedCurrentHue !== undefined) {
state.enhancedCurrentHue = enhancedCurrentHue;
const currentSaturation = set.extField[3] as number | undefined;

if (currentSaturation !== undefined) {
state.currentSaturation = currentSaturation;
const colorLoopActive = set.extField[4] as number | undefined;

if (colorLoopActive !== undefined) {
state.colorLoopActive = colorLoopActive;
const colorLoopDirection = set.extField[5] as number | undefined;

if (colorLoopDirection !== undefined) {
state.colorLoopDirection = colorLoopDirection;
const colorLoopTime = set.extField[6] as number | undefined;

if (colorLoopTime !== undefined) {
state.colorLoopTime = colorLoopTime;
const colorTemperature = set.extField[7] as number | undefined;

if (colorTemperature !== undefined) {
state.colorTemperature = colorTemperature;
}
}
}
}
}
}
}

sceneState.lightingColorCtrl = state;

break;
}
}
}

return sceneState;
}

export {attributeKeyValue, attributeList, sceneFromExtensionFieldSets};
Loading
Loading