Skip to content

Commit

Permalink
fix: EZSP adapter fixes (#921)
Browse files Browse the repository at this point in the history
  • Loading branch information
Nerivec committed Feb 19, 2024
1 parent 548dd42 commit 6bb05c7
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 50 deletions.
58 changes: 33 additions & 25 deletions src/adapter/ezsp/adapter/ezspAdapter.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
/* istanbul ignore file */
/* eslint-disable */
import {
NetworkOptions, SerialPortOptions, Coordinator, CoordinatorVersion, NodeDescriptor,
DeviceType, ActiveEndpoints, SimpleDescriptor, LQI, RoutingTable, Backup as BackupType, NetworkParameters,
ActiveEndpoints, SimpleDescriptor, LQI, RoutingTable, NetworkParameters,
StartResult, LQINeighbor, RoutingTableEntry, AdapterOptions
} from '../../tstype';
import Debug from "debug";
import Adapter from '../../adapter';

const debug = Debug("zigbee-herdsman:adapter:ezsp:debg");
import {Driver, EmberIncomingMessage} from '../driver';
import {EmberZDOCmd, EmberApsOption, uint16_t, EmberEUI64, EmberStatus, EmberKeyData} from '../driver/types';
import {EmberZDOCmd, uint16_t, EmberEUI64, EmberStatus} from '../driver/types';
import {ZclFrame, FrameType, Direction, Foundation} from '../../../zcl';
import * as Events from '../../events';
import {Queue, Waitress, Wait, RealpathSync} from '../../../utils';
import * as Models from "../../../models";
import SerialPortUtils from '../../serialPortUtils';
import SocketPortUtils from '../../socketPortUtils';
import {EZSPAdapterBackup} from './backup';
import {EZSPZDOResponseFrameData} from '../driver/ezsp';


const autoDetectDefinitions = [
{ manufacturer: 'ITEAD', vendorId: '1a86', productId: '55d4' }, // Sonoff ZBDongle-E
{ manufacturer: 'Nabu Casa', vendorId: '10c4', productId: 'ea60' }, // Home Assistant SkyConnect
{manufacturer: 'ITEAD', vendorId: '1a86', productId: '55d4'}, // Sonoff ZBDongle-E
{manufacturer: 'Nabu Casa', vendorId: '10c4', productId: 'ea60'}, // Home Assistant SkyConnect
];


Expand All @@ -44,7 +44,7 @@ class EZSPAdapter extends Adapter {


public constructor(networkOptions: NetworkOptions,
serialPortOptions: SerialPortOptions, backupPath: string, adapterOptions: AdapterOptions) {
serialPortOptions: SerialPortOptions, backupPath: string, adapterOptions: AdapterOptions) {
super(networkOptions, serialPortOptions, backupPath, adapterOptions);

this.waitress = new Waitress<Events.ZclDataPayload, WaitressMatcher>(
Expand All @@ -65,13 +65,14 @@ class EZSPAdapter extends Adapter {
this.backupMan = new EZSPAdapterBackup(this.driver, backupPath);
}

private async processMessage(frame: EmberIncomingMessage) {
private async processMessage(frame: EmberIncomingMessage): Promise<void> {
debug(`processMessage: ${JSON.stringify(frame)}`);
if (frame.apsFrame.profileId == 0) {
if (
frame.apsFrame.clusterId == EmberZDOCmd.Device_annce &&
frame.apsFrame.destinationEndpoint == 0) {
let nwk, rst, ieee;
// eslint-disable-next-line prefer-const
[nwk, rst] = uint16_t.deserialize(uint16_t, frame.message.subarray(1));
[ieee, rst] = EmberEUI64.deserialize(EmberEUI64, rst as Buffer);
ieee = new EmberEUI64(ieee);
Expand Down Expand Up @@ -148,23 +149,25 @@ class EZSPAdapter extends Adapter {
this.emit('event', frame);
}

private async handleDeviceJoin(arr: any[]) {
let [nwk, ieee] = arr;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private async handleDeviceJoin(arr: any[]): Promise<void> {
const [nwk, ieee] = arr;
debug('Device join request received: %s %s', nwk, ieee.toString('hex'));
const payload: Events.DeviceJoinedPayload = {
networkAddress: nwk,
ieeeAddr: `0x${ieee.toString('hex')}`,
};

if (nwk == 0) {
const nd = await this.nodeDescriptor(nwk);
await this.nodeDescriptor(nwk);
} else {
this.emit(Events.Events.deviceJoined, payload);
}
}

private handleDeviceLeft(arr: any[]) {
let [nwk, ieee] = arr;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private handleDeviceLeft(arr: any[]): void {
const [nwk, ieee] = arr;
debug('Device left network request received: %s %s', nwk, ieee);

const payload: Events.DeviceLeavePayload = {
Expand Down Expand Up @@ -252,9 +255,9 @@ class EZSPAdapter extends Adapter {
if (this.driver.ezsp.isInitialized()) {
return this.queue.execute<void>(async () => {
this.checkInterpanLock();
if (seconds) {
this.driver.preJoining();
}

await this.driver.preJoining(seconds);

if (networkAddress) {
const result = await this.driver.zdoRequest(
networkAddress, EmberZDOCmd.Mgmt_Permit_Joining_req,
Expand Down Expand Up @@ -282,6 +285,7 @@ class EZSPAdapter extends Adapter {
await this.driver.addInstallCode(ieeeAddress, key);
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
public async reset(type: 'soft' | 'hard'): Promise<void> {
return Promise.reject(new Error("Not supported"));
}
Expand All @@ -291,7 +295,7 @@ class EZSPAdapter extends Adapter {
this.checkInterpanLock();
const neighbors: LQINeighbor[] = [];

const request = async (startIndex: number): Promise<any> => {
const request = async (startIndex: number): Promise<EZSPZDOResponseFrameData> => {
const result = await this.driver.zdoRequest(
networkAddress, EmberZDOCmd.Mgmt_Lqi_req, EmberZDOCmd.Mgmt_Lqi_rsp,
{startindex: startIndex}
Expand Down Expand Up @@ -337,7 +341,7 @@ class EZSPAdapter extends Adapter {
this.checkInterpanLock();
const table: RoutingTableEntry[] = [];

const request = async (startIndex: number): Promise<any> => {
const request = async (startIndex: number): Promise<EZSPZDOResponseFrameData> => {
const result = await this.driver.zdoRequest(
networkAddress, EmberZDOCmd.Mgmt_Rtg_req, EmberZDOCmd.Mgmt_Rtg_rsp,
{startindex: startIndex}
Expand Down Expand Up @@ -512,7 +516,8 @@ class EZSPAdapter extends Adapter {
frame.sourceEndpoint = 0x01;
frame.destinationEndpoint = 0x01;
frame.groupId = groupID;
const dataConfirmResult = await this.driver.mrequest(frame, zclFrame.toBuffer());

await this.driver.mrequest(frame, zclFrame.toBuffer());
/**
* As a group command is not confirmed and thus immidiately returns
* (contrary to network address requests) we will give the
Expand All @@ -530,7 +535,8 @@ class EZSPAdapter extends Adapter {
frame.sourceEndpoint = sourceEndpoint;
frame.destinationEndpoint = endpoint;
frame.groupId = 0xFFFD;
const dataConfirmResult = await this.driver.mrequest(frame, zclFrame.toBuffer());

await this.driver.mrequest(frame, zclFrame.toBuffer());

/**
* As a broadcast command is not confirmed and thus immidiately returns
Expand All @@ -555,14 +561,14 @@ class EZSPAdapter extends Adapter {
destAddr = {
addrmode: 0x01,
nwk: destinationAddressOrGroup,
}
};
} else {
// 0x03 = 64-bit extended address for DstAddr and DstEndpoint present
destAddr = {
addrmode: 0x03,
ieee: new EmberEUI64(destinationAddressOrGroup as string),
endpoint: destinationEndpoint,
}
};
this.driver.setNode(destinationNetworkAddress, destAddr.ieee);
}
await this.driver.zdoRequest(
Expand All @@ -586,14 +592,14 @@ class EZSPAdapter extends Adapter {
destAddr = {
addrmode: 0x01,
nwk: destinationAddressOrGroup,
}
};
} else {
// 0x03 = 64-bit extended address for DstAddr and DstEndpoint present
destAddr = {
addrmode: 0x03,
ieee: new EmberEUI64(destinationAddressOrGroup as string),
endpoint: destinationEndpoint,
}
};
this.driver.setNode(destinationNetworkAddress, destAddr.ieee);
}
await this.driver.zdoRequest(
Expand Down Expand Up @@ -663,7 +669,8 @@ class EZSPAdapter extends Adapter {
frame.appFrameControl = 0x03;
frame.clusterId = zclFrame.Cluster.ID;
frame.profileId = 0xc05e;
const dataConfirmResult = await this.driver.ieeerawrequest(frame, zclFrame.toBuffer());

await this.driver.ieeerawrequest(frame, zclFrame.toBuffer());
} catch (error) {
throw error;
}
Expand Down Expand Up @@ -693,7 +700,8 @@ class EZSPAdapter extends Adapter {
frame.appFrameControl = 0x0b;
frame.clusterId = zclFrame.Cluster.ID;
frame.profileId = 0xc05e;
const dataConfirmResult = await this.driver.rawrequest(frame, zclFrame.toBuffer());

await this.driver.rawrequest(frame, zclFrame.toBuffer());
} catch (error) {
response.cancel();
throw error;
Expand Down
41 changes: 16 additions & 25 deletions src/adapter/ezsp/driver/driver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -330,10 +330,6 @@ export class Driver extends EventEmitter {
if (frame.status === EmberDeviceUpdate.DEVICE_LEFT) {
this.handleNodeLeft(frame.newNodeId, frame.newNodeEui64);
} else {
if (frame.status === EmberDeviceUpdate.STANDARD_SECURITY_UNSECURED_JOIN) {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.cleanupTClinkKey(frame.newNodeEui64);
}
if (frame.policyDecision !== EmberJoinDecision.DENY_JOIN) {
this.handleNodeJoined(frame.newNodeId, frame.newNodeEui64);
}
Expand Down Expand Up @@ -419,15 +415,6 @@ export class Driver extends EventEmitter {
}
}

private async cleanupTClinkKey(ieee: EmberEUI64): Promise<void> {
// Remove tc link_key for the given device.
const index = (await this.ezsp.execCommand('findKeyTableEntry', {address: ieee, linkKey: true})).index;

if (index != 0xFF) {
await this.ezsp.execCommand('eraseKeyTableEntry', {index: index});
}
}

private handleRouteRecord(nwk: number, ieee: EmberEUI64 | number[], lqi: number, rssi: number,
relays: number): void {
// todo
Expand Down Expand Up @@ -703,20 +690,24 @@ export class Driver extends EventEmitter {
}
}

public async preJoining(): Promise<void> {
const ieee = new EmberEUI64('0xFFFFFFFFFFFFFFFF');
const linkKey = new EmberKeyData();
linkKey.contents = Buffer.from("ZigBeeAlliance09");
const result = await this.addTransientLinkKey(ieee, linkKey);
public async preJoining(seconds: number): Promise<void> {
if (seconds) {
const ieee = new EmberEUI64('0xFFFFFFFFFFFFFFFF');
const linkKey = new EmberKeyData();
linkKey.contents = Buffer.from("ZigBeeAlliance09");
const result = await this.addTransientLinkKey(ieee, linkKey);

if (result.status !== EmberStatus.SUCCESS) {
throw new Error(`Add Transient Link Key for '${ieee}' failed`);
}
if (result.status !== EmberStatus.SUCCESS) {
throw new Error(`Add Transient Link Key for '${ieee}' failed`);
}

if (this.ezsp.ezspV >= 8) {
await this.ezsp.setPolicy(EzspPolicyId.TRUST_CENTER_POLICY,
EzspDecisionBitmask.ALLOW_UNSECURED_REJOINS | EzspDecisionBitmask.ALLOW_JOINS);
//| EzspDecisionBitmask.JOINS_USE_INSTALL_CODE_KEY
if (this.ezsp.ezspV >= 8) {
await this.ezsp.setPolicy(EzspPolicyId.TRUST_CENTER_POLICY,
EzspDecisionBitmask.ALLOW_UNSECURED_REJOINS | EzspDecisionBitmask.ALLOW_JOINS);
//| EzspDecisionBitmask.JOINS_USE_INSTALL_CODE_KEY
}
} else {
await this.ezsp.execCommand('clearTransientLinkKeys');
}
}

Expand Down

0 comments on commit 6bb05c7

Please sign in to comment.