diff --git a/src/adapter/adapter.ts b/src/adapter/adapter.ts index 5759f2718a..dbb6bb6492 100644 --- a/src/adapter/adapter.ts +++ b/src/adapter/adapter.ts @@ -167,8 +167,6 @@ abstract class Adapter extends events.EventEmitter { public abstract getNetworkParameters(): Promise; - public abstract supportsChangeChannel(): Promise; - public abstract changeChannel(newChannel: number): Promise; public abstract setTransmitPower(value: number): Promise; diff --git a/src/adapter/deconz/adapter/deconzAdapter.ts b/src/adapter/deconz/adapter/deconzAdapter.ts index 75c643e013..d593a6d101 100644 --- a/src/adapter/deconz/adapter/deconzAdapter.ts +++ b/src/adapter/deconz/adapter/deconzAdapter.ts @@ -1174,12 +1174,8 @@ class DeconzAdapter extends Adapter { throw new Error('not supported'); } - public async supportsChangeChannel(): Promise { - return false; - } - public async changeChannel(newChannel: number): Promise { - throw new Error('not supported'); + throw new Error(`Channel change is not supported for 'deconz'`); } public async setTransmitPower(value: number): Promise { diff --git a/src/adapter/ember/adapter/emberAdapter.ts b/src/adapter/ember/adapter/emberAdapter.ts index 62fd0be85f..523ec2e1af 100644 --- a/src/adapter/ember/adapter/emberAdapter.ts +++ b/src/adapter/ember/adapter/emberAdapter.ts @@ -2039,10 +2039,6 @@ export class EmberAdapter extends Adapter { }); } - public async supportsChangeChannel(): Promise { - return true; - } - // queued public async changeChannel(newChannel: number): Promise { return this.queue.execute(async () => { diff --git a/src/adapter/ezsp/adapter/ezspAdapter.ts b/src/adapter/ezsp/adapter/ezspAdapter.ts index a9e2340bf5..b41ec8d5b0 100644 --- a/src/adapter/ezsp/adapter/ezspAdapter.ts +++ b/src/adapter/ezsp/adapter/ezspAdapter.ts @@ -765,13 +765,9 @@ class EZSPAdapter extends Adapter { }); } - public async supportsChangeChannel(): Promise { - return false; - } - // eslint-disable-next-line @typescript-eslint/no-unused-vars public async changeChannel(newChannel: number): Promise { - return Promise.reject(new Error('Not supported')); + throw new Error(`Channel change is not supported for 'ezsp'`); } public async setTransmitPower(value: number): Promise { diff --git a/src/adapter/z-stack/adapter/manager.ts b/src/adapter/z-stack/adapter/manager.ts index f113b62625..3803b218a5 100644 --- a/src/adapter/z-stack/adapter/manager.ts +++ b/src/adapter/z-stack/adapter/manager.ts @@ -135,7 +135,8 @@ export class ZnpAdapterManager { /* istanbul ignore next */ const configMatchesAdapter = nib && - Utils.compareChannelLists(this.nwkOptions.channelList, nib.channelList) && // TODO: remove? + // Don't check for channel anymore because channel change is supported. + // Utils.compareChannelLists(this.nwkOptions.channelList, nib.channelList) && this.nwkOptions.panId === nib.nwkPanId && (this.nwkOptions.extendedPanId.equals(nib.extendedPANID) || /* exception for migration from previous code-base */ diff --git a/src/adapter/z-stack/adapter/zStackAdapter.ts b/src/adapter/z-stack/adapter/zStackAdapter.ts index a93d4d9cfc..64e272c757 100644 --- a/src/adapter/z-stack/adapter/zStackAdapter.ts +++ b/src/adapter/z-stack/adapter/zStackAdapter.ts @@ -1070,10 +1070,6 @@ class ZStackAdapter extends Adapter { }); } - public async supportsChangeChannel(): Promise { - return false; - } - public async changeChannel(newChannel: number): Promise { return this.queue.execute(async () => { this.checkInterpanLock(); @@ -1083,8 +1079,8 @@ class ZStackAdapter extends Adapter { dstaddrmode: AddressMode.ADDR_BROADCAST, channelmask: [newChannel].reduce((a, c) => a + (1 << c), 0), scanduration: 0xfe, // change channel - // scancount: null,// TODO: what's "not present" here? - // nwkmanageraddr: null,// TODO: what's "not present" here? + scancount: 0, + nwkmanageraddr: 0, }; await this.znp.request(Subsystem.ZDO, 'mgmtNwkUpdateReq', payload); diff --git a/src/adapter/zigate/adapter/zigateAdapter.ts b/src/adapter/zigate/adapter/zigateAdapter.ts index 99309bb008..eda86f5083 100644 --- a/src/adapter/zigate/adapter/zigateAdapter.ts +++ b/src/adapter/zigate/adapter/zigateAdapter.ts @@ -194,13 +194,9 @@ class ZiGateAdapter extends Adapter { throw new Error('This adapter does not support backup'); } - public async supportsChangeChannel(): Promise { - return false; - } - // eslint-disable-next-line @typescript-eslint/no-unused-vars public async changeChannel(newChannel: number): Promise { - throw new Error('not supported'); + throw new Error(`Channel change is not supported for 'zigate'`); } public async setTransmitPower(value: number): Promise { diff --git a/src/controller/controller.ts b/src/controller/controller.ts index 06dbe84803..6ef90a59cb 100644 --- a/src/controller/controller.ts +++ b/src/controller/controller.ts @@ -131,11 +131,14 @@ class Controller extends events.EventEmitter { // Check if we have to change the channel, only do this when adapter `resumed` because: // - `getNetworkParameters` might be return wrong info because it needs to propogate after backup restore // - If result is not `resumed` (`reset` or `restored`), the adapter should comission with the channel from `this.options.network` - if (startResult === 'resumed' && (await this.adapter.supportsChangeChannel())) { + if (startResult === 'resumed') { const netParams = await this.getNetworkParameters(); + const configuredChannel = this.options.network.channelList[0]; + const adapterChannel = netParams.channel; - if (this.options.network.channelList[0] !== netParams.channel) { - await this.changeChannel(); + if (configuredChannel != adapterChannel) { + logger.info(`Configured channel '${configuredChannel}' does not match adapter channel '${adapterChannel}', changing channel`, NS); + await this.changeChannel(adapterChannel, configuredChannel); } } @@ -438,9 +441,10 @@ class Controller extends events.EventEmitter { /** * Broadcast a network-wide channel change. */ - private async changeChannel(): Promise { - logger.info(`Broadcasting change channel to '${this.options.network.channelList[0]}'.`, NS); - await this.adapter.changeChannel(this.options.network.channelList[0]); + private async changeChannel(oldChannel: number, newChannel: number): Promise { + logger.warning(`Changing channel from '${oldChannel}' to '${newChannel}'`, NS); + await this.adapter.changeChannel(newChannel); + logger.info(`Channel changed to '${newChannel}'`, NS); this.networkParametersCached = null; // invalidate cache } diff --git a/test/adapter/z-stack/adapter.test.ts b/test/adapter/z-stack/adapter.test.ts index 4ed19fc5e7..29beb67dee 100644 --- a/test/adapter/z-stack/adapter.test.ts +++ b/test/adapter/z-stack/adapter.test.ts @@ -2278,12 +2278,6 @@ describe('zstack-adapter', () => { expect(mockZnpRequest).toBeCalledWith(Subsystem.SYS, 'resetReq', {type: 0}); }); - it('Supports change channel', async () => { - basicMocks(); - await adapter.start(); - expect(await adapter.supportsChangeChannel()).toBeFalsy(); - }); - it('Change channel', async () => { basicMocks(); await adapter.start(); @@ -2295,6 +2289,8 @@ describe('zstack-adapter', () => { dstaddrmode: 15, channelmask: 0x2000000, scanduration: 0xfe, + scancount: 0, + nwkmanageraddr: 0, }); }); diff --git a/test/controller.test.ts b/test/controller.test.ts index 3cbf1b8482..d7477c6216 100755 --- a/test/controller.test.ts +++ b/test/controller.test.ts @@ -54,7 +54,6 @@ const mockAdapterReset = jest.fn(); const mockAdapterStop = jest.fn(); const mockAdapterStart = jest.fn().mockReturnValue('resumed'); const mockAdapterSetTransmitPower = jest.fn(); -const mockAdapterSupportsChangeChannel = jest.fn().mockReturnValue(false); const mockAdapterChangeChannel = jest.fn(); const mockAdapterGetCoordinator = jest.fn().mockReturnValue({ ieeeAddr: '0x0000012300000000', @@ -530,7 +529,6 @@ jest.mock('../src/adapter/z-stack/adapter/zStackAdapter', () => { getNetworkParameters: mockAdapterGetNetworkParameters, waitFor: mockAdapterWaitFor, setTransmitPower: mockAdapterSetTransmitPower, - supportsChangeChannel: mockAdapterSupportsChangeChannel, changeChannel: mockAdapterChangeChannel, nodeDescriptor: mockAdapterNodeDescriptor, activeEndpoints: (networkAddress) => { @@ -1726,16 +1724,14 @@ describe('Controller', () => { it('Change channel', async () => { await controller.start(); - controller.options.network.channelList[0] = 20; - await controller.changeChannel(); + await controller.changeChannel(10, 20); expect(mockAdapterChangeChannel).toHaveBeenCalledWith(20); mockAdapterGetNetworkParameters.mockReturnValueOnce({panID: 1, extendedPanID: 3, channel: 20}); expect(await controller.getNetworkParameters()).toEqual({panID: 1, channel: 20, extendedPanID: 3}); }); - it('Change channel on start if supported', async () => { + it('Change channel on start', async () => { mockAdapterStart.mockReturnValueOnce('resumed'); - mockAdapterSupportsChangeChannel.mockReturnValueOnce(true); mockAdapterGetNetworkParameters.mockReturnValueOnce({panID: 1, extendedPanID: 3, channel: 25}); await controller.start(); expect(mockAdapterGetNetworkParameters).toHaveBeenCalledTimes(1); @@ -1745,7 +1741,6 @@ describe('Controller', () => { it('Does not change channel on start if not changed', async () => { mockAdapterStart.mockReturnValueOnce('resumed'); - mockAdapterSupportsChangeChannel.mockReturnValueOnce(true); await controller.start(); expect(mockAdapterGetNetworkParameters).toHaveBeenCalledTimes(1); expect(mockAdapterChangeChannel).toHaveBeenCalledTimes(0); @@ -1753,11 +1748,13 @@ describe('Controller', () => { it('Does not change channel on start if not supported', async () => { mockAdapterStart.mockReturnValueOnce('resumed'); - mockAdapterSupportsChangeChannel.mockReturnValueOnce(false); + mockAdapterChangeChannel.mockImplementationOnce(() => { + throw new Error('Not supported'); + }); mockAdapterGetNetworkParameters.mockReturnValueOnce({panID: 1, extendedPanID: 3, channel: 25}); - await controller.start(); - expect(mockAdapterGetNetworkParameters).toHaveBeenCalledTimes(0); - expect(mockAdapterChangeChannel).toHaveBeenCalledTimes(0); + await expect(controller.start()).rejects.toThrow(`Not supported`); + expect(mockAdapterGetNetworkParameters).toHaveBeenCalledTimes(1); + expect(mockAdapterChangeChannel).toHaveBeenCalledTimes(1); // get rid of the mockReturnValueOnce that was never called mockAdapterGetNetworkParameters(); });