diff --git a/src/adapter/zigate/adapter/zigateAdapter.ts b/src/adapter/zigate/adapter/zigateAdapter.ts index dc4a43de32..e412d0f543 100644 --- a/src/adapter/zigate/adapter/zigateAdapter.ts +++ b/src/adapter/zigate/adapter/zigateAdapter.ts @@ -66,40 +66,27 @@ class ZiGateAdapter extends Adapter { * Adapter methods */ public async start(): Promise { - 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 { @@ -107,6 +94,58 @@ class ZiGateAdapter extends Adapter { 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 { + await this.driver.sendCommand(ZiGateCommandCode.ErasePersistentData, {}, 5000); + // will be ZiGateMessageCode.RestartFactoryNew when here + } + + public async formNetwork(backup?: Models.Backup): Promise { + 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 { + // 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 { const networkResponse = await this.driver.sendCommand(ZiGateCommandCode.GetNetworkState); return networkResponse.payload.extendedAddress; @@ -173,9 +212,9 @@ class ZiGateAdapter extends Adapter { const result = await this.driver.sendCommand(ZiGateCommandCode.GetNetworkState, {}, 10000); return { - panID: result.payload.PANID, - extendedPanID: result.payload.ExtPANID, - channel: 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}`); @@ -472,36 +511,6 @@ class ZiGateAdapter extends Adapter { }); } - /** - * Supplementary functions - */ - private async initNetwork(): Promise { - 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,