From 84b302929eca4353f6b7be55f85ed191e9fd4159 Mon Sep 17 00:00:00 2001 From: Koen Kanters Date: Thu, 5 Sep 2024 13:06:16 +0200 Subject: [PATCH 1/2] fix: Fix Deconz Green power implementation https://github.com/Koenkk/zigbee2mqtt/issues/23814 --- package.json | 2 +- src/adapter/deconz/adapter/deconzAdapter.ts | 50 +++++++++------------ src/adapter/deconz/driver/constants.ts | 2 +- src/adapter/deconz/driver/frameParser.ts | 4 +- 4 files changed, 25 insertions(+), 33 deletions(-) diff --git a/package.json b/package.json index 6f970ed561..942b32e01c 100644 --- a/package.json +++ b/package.json @@ -81,7 +81,7 @@ }, "scripts": { "build": "tsc", - "start": "tsc -w", + "build:watch": "tsc -w", "test": "jest test --silent --maxWorkers=50%", "test-with-coverage": "jest test --silent --maxWorkers=50% --coverage", "test-watch": "jest test --silent --maxWorkers=25% --watch", diff --git a/src/adapter/deconz/adapter/deconzAdapter.ts b/src/adapter/deconz/adapter/deconzAdapter.ts index 07f8814c8b..1ec3d276de 100644 --- a/src/adapter/deconz/adapter/deconzAdapter.ts +++ b/src/adapter/deconz/adapter/deconzAdapter.ts @@ -2,6 +2,7 @@ import assert from 'assert'; +import {ZSpec} from '../../..'; import Device from '../../../controller/model/device'; import * as Models from '../../../models'; import {Queue, Waitress} from '../../../utils'; @@ -1229,38 +1230,29 @@ class DeconzAdapter extends Adapter { } private checkReceivedGreenPowerIndication(ind: gpDataInd): void { - ind.clusterId = 0x21; - - const gpFrame = [ - ind.rspId!, - ind.seqNr!, - ind.id!, - 0, - 0, // 0, 0 for options is a temp fix until https://github.com/Koenkk/zigbee-herdsman/pull/536 is merged. - // ind.options & 0xff, (ind.options >> 8) & 0xff, - ind.srcId! & 0xff, - (ind.srcId! >> 8) & 0xff, - (ind.srcId! >> 16) & 0xff, - (ind.srcId! >> 24) & 0xff, - ind.frameCounter! & 0xff, - (ind.frameCounter! >> 8) & 0xff, - (ind.frameCounter! >> 16) & 0xff, - (ind.frameCounter! >> 24) & 0xff, - ind.commandId!, - ind.commandFrameSize!, - ].concat(ind.commandFrame!); - - const payBuf = Buffer.from(gpFrame); + const gpdHeader = Buffer.alloc(15); // applicationId === IEEE_ADDRESS ? 20 : 15 + gpdHeader.writeUInt8(0b00000001, 0); // frameControl: FrameType.SPECIFIC + Direction.CLIENT_TO_SERVER + disableDefaultResponse=false + gpdHeader.writeUInt8(ind.seqNr!, 1); + gpdHeader.writeUInt8(ind.id!, 2); // commandIdentifier + gpdHeader.writeUInt16LE(0, 3); // options, only srcID present + gpdHeader.writeUInt32LE(ind.srcId!, 5); + // omitted: gpdIEEEAddr (ieeeAddr) + // omitted: gpdEndpoint (uint8) + gpdHeader.writeUInt32LE(ind.frameCounter!, 9); + gpdHeader.writeUInt8(ind.commandId!, 13); + gpdHeader.writeUInt8(ind.commandFrameSize!, 14); + + const payBuf = Buffer.concat([gpdHeader, ind.commandFrame!]); const payload: Events.ZclPayload = { header: Zcl.Header.fromBuffer(payBuf), data: payBuf, - clusterID: ind.clusterId, - address: ind.srcId!, - endpoint: 242, // GP endpoint - linkquality: 127, - groupID: 0x0b84, - wasBroadcast: false, - destinationEndpoint: 1, + clusterID: Zcl.Clusters.greenPower.ID, + address: ind.srcId! & 0xffff, + endpoint: ZSpec.GP_ENDPOINT, + linkquality: 0xff, // bogus + groupID: ZSpec.GP_GROUP_ID, + wasBroadcast: true, // Take the codepath that doesn't require `gppNwkAddr` as its not present in the payload + destinationEndpoint: ZSpec.GP_ENDPOINT, }; this.waitress.resolve(payload); diff --git a/src/adapter/deconz/driver/constants.ts b/src/adapter/deconz/driver/constants.ts index af90f2edad..796babffdf 100644 --- a/src/adapter/deconz/driver/constants.ts +++ b/src/adapter/deconz/driver/constants.ts @@ -111,7 +111,7 @@ interface gpDataInd { frameCounter?: number; commandId?: number; commandFrameSize?: number; - commandFrame?: number[]; + commandFrame?: Buffer; } interface DataStateResponse { diff --git a/src/adapter/deconz/driver/frameParser.ts b/src/adapter/deconz/driver/frameParser.ts index 44eef27fe6..d6372fb3c8 100644 --- a/src/adapter/deconz/driver/frameParser.ts +++ b/src/adapter/deconz/driver/frameParser.ts @@ -382,7 +382,7 @@ function parseGreenPowerDataIndication(view: DataView): object | null { ind.commandId = view.getUint8(17); ind.commandFrameSize = view.byteLength - 18 - 6; // cut 18 from begin and 4 (sec mic) and 2 from end (cfc) - const payload = []; + const payload = Buffer.alloc(ind.commandFrameSize); let i = 0; for (let u = 18; u < ind.commandFrameSize + 18; u++) { payload[i] = view.getUint8(u); @@ -399,7 +399,7 @@ function parseGreenPowerDataIndication(view: DataView): object | null { ind.commandId = view.getUint8(12); ind.commandFrameSize = view.byteLength - 13 - 2; // cut 13 from begin and 2 from end (cfc) - const payload = []; + const payload = Buffer.alloc(ind.commandFrameSize); let i = 0; for (let u = 13; u < ind.commandFrameSize + 13; u++) { payload[i] = view.getUint8(u); From e4b9f5648fce3b4fc56f4070c1374a8b67f95e11 Mon Sep 17 00:00:00 2001 From: Koen Kanters Date: Fri, 6 Sep 2024 14:05:13 +0200 Subject: [PATCH 2/2] process feedback --- src/adapter/deconz/driver/frameParser.ts | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/src/adapter/deconz/driver/frameParser.ts b/src/adapter/deconz/driver/frameParser.ts index d6372fb3c8..1d275ea2d7 100644 --- a/src/adapter/deconz/driver/frameParser.ts +++ b/src/adapter/deconz/driver/frameParser.ts @@ -381,14 +381,7 @@ function parseGreenPowerDataIndication(view: DataView): object | null { ind.frameCounter = view.getUint32(13, littleEndian); ind.commandId = view.getUint8(17); ind.commandFrameSize = view.byteLength - 18 - 6; // cut 18 from begin and 4 (sec mic) and 2 from end (cfc) - - const payload = Buffer.alloc(ind.commandFrameSize); - let i = 0; - for (let u = 18; u < ind.commandFrameSize + 18; u++) { - payload[i] = view.getUint8(u); - i++; - } - ind.commandFrame = payload; + ind.commandFrame = Buffer.from(view.buffer.slice(18, ind.commandFrameSize + 18)); } else { logger.debug('GP commissioning notification', NS); ind.id = 0x04; // 0 = notification, 4 = commissioning @@ -398,14 +391,7 @@ function parseGreenPowerDataIndication(view: DataView): object | null { ind.frameCounter = view.getUint32(36, littleEndian); ind.commandId = view.getUint8(12); ind.commandFrameSize = view.byteLength - 13 - 2; // cut 13 from begin and 2 from end (cfc) - - const payload = Buffer.alloc(ind.commandFrameSize); - let i = 0; - for (let u = 13; u < ind.commandFrameSize + 13; u++) { - payload[i] = view.getUint8(u); - i++; - } - ind.commandFrame = payload; + ind.commandFrame = Buffer.from(view.buffer.slice(13, ind.commandFrameSize + 13)); } if (