Skip to content

Commit

Permalink
prelim zigate
Browse files Browse the repository at this point in the history
  • Loading branch information
Nerivec committed Dec 11, 2024
1 parent c694f17 commit 3d46e34
Showing 1 changed file with 73 additions and 64 deletions.
137 changes: 73 additions & 64 deletions src/adapter/zigate/adapter/zigateAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,47 +66,86 @@ class ZiGateAdapter extends Adapter {
* Adapter methods
*/
public async start(): Promise<TsType.StartResult> {
let startResult: TsType.StartResult = 'resumed';
try {
await this.driver.open();
logger.info('Connected to ZiGate adapter successfully.', NS);

const resetResponse = await this.driver.sendCommand(ZiGateCommandCode.Reset, {}, 5000);
if (resetResponse.code === ZiGateMessageCode.RestartNonFactoryNew) {
startResult = 'resumed';
} else if (resetResponse.code === ZiGateMessageCode.RestartFactoryNew) {
startResult = 'reset';
}
await this.driver.sendCommand(ZiGateCommandCode.RawMode, {enabled: 0x01});
// @todo check
await this.driver.sendCommand(ZiGateCommandCode.SetDeviceType, {
deviceType: DEVICE_TYPE.coordinator,
});
await this.initNetwork();

await this.driver.sendCommand(ZiGateCommandCode.AddGroup, {
addressMode: ADDRESS_MODE.short,
shortAddress: ZSpec.COORDINATOR_ADDRESS,
sourceEndpoint: ZSpec.HA_ENDPOINT,
destinationEndpoint: ZSpec.HA_ENDPOINT,
groupAddress: default_bind_group,
});
await this.driver.open();
logger.info('Connected to ZiGate adapter successfully.', NS);

if (this.adapterOptions.transmitPower != undefined) {
await this.driver.sendCommand(ZiGateCommandCode.SetTXpower, {value: this.adapterOptions.transmitPower});
}
} catch (error) {
throw new Error('failed to connect to zigate adapter ' + (error as Error).message);
// TODO: should always be called or only in `formNetwork`? this is not in doc API
await this.driver.sendCommand(ZiGateCommandCode.RawMode, {enabled: 0x01});

const result = await this.initNetwork();

await this.driver.sendCommand(ZiGateCommandCode.AddGroup, {
addressMode: ADDRESS_MODE.short,
shortAddress: ZSpec.COORDINATOR_ADDRESS,
sourceEndpoint: ZSpec.HA_ENDPOINT,
destinationEndpoint: ZSpec.HA_ENDPOINT,
groupAddress: default_bind_group,
});

if (this.adapterOptions.transmitPower != undefined) {
await this.driver.sendCommand(ZiGateCommandCode.SetTXpower, {value: this.adapterOptions.transmitPower});
}

return startResult; // 'resumed' | 'reset' | 'restored'
return result;
}

public async stop(): Promise<void> {
this.closing = true;
await this.driver.close();
}

protected async initHasNetwork(): Promise<[true, panID: number, extendedPanID: Buffer] | [false, panID: undefined, extendedPanID: undefined]> {
const resetResponse = await this.driver.sendCommand(ZiGateCommandCode.Reset, {}, 5000);

if (resetResponse.code === ZiGateMessageCode.RestartNonFactoryNew) {
const result = await this.driver.sendCommand(ZiGateCommandCode.GetNetworkState, {}, 10000);
const extPanId = result.payload.ExtPANID as number;
const extPanIdBuf = Buffer.from(extPanId.toString(16), 'hex');

return [true, result.payload.PANID as number, extPanIdBuf];
}

return [false, undefined, undefined];
}

public async leaveNetwork(): Promise<void> {
await this.driver.sendCommand(ZiGateCommandCode.ErasePersistentData, {}, 5000);
// will be ZiGateMessageCode.RestartFactoryNew when here
}

public async formNetwork(backup?: Models.Backup): Promise<void> {
if (backup) {
// this path should never be reached
throw new Error('This adapter does not support backup');
} else {
await this.driver.sendCommand(ZiGateCommandCode.SetDeviceType, {deviceType: DEVICE_TYPE.coordinator});
await this.driver.sendCommand(ZiGateCommandCode.SetChannelMask, {
channelMask: ZSpec.Utils.channelsToUInt32Mask(this.networkOptions.channelList),
});
await this.driver.sendCommand(ZiGateCommandCode.SetSecurityStateKey, {
keyType: this.networkOptions.networkKeyDistribute
? ZPSNwkKeyState.ZPS_ZDO_DISTRIBUTED_LINK_KEY
: ZPSNwkKeyState.ZPS_ZDO_PRECONFIGURED_LINK_KEY,
key: this.networkOptions.networkKey,
});
logger.debug(`Set EPanID ${this.networkOptions.extendedPanID.toString()}`, NS);
await this.driver.sendCommand(ZiGateCommandCode.SetExtendedPANID, {panId: this.networkOptions.extendedPanID});
await this.driver.sendCommand(ZiGateCommandCode.StartNetwork, {});
}
}

public async getNetworkKey(): Promise<Buffer> {
// TODO: doesn't look like zigate has any way to retrieve network key...
// force 'always assume matching'
return Buffer.from(this.networkOptions.networkKey);
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
public checkBackup(backup: Models.Backup): void {
// always fail if found a backup, since not supported, it can't be for zigate
throw new Error('This adapter does not support backup');
}

public async getCoordinatorIEEE(): Promise<string> {
const networkResponse = await this.driver.sendCommand(ZiGateCommandCode.GetNetworkState);
return networkResponse.payload.extendedAddress;
Expand Down Expand Up @@ -173,9 +212,9 @@ class ZiGateAdapter extends Adapter {
const result = await this.driver.sendCommand(ZiGateCommandCode.GetNetworkState, {}, 10000);

return {
panID: <number>result.payload.PANID,
extendedPanID: <number>result.payload.ExtPANID,
channel: <number>result.payload.Channel,
panID: result.payload.PANID as number,
extendedPanID: result.payload.ExtPANID as number,
channel: result.payload.Channel as number,
};
} catch (error) {
throw new Error(`Get network parameters failed ${error}`);
Expand Down Expand Up @@ -472,36 +511,6 @@ class ZiGateAdapter extends Adapter {
});
}

/**
* Supplementary functions
*/
private async initNetwork(): Promise<void> {
logger.debug(`Set channel mask ${this.networkOptions.channelList} key`, NS);
await this.driver.sendCommand(ZiGateCommandCode.SetChannelMask, {
channelMask: ZSpec.Utils.channelsToUInt32Mask(this.networkOptions.channelList),
});

logger.debug(`Set security key`, NS);
await this.driver.sendCommand(ZiGateCommandCode.SetSecurityStateKey, {
keyType: this.networkOptions.networkKeyDistribute
? ZPSNwkKeyState.ZPS_ZDO_DISTRIBUTED_LINK_KEY
: ZPSNwkKeyState.ZPS_ZDO_PRECONFIGURED_LINK_KEY,
key: this.networkOptions.networkKey,
});

try {
// The block is wrapped in trapping because if the network is already created, the firmware does not accept the new key.
logger.debug(`Set EPanID ${this.networkOptions.extendedPanID!.toString()}`, NS);
await this.driver.sendCommand(ZiGateCommandCode.SetExtendedPANID, {
panId: this.networkOptions.extendedPanID,
});

await this.driver.sendCommand(ZiGateCommandCode.StartNetwork, {});
} catch (error) {
logger.error((error as Error).stack!, NS);
}
}

public waitFor(
networkAddress: number | undefined,
endpoint: number,
Expand Down

0 comments on commit 3d46e34

Please sign in to comment.