-
Notifications
You must be signed in to change notification settings - Fork 279
/
greenPower.ts
91 lines (74 loc) · 3.19 KB
/
greenPower.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
import {Adapter, Events as AdapterEvents} from '../adapter';
import * as Zcl from '../zcl';
import crypto from 'crypto';
import ZclTransactionSequenceNumber from './helpers/zclTransactionSequenceNumber';
import events from 'events';
import {GreenPowerEvents, GreenPowerDeviceJoinedPayload} from './tstype';
const zigBeeLinkKey = Buffer.from([
0x5A, 0x69, 0x67, 0x42, 0x65, 0x65, 0x41, 0x6C, 0x6C, 0x69, 0x61, 0x6E, 0x63, 0x65, 0x30, 0x39
]);
class GreenPower extends events.EventEmitter {
private adapter: Adapter;
public constructor(adapter: Adapter) {
super();
this.adapter = adapter;
}
private encryptSecurityKey(sourceID: number, securityKey: Buffer): Buffer {
const sourceIDInBytes = Buffer.from([
(sourceID & 0x000000ff),
(sourceID & 0x0000ff00) >> 8,
(sourceID & 0x00ff0000) >> 16,
(sourceID & 0xff000000) >> 24]
);
const nonce = Buffer.alloc(13);
for (let i = 0; i < 3; i++)
{
for (let j = 0; j < 4; j++)
{
nonce[4 * i + j] = sourceIDInBytes[j];
}
}
nonce[12] = 0x05;
const cipher = crypto.createCipheriv('aes-128-ccm', zigBeeLinkKey, nonce, {authTagLength: 16});
const encrypted = cipher.update(securityKey);
return Buffer.concat([encrypted, cipher.final()]);
}
public async onZclGreenPowerData(dataPayload: AdapterEvents.ZclDataPayload): Promise<void> {
if (dataPayload.frame.Payload.commandID === 224 && typeof dataPayload.address === 'number') {
const key = this.encryptSecurityKey(
dataPayload.frame.Payload.srcID, dataPayload.frame.Payload.commandFrame.securityKey
);
const payload = {
options: 0x00e548,
srcID: dataPayload.frame.Payload.srcID,
sinkGroupID: this.adapter.greenPowerGroup,
deviceID: dataPayload.frame.Payload.commandFrame.deviceID,
frameCounter: dataPayload.frame.Payload.commandFrame.outgoingCounter,
gpdKey: [...key],
};
const frame = Zcl.ZclFrame.create(
Zcl.FrameType.SPECIFIC, Zcl.Direction.SERVER_TO_CLIENT, true,
null, ZclTransactionSequenceNumber.next(), 'pairing', 33, payload
);
await this.adapter.sendZclFrameToAll(242, frame, 242);
const eventData: GreenPowerDeviceJoinedPayload = {
sourceID: dataPayload.frame.Payload.srcID,
deviceID: dataPayload.frame.Payload.commandFrame.deviceID,
networkAddress: dataPayload.address,
};
this.emit(GreenPowerEvents.deviceJoined, eventData);
}
}
public async permitJoin(time: number): Promise<void> {
const payload = {
options: 0x0b,
commisioningWindow: time,
};
const frame = Zcl.ZclFrame.create(
Zcl.FrameType.SPECIFIC, Zcl.Direction.SERVER_TO_CLIENT, true,
null, ZclTransactionSequenceNumber.next(), 'commisioningMode', 33, payload
);
await this.adapter.sendZclFrameToAll(242, frame, 242);
}
}
export default GreenPower;