zigbee-herdsman 0.51.0 → 0.53.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +4 -2
- package/.prettierrc +9 -0
- package/.release-please-manifest.json +1 -1
- package/CHANGELOG.md +25 -0
- package/dist/adapter/adapter.d.ts +4 -4
- package/dist/adapter/adapter.d.ts.map +1 -1
- package/dist/adapter/adapter.js +8 -13
- package/dist/adapter/adapter.js.map +1 -1
- package/dist/adapter/deconz/adapter/deconzAdapter.d.ts +1 -1
- package/dist/adapter/deconz/adapter/deconzAdapter.d.ts.map +1 -1
- package/dist/adapter/deconz/adapter/deconzAdapter.js +249 -155
- package/dist/adapter/deconz/adapter/deconzAdapter.js.map +1 -1
- package/dist/adapter/deconz/adapter/index.d.ts +1 -1
- package/dist/adapter/deconz/adapter/index.d.ts.map +1 -1
- package/dist/adapter/deconz/adapter/index.js.map +1 -1
- package/dist/adapter/deconz/driver/constants.d.ts +1 -1
- package/dist/adapter/deconz/driver/constants.d.ts.map +1 -1
- package/dist/adapter/deconz/driver/constants.js +7 -7
- package/dist/adapter/deconz/driver/constants.js.map +1 -1
- package/dist/adapter/deconz/driver/driver.d.ts.map +1 -1
- package/dist/adapter/deconz/driver/driver.js +92 -60
- package/dist/adapter/deconz/driver/driver.js.map +1 -1
- package/dist/adapter/deconz/driver/frameParser.d.ts.map +1 -1
- package/dist/adapter/deconz/driver/frameParser.js +55 -46
- package/dist/adapter/deconz/driver/frameParser.js.map +1 -1
- package/dist/adapter/deconz/driver/parser.js +1 -1
- package/dist/adapter/ember/adapter/emberAdapter.d.ts +5 -5
- package/dist/adapter/ember/adapter/emberAdapter.d.ts.map +1 -1
- package/dist/adapter/ember/adapter/emberAdapter.js +803 -955
- package/dist/adapter/ember/adapter/emberAdapter.js.map +1 -1
- package/dist/adapter/ember/adapter/endpoints.d.ts.map +1 -1
- package/dist/adapter/ember/adapter/endpoints.js +4 -2
- package/dist/adapter/ember/adapter/endpoints.js.map +1 -1
- package/dist/adapter/ember/adapter/oneWaitress.d.ts +2 -2
- package/dist/adapter/ember/adapter/oneWaitress.d.ts.map +1 -1
- package/dist/adapter/ember/adapter/oneWaitress.js +16 -16
- package/dist/adapter/ember/adapter/oneWaitress.js.map +1 -1
- package/dist/adapter/ember/adapter/tokensManager.d.ts +3 -3
- package/dist/adapter/ember/adapter/tokensManager.d.ts.map +1 -1
- package/dist/adapter/ember/adapter/tokensManager.js +86 -85
- package/dist/adapter/ember/adapter/tokensManager.js.map +1 -1
- package/dist/adapter/ember/consts.d.ts.map +1 -1
- package/dist/adapter/ember/consts.js +27 -27
- package/dist/adapter/ember/consts.js.map +1 -1
- package/dist/adapter/ember/enums.d.ts +2 -2
- package/dist/adapter/ember/enums.d.ts.map +1 -1
- package/dist/adapter/ember/enums.js +8 -50
- package/dist/adapter/ember/enums.js.map +1 -1
- package/dist/adapter/ember/ezsp/buffalo.d.ts +4 -4
- package/dist/adapter/ember/ezsp/buffalo.d.ts.map +1 -1
- package/dist/adapter/ember/ezsp/buffalo.js +35 -34
- package/dist/adapter/ember/ezsp/buffalo.js.map +1 -1
- package/dist/adapter/ember/ezsp/consts.d.ts.map +1 -1
- package/dist/adapter/ember/ezsp/consts.js +4 -4
- package/dist/adapter/ember/ezsp/consts.js.map +1 -1
- package/dist/adapter/ember/ezsp/enums.d.ts.map +1 -1
- package/dist/adapter/ember/ezsp/enums.js +0 -2
- package/dist/adapter/ember/ezsp/enums.js.map +1 -1
- package/dist/adapter/ember/ezsp/ezsp.d.ts +23 -20
- package/dist/adapter/ember/ezsp/ezsp.d.ts.map +1 -1
- package/dist/adapter/ember/ezsp/ezsp.js +1146 -1141
- package/dist/adapter/ember/ezsp/ezsp.js.map +1 -1
- package/dist/adapter/ember/ezspError.d.ts +1 -1
- package/dist/adapter/ember/ezspError.d.ts.map +1 -1
- package/dist/adapter/ember/ezspError.js.map +1 -1
- package/dist/adapter/ember/types.d.ts +2 -1
- package/dist/adapter/ember/types.d.ts.map +1 -1
- package/dist/adapter/ember/uart/ash.d.ts +5 -5
- package/dist/adapter/ember/uart/ash.d.ts.map +1 -1
- package/dist/adapter/ember/uart/ash.js +66 -65
- package/dist/adapter/ember/uart/ash.js.map +1 -1
- package/dist/adapter/ember/uart/consts.d.ts.map +1 -1
- package/dist/adapter/ember/uart/consts.js +9 -9
- package/dist/adapter/ember/uart/consts.js.map +1 -1
- package/dist/adapter/ember/uart/enums.d.ts.map +1 -1
- package/dist/adapter/ember/uart/parser.d.ts +1 -1
- package/dist/adapter/ember/uart/parser.d.ts.map +1 -1
- package/dist/adapter/ember/uart/parser.js +1 -1
- package/dist/adapter/ember/uart/parser.js.map +1 -1
- package/dist/adapter/ember/uart/queues.d.ts.map +1 -1
- package/dist/adapter/ember/uart/queues.js +1 -1
- package/dist/adapter/ember/uart/queues.js.map +1 -1
- package/dist/adapter/ember/uart/writer.d.ts +1 -1
- package/dist/adapter/ember/uart/writer.d.ts.map +1 -1
- package/dist/adapter/ember/uart/writer.js +2 -3
- package/dist/adapter/ember/uart/writer.js.map +1 -1
- package/dist/adapter/ember/utils/initters.d.ts +2 -2
- package/dist/adapter/ember/utils/initters.d.ts.map +1 -1
- package/dist/adapter/ember/utils/initters.js +1 -0
- package/dist/adapter/ember/utils/initters.js.map +1 -1
- package/dist/adapter/ember/utils/math.d.ts.map +1 -1
- package/dist/adapter/ember/utils/math.js +11 -11
- package/dist/adapter/ember/utils/math.js.map +1 -1
- package/dist/adapter/events.d.ts +1 -1
- package/dist/adapter/events.d.ts.map +1 -1
- package/dist/adapter/ezsp/adapter/backup.d.ts +1 -1
- package/dist/adapter/ezsp/adapter/backup.d.ts.map +1 -1
- package/dist/adapter/ezsp/adapter/backup.js +11 -10
- package/dist/adapter/ezsp/adapter/backup.js.map +1 -1
- package/dist/adapter/ezsp/adapter/ezspAdapter.d.ts +4 -4
- package/dist/adapter/ezsp/adapter/ezspAdapter.d.ts.map +1 -1
- package/dist/adapter/ezsp/adapter/ezspAdapter.js +74 -41
- package/dist/adapter/ezsp/adapter/ezspAdapter.js.map +1 -1
- package/dist/adapter/ezsp/adapter/index.d.ts +1 -1
- package/dist/adapter/ezsp/adapter/index.d.ts.map +1 -1
- package/dist/adapter/ezsp/adapter/index.js.map +1 -1
- package/dist/adapter/ezsp/driver/commands.d.ts.map +1 -1
- package/dist/adapter/ezsp/driver/commands.js +452 -452
- package/dist/adapter/ezsp/driver/commands.js.map +1 -1
- package/dist/adapter/ezsp/driver/consts.js +4 -4
- package/dist/adapter/ezsp/driver/consts.js.map +1 -1
- package/dist/adapter/ezsp/driver/driver.d.ts +5 -5
- package/dist/adapter/ezsp/driver/driver.d.ts.map +1 -1
- package/dist/adapter/ezsp/driver/driver.js +82 -82
- package/dist/adapter/ezsp/driver/driver.js.map +1 -1
- package/dist/adapter/ezsp/driver/ezsp.d.ts +3 -3
- package/dist/adapter/ezsp/driver/ezsp.d.ts.map +1 -1
- package/dist/adapter/ezsp/driver/ezsp.js +58 -58
- package/dist/adapter/ezsp/driver/ezsp.js.map +1 -1
- package/dist/adapter/ezsp/driver/frame.js +9 -9
- package/dist/adapter/ezsp/driver/frame.js.map +1 -1
- package/dist/adapter/ezsp/driver/index.d.ts +1 -1
- package/dist/adapter/ezsp/driver/index.d.ts.map +1 -1
- package/dist/adapter/ezsp/driver/index.js +2 -2
- package/dist/adapter/ezsp/driver/index.js.map +1 -1
- package/dist/adapter/ezsp/driver/multicast.d.ts.map +1 -1
- package/dist/adapter/ezsp/driver/multicast.js +1 -1
- package/dist/adapter/ezsp/driver/multicast.js.map +1 -1
- package/dist/adapter/ezsp/driver/parser.d.ts.map +1 -1
- package/dist/adapter/ezsp/driver/parser.js +1 -1
- package/dist/adapter/ezsp/driver/parser.js.map +1 -1
- package/dist/adapter/ezsp/driver/types/basic.d.ts.map +1 -1
- package/dist/adapter/ezsp/driver/types/basic.js +5 -5
- package/dist/adapter/ezsp/driver/types/basic.js.map +1 -1
- package/dist/adapter/ezsp/driver/types/index.d.ts.map +1 -1
- package/dist/adapter/ezsp/driver/types/index.js.map +1 -1
- package/dist/adapter/ezsp/driver/types/named.d.ts.map +1 -1
- package/dist/adapter/ezsp/driver/types/named.js +236 -234
- package/dist/adapter/ezsp/driver/types/named.js.map +1 -1
- package/dist/adapter/ezsp/driver/types/struct.d.ts.map +1 -1
- package/dist/adapter/ezsp/driver/types/struct.js +5 -3
- package/dist/adapter/ezsp/driver/types/struct.js.map +1 -1
- package/dist/adapter/ezsp/driver/uart.d.ts.map +1 -1
- package/dist/adapter/ezsp/driver/uart.js +8 -8
- package/dist/adapter/ezsp/driver/uart.js.map +1 -1
- package/dist/adapter/ezsp/driver/utils/index.d.ts +1 -1
- package/dist/adapter/ezsp/driver/utils/index.d.ts.map +1 -1
- package/dist/adapter/ezsp/driver/utils/index.js +12 -11
- package/dist/adapter/ezsp/driver/utils/index.js.map +1 -1
- package/dist/adapter/ezsp/driver/writer.d.ts.map +1 -1
- package/dist/adapter/ezsp/driver/writer.js +6 -7
- package/dist/adapter/ezsp/driver/writer.js.map +1 -1
- package/dist/adapter/index.d.ts +2 -2
- package/dist/adapter/index.d.ts.map +1 -1
- package/dist/adapter/index.js +2 -2
- package/dist/adapter/index.js.map +1 -1
- package/dist/adapter/serialPort.d.ts +1 -1
- package/dist/adapter/serialPort.d.ts.map +1 -1
- package/dist/adapter/serialPort.js +1 -1
- package/dist/adapter/serialPort.js.map +1 -1
- package/dist/adapter/serialPortUtils.js +1 -1
- package/dist/adapter/serialPortUtils.js.map +1 -1
- package/dist/adapter/socketPortUtils.js +3 -3
- package/dist/adapter/tstype.d.ts +1 -1
- package/dist/adapter/tstype.d.ts.map +1 -1
- package/dist/adapter/z-stack/adapter/adapter-backup.d.ts +3 -3
- package/dist/adapter/z-stack/adapter/adapter-backup.d.ts.map +1 -1
- package/dist/adapter/z-stack/adapter/adapter-backup.js +101 -86
- package/dist/adapter/z-stack/adapter/adapter-backup.js.map +1 -1
- package/dist/adapter/z-stack/adapter/adapter-nv-memory.d.ts +10 -10
- package/dist/adapter/z-stack/adapter/adapter-nv-memory.d.ts.map +1 -1
- package/dist/adapter/z-stack/adapter/adapter-nv-memory.js +30 -24
- package/dist/adapter/z-stack/adapter/adapter-nv-memory.js.map +1 -1
- package/dist/adapter/z-stack/adapter/endpoints.d.ts.map +1 -1
- package/dist/adapter/z-stack/adapter/endpoints.js +4 -4
- package/dist/adapter/z-stack/adapter/endpoints.js.map +1 -1
- package/dist/adapter/z-stack/adapter/index.d.ts +1 -1
- package/dist/adapter/z-stack/adapter/index.d.ts.map +1 -1
- package/dist/adapter/z-stack/adapter/index.js.map +1 -1
- package/dist/adapter/z-stack/adapter/manager.d.ts +5 -5
- package/dist/adapter/z-stack/adapter/manager.d.ts.map +1 -1
- package/dist/adapter/z-stack/adapter/manager.js +90 -81
- package/dist/adapter/z-stack/adapter/manager.js.map +1 -1
- package/dist/adapter/z-stack/adapter/tstype.d.ts +1 -1
- package/dist/adapter/z-stack/adapter/tstype.d.ts.map +1 -1
- package/dist/adapter/z-stack/adapter/zStackAdapter.d.ts +5 -5
- package/dist/adapter/z-stack/adapter/zStackAdapter.d.ts.map +1 -1
- package/dist/adapter/z-stack/adapter/zStackAdapter.js +72 -57
- package/dist/adapter/z-stack/adapter/zStackAdapter.js.map +1 -1
- package/dist/adapter/z-stack/constants/af.js +5 -5
- package/dist/adapter/z-stack/constants/af.js.map +1 -1
- package/dist/adapter/z-stack/constants/dbg.js +2 -2
- package/dist/adapter/z-stack/constants/index.d.ts +2 -2
- package/dist/adapter/z-stack/constants/index.d.ts.map +1 -1
- package/dist/adapter/z-stack/constants/index.js +2 -2
- package/dist/adapter/z-stack/constants/index.js.map +1 -1
- package/dist/adapter/z-stack/constants/mac.js +11 -11
- package/dist/adapter/z-stack/constants/sapi.js +4 -4
- package/dist/adapter/z-stack/constants/sys.js +11 -11
- package/dist/adapter/z-stack/constants/util.js +11 -11
- package/dist/adapter/z-stack/constants/utils.d.ts.map +1 -1
- package/dist/adapter/z-stack/constants/utils.js +3 -3
- package/dist/adapter/z-stack/constants/utils.js.map +1 -1
- package/dist/adapter/z-stack/constants/zdo.js +13 -13
- package/dist/adapter/z-stack/models/index.d.ts +1 -1
- package/dist/adapter/z-stack/models/startup-options.d.ts +2 -2
- package/dist/adapter/z-stack/structs/entries/address-manager-entry.d.ts +1 -1
- package/dist/adapter/z-stack/structs/entries/address-manager-entry.js +4 -4
- package/dist/adapter/z-stack/structs/entries/address-manager-entry.js.map +1 -1
- package/dist/adapter/z-stack/structs/entries/address-manager-table.d.ts +2 -2
- package/dist/adapter/z-stack/structs/entries/address-manager-table.d.ts.map +1 -1
- package/dist/adapter/z-stack/structs/entries/address-manager-table.js +4 -7
- package/dist/adapter/z-stack/structs/entries/address-manager-table.js.map +1 -1
- package/dist/adapter/z-stack/structs/entries/aps-link-key-data-entry.d.ts +1 -1
- package/dist/adapter/z-stack/structs/entries/aps-link-key-data-entry.d.ts.map +1 -1
- package/dist/adapter/z-stack/structs/entries/aps-link-key-data-entry.js +1 -5
- package/dist/adapter/z-stack/structs/entries/aps-link-key-data-entry.js.map +1 -1
- package/dist/adapter/z-stack/structs/entries/aps-link-key-data-table.d.ts +2 -2
- package/dist/adapter/z-stack/structs/entries/aps-link-key-data-table.d.ts.map +1 -1
- package/dist/adapter/z-stack/structs/entries/aps-link-key-data-table.js +3 -6
- package/dist/adapter/z-stack/structs/entries/aps-link-key-data-table.js.map +1 -1
- package/dist/adapter/z-stack/structs/entries/aps-tc-link-key-entry.d.ts +1 -1
- package/dist/adapter/z-stack/structs/entries/aps-tc-link-key-entry.js +6 -6
- package/dist/adapter/z-stack/structs/entries/aps-tc-link-key-table.d.ts +2 -2
- package/dist/adapter/z-stack/structs/entries/aps-tc-link-key-table.d.ts.map +1 -1
- package/dist/adapter/z-stack/structs/entries/aps-tc-link-key-table.js +3 -6
- package/dist/adapter/z-stack/structs/entries/aps-tc-link-key-table.js.map +1 -1
- package/dist/adapter/z-stack/structs/entries/channel-list.d.ts +1 -1
- package/dist/adapter/z-stack/structs/entries/channel-list.d.ts.map +1 -1
- package/dist/adapter/z-stack/structs/entries/channel-list.js +1 -3
- package/dist/adapter/z-stack/structs/entries/channel-list.js.map +1 -1
- package/dist/adapter/z-stack/structs/entries/has-configured.d.ts +1 -1
- package/dist/adapter/z-stack/structs/entries/has-configured.d.ts.map +1 -1
- package/dist/adapter/z-stack/structs/entries/has-configured.js +2 -2
- package/dist/adapter/z-stack/structs/entries/has-configured.js.map +1 -1
- package/dist/adapter/z-stack/structs/entries/index.d.ts +16 -16
- package/dist/adapter/z-stack/structs/entries/nib.d.ts +1 -1
- package/dist/adapter/z-stack/structs/entries/nib.d.ts.map +1 -1
- package/dist/adapter/z-stack/structs/entries/nib.js +50 -50
- package/dist/adapter/z-stack/structs/entries/nib.js.map +1 -1
- package/dist/adapter/z-stack/structs/entries/nwk-key-descriptor.d.ts +1 -1
- package/dist/adapter/z-stack/structs/entries/nwk-key-descriptor.d.ts.map +1 -1
- package/dist/adapter/z-stack/structs/entries/nwk-key-descriptor.js +1 -4
- package/dist/adapter/z-stack/structs/entries/nwk-key-descriptor.js.map +1 -1
- package/dist/adapter/z-stack/structs/entries/nwk-key.d.ts +1 -1
- package/dist/adapter/z-stack/structs/entries/nwk-key.d.ts.map +1 -1
- package/dist/adapter/z-stack/structs/entries/nwk-key.js +1 -3
- package/dist/adapter/z-stack/structs/entries/nwk-key.js.map +1 -1
- package/dist/adapter/z-stack/structs/entries/nwk-pan-id.d.ts +1 -1
- package/dist/adapter/z-stack/structs/entries/nwk-pan-id.d.ts.map +1 -1
- package/dist/adapter/z-stack/structs/entries/nwk-pan-id.js +1 -3
- package/dist/adapter/z-stack/structs/entries/nwk-pan-id.js.map +1 -1
- package/dist/adapter/z-stack/structs/entries/nwk-sec-material-descriptor-entry.d.ts +1 -1
- package/dist/adapter/z-stack/structs/entries/nwk-sec-material-descriptor-entry.d.ts.map +1 -1
- package/dist/adapter/z-stack/structs/entries/nwk-sec-material-descriptor-entry.js +3 -3
- package/dist/adapter/z-stack/structs/entries/nwk-sec-material-descriptor-entry.js.map +1 -1
- package/dist/adapter/z-stack/structs/entries/nwk-sec-material-descriptor-table.d.ts +2 -2
- package/dist/adapter/z-stack/structs/entries/nwk-sec-material-descriptor-table.d.ts.map +1 -1
- package/dist/adapter/z-stack/structs/entries/nwk-sec-material-descriptor-table.js +3 -6
- package/dist/adapter/z-stack/structs/entries/nwk-sec-material-descriptor-table.js.map +1 -1
- package/dist/adapter/z-stack/structs/entries/security-manager-entry.d.ts +1 -1
- package/dist/adapter/z-stack/structs/entries/security-manager-entry.js +4 -4
- package/dist/adapter/z-stack/structs/entries/security-manager-table.d.ts +2 -2
- package/dist/adapter/z-stack/structs/entries/security-manager-table.d.ts.map +1 -1
- package/dist/adapter/z-stack/structs/entries/security-manager-table.js +3 -7
- package/dist/adapter/z-stack/structs/entries/security-manager-table.js.map +1 -1
- package/dist/adapter/z-stack/structs/index.d.ts +4 -4
- package/dist/adapter/z-stack/structs/serializable-memory-object.d.ts +1 -1
- package/dist/adapter/z-stack/structs/struct.d.ts +6 -6
- package/dist/adapter/z-stack/structs/struct.d.ts.map +1 -1
- package/dist/adapter/z-stack/structs/struct.js +53 -52
- package/dist/adapter/z-stack/structs/struct.js.map +1 -1
- package/dist/adapter/z-stack/structs/table.d.ts +3 -3
- package/dist/adapter/z-stack/structs/table.d.ts.map +1 -1
- package/dist/adapter/z-stack/structs/table.js +16 -16
- package/dist/adapter/z-stack/structs/table.js.map +1 -1
- package/dist/adapter/z-stack/unpi/constants.d.ts +1 -1
- package/dist/adapter/z-stack/unpi/constants.d.ts.map +1 -1
- package/dist/adapter/z-stack/unpi/constants.js +1 -1
- package/dist/adapter/z-stack/unpi/constants.js.map +1 -1
- package/dist/adapter/z-stack/unpi/frame.d.ts.map +1 -1
- package/dist/adapter/z-stack/unpi/frame.js +5 -6
- package/dist/adapter/z-stack/unpi/frame.js.map +1 -1
- package/dist/adapter/z-stack/unpi/index.d.ts +4 -4
- package/dist/adapter/z-stack/unpi/index.d.ts.map +1 -1
- package/dist/adapter/z-stack/unpi/index.js +6 -6
- package/dist/adapter/z-stack/unpi/index.js.map +1 -1
- package/dist/adapter/z-stack/unpi/parser.d.ts.map +1 -1
- package/dist/adapter/z-stack/unpi/parser.js +1 -1
- package/dist/adapter/z-stack/unpi/parser.js.map +1 -1
- package/dist/adapter/z-stack/unpi/writer.d.ts.map +1 -1
- package/dist/adapter/z-stack/unpi/writer.js.map +1 -1
- package/dist/adapter/z-stack/utils/channel-list.d.ts.map +1 -1
- package/dist/adapter/z-stack/utils/channel-list.js +5 -2
- package/dist/adapter/z-stack/utils/channel-list.js.map +1 -1
- package/dist/adapter/z-stack/utils/index.d.ts +2 -2
- package/dist/adapter/z-stack/utils/network-options.d.ts +1 -1
- package/dist/adapter/z-stack/utils/network-options.d.ts.map +1 -1
- package/dist/adapter/z-stack/utils/network-options.js +1 -1
- package/dist/adapter/z-stack/utils/network-options.js.map +1 -1
- package/dist/adapter/z-stack/znp/buffaloZnp.d.ts.map +1 -1
- package/dist/adapter/z-stack/znp/buffaloZnp.js +8 -8
- package/dist/adapter/z-stack/znp/buffaloZnp.js.map +1 -1
- package/dist/adapter/z-stack/znp/definition.d.ts.map +1 -1
- package/dist/adapter/z-stack/znp/definition.js +200 -592
- package/dist/adapter/z-stack/znp/definition.js.map +1 -1
- package/dist/adapter/z-stack/znp/index.d.ts +1 -1
- package/dist/adapter/z-stack/znp/index.d.ts.map +1 -1
- package/dist/adapter/z-stack/znp/index.js.map +1 -1
- package/dist/adapter/z-stack/znp/parameterType.d.ts.map +1 -1
- package/dist/adapter/z-stack/znp/parameterType.js.map +1 -1
- package/dist/adapter/z-stack/znp/tstype.d.ts.map +1 -1
- package/dist/adapter/z-stack/znp/znp.d.ts +3 -3
- package/dist/adapter/z-stack/znp/znp.d.ts.map +1 -1
- package/dist/adapter/z-stack/znp/znp.js +12 -15
- package/dist/adapter/z-stack/znp/znp.js.map +1 -1
- package/dist/adapter/z-stack/znp/zpiObject.d.ts +1 -1
- package/dist/adapter/z-stack/znp/zpiObject.d.ts.map +1 -1
- package/dist/adapter/z-stack/znp/zpiObject.js +17 -9
- package/dist/adapter/z-stack/znp/zpiObject.js.map +1 -1
- package/dist/adapter/zigate/adapter/index.d.ts.map +1 -1
- package/dist/adapter/zigate/adapter/index.js.map +1 -1
- package/dist/adapter/zigate/adapter/zigateAdapter.d.ts +1 -1
- package/dist/adapter/zigate/adapter/zigateAdapter.d.ts.map +1 -1
- package/dist/adapter/zigate/adapter/zigateAdapter.js +88 -92
- package/dist/adapter/zigate/adapter/zigateAdapter.js.map +1 -1
- package/dist/adapter/zigate/driver/buffaloZiGate.js.map +1 -1
- package/dist/adapter/zigate/driver/commandType.d.ts +2 -2
- package/dist/adapter/zigate/driver/commandType.d.ts.map +1 -1
- package/dist/adapter/zigate/driver/commandType.js +72 -80
- package/dist/adapter/zigate/driver/commandType.js.map +1 -1
- package/dist/adapter/zigate/driver/constants.d.ts +9 -9
- package/dist/adapter/zigate/driver/constants.d.ts.map +1 -1
- package/dist/adapter/zigate/driver/constants.js +11 -65
- package/dist/adapter/zigate/driver/constants.js.map +1 -1
- package/dist/adapter/zigate/driver/frame.d.ts.map +1 -1
- package/dist/adapter/zigate/driver/frame.js +3 -15
- package/dist/adapter/zigate/driver/frame.js.map +1 -1
- package/dist/adapter/zigate/driver/messageType.d.ts +1 -1
- package/dist/adapter/zigate/driver/messageType.d.ts.map +1 -1
- package/dist/adapter/zigate/driver/messageType.js +29 -30
- package/dist/adapter/zigate/driver/messageType.js.map +1 -1
- package/dist/adapter/zigate/driver/parameterType.d.ts.map +1 -1
- package/dist/adapter/zigate/driver/parameterType.js.map +1 -1
- package/dist/adapter/zigate/driver/ziGateObject.d.ts +2 -2
- package/dist/adapter/zigate/driver/ziGateObject.d.ts.map +1 -1
- package/dist/adapter/zigate/driver/ziGateObject.js +11 -5
- package/dist/adapter/zigate/driver/ziGateObject.js.map +1 -1
- package/dist/adapter/zigate/driver/zigate.d.ts +5 -5
- package/dist/adapter/zigate/driver/zigate.d.ts.map +1 -1
- package/dist/adapter/zigate/driver/zigate.js +12 -12
- package/dist/adapter/zigate/driver/zigate.js.map +1 -1
- package/dist/buffalo/buffalo.d.ts +1 -1
- package/dist/buffalo/buffalo.d.ts.map +1 -1
- package/dist/buffalo/buffalo.js +1 -1
- package/dist/buffalo/buffalo.js.map +1 -1
- package/dist/controller/controller.d.ts.map +1 -1
- package/dist/controller/controller.js +34 -33
- package/dist/controller/controller.js.map +1 -1
- package/dist/controller/database.d.ts.map +1 -1
- package/dist/controller/database.js +6 -2
- package/dist/controller/database.js.map +1 -1
- package/dist/controller/events.d.ts +3 -3
- package/dist/controller/events.d.ts.map +1 -1
- package/dist/controller/greenPower.d.ts +1 -1
- package/dist/controller/greenPower.d.ts.map +1 -1
- package/dist/controller/greenPower.js +15 -17
- package/dist/controller/greenPower.js.map +1 -1
- package/dist/controller/helpers/index.d.ts +1 -1
- package/dist/controller/helpers/index.d.ts.map +1 -1
- package/dist/controller/helpers/index.js.map +1 -1
- package/dist/controller/helpers/request.d.ts +1 -1
- package/dist/controller/helpers/request.d.ts.map +1 -1
- package/dist/controller/helpers/request.js +7 -10
- package/dist/controller/helpers/request.js.map +1 -1
- package/dist/controller/helpers/requestQueue.d.ts.map +1 -1
- package/dist/controller/helpers/requestQueue.js +2 -3
- package/dist/controller/helpers/requestQueue.js.map +1 -1
- package/dist/controller/helpers/zclFrameConverter.d.ts +1 -1
- package/dist/controller/helpers/zclFrameConverter.d.ts.map +1 -1
- package/dist/controller/helpers/zclFrameConverter.js.map +1 -1
- package/dist/controller/index.d.ts +1 -1
- package/dist/controller/index.d.ts.map +1 -1
- package/dist/controller/index.js.map +1 -1
- package/dist/controller/model/device.d.ts +3 -3
- package/dist/controller/model/device.d.ts.map +1 -1
- package/dist/controller/model/device.js +247 -94
- package/dist/controller/model/device.js.map +1 -1
- package/dist/controller/model/endpoint.d.ts +4 -4
- package/dist/controller/model/endpoint.d.ts.map +1 -1
- package/dist/controller/model/endpoint.js +45 -31
- package/dist/controller/model/endpoint.js.map +1 -1
- package/dist/controller/model/entity.d.ts +2 -2
- package/dist/controller/model/entity.d.ts.map +1 -1
- package/dist/controller/model/entity.js.map +1 -1
- package/dist/controller/model/group.d.ts +2 -2
- package/dist/controller/model/group.d.ts.map +1 -1
- package/dist/controller/model/group.js +8 -6
- package/dist/controller/model/group.js.map +1 -1
- package/dist/controller/model/index.d.ts +1 -1
- package/dist/controller/model/index.d.ts.map +1 -1
- package/dist/controller/model/index.js.map +1 -1
- package/dist/controller/touchlink.d.ts.map +1 -1
- package/dist/controller/touchlink.js +2 -2
- package/dist/controller/touchlink.js.map +1 -1
- package/dist/controller/tstype.d.ts.map +1 -1
- package/dist/controller/tstype.js +0 -1
- package/dist/controller/tstype.js.map +1 -1
- package/dist/models/backup-storage-legacy.d.ts +4 -4
- package/dist/models/backup-storage-legacy.d.ts.map +1 -1
- package/dist/models/backup-storage-unified.d.ts +1 -1
- package/dist/models/backup.d.ts +2 -2
- package/dist/models/index.d.ts +4 -4
- package/dist/utils/backup.d.ts +1 -1
- package/dist/utils/backup.d.ts.map +1 -1
- package/dist/utils/backup.js +71 -58
- package/dist/utils/backup.js.map +1 -1
- package/dist/utils/index.d.ts +6 -6
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +10 -10
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/isNumberArray.js +1 -1
- package/dist/utils/isNumberArray.js.map +1 -1
- package/dist/utils/queue.js +1 -1
- package/dist/utils/queue.js.map +1 -1
- package/dist/utils/waitress.d.ts.map +1 -1
- package/dist/utils/waitress.js +2 -2
- package/dist/utils/waitress.js.map +1 -1
- package/dist/zspec/consts.d.ts +1 -1
- package/dist/zspec/consts.d.ts.map +1 -1
- package/dist/zspec/consts.js +16 -16
- package/dist/zspec/consts.js.map +1 -1
- package/dist/zspec/enums.js +0 -1
- package/dist/zspec/enums.js.map +1 -1
- package/dist/zspec/utils.d.ts.map +1 -1
- package/dist/zspec/utils.js +5 -3
- package/dist/zspec/utils.js.map +1 -1
- package/dist/zspec/zcl/buffaloZcl.d.ts +2 -2
- package/dist/zspec/zcl/buffaloZcl.d.ts.map +1 -1
- package/dist/zspec/zcl/buffaloZcl.js +44 -51
- package/dist/zspec/zcl/buffaloZcl.js.map +1 -1
- package/dist/zspec/zcl/definition/cluster.d.ts.map +1 -1
- package/dist/zspec/zcl/definition/cluster.js +284 -380
- package/dist/zspec/zcl/definition/cluster.js.map +1 -1
- package/dist/zspec/zcl/definition/consts.js +10 -10
- package/dist/zspec/zcl/definition/consts.js.map +1 -1
- package/dist/zspec/zcl/definition/enums.d.ts.map +1 -1
- package/dist/zspec/zcl/definition/enums.js.map +1 -1
- package/dist/zspec/zcl/definition/foundation.d.ts +1 -1
- package/dist/zspec/zcl/definition/foundation.d.ts.map +1 -1
- package/dist/zspec/zcl/definition/foundation.js +51 -22
- package/dist/zspec/zcl/definition/foundation.js.map +1 -1
- package/dist/zspec/zcl/definition/manufacturerCode.js +0 -1
- package/dist/zspec/zcl/definition/manufacturerCode.js.map +1 -1
- package/dist/zspec/zcl/definition/status.d.ts.map +1 -1
- package/dist/zspec/zcl/definition/tstype.d.ts +1 -1
- package/dist/zspec/zcl/definition/tstype.d.ts.map +1 -1
- package/dist/zspec/zcl/definition/tstype.js +0 -1
- package/dist/zspec/zcl/definition/tstype.js.map +1 -1
- package/dist/zspec/zcl/utils.d.ts.map +1 -1
- package/dist/zspec/zcl/utils.js +59 -19
- package/dist/zspec/zcl/utils.js.map +1 -1
- package/dist/zspec/zcl/zclFrame.d.ts +1 -1
- package/dist/zspec/zcl/zclFrame.d.ts.map +1 -1
- package/dist/zspec/zcl/zclFrame.js +14 -15
- package/dist/zspec/zcl/zclFrame.js.map +1 -1
- package/dist/zspec/zcl/zclHeader.d.ts +1 -1
- package/dist/zspec/zcl/zclHeader.d.ts.map +1 -1
- package/dist/zspec/zcl/zclHeader.js +7 -7
- package/dist/zspec/zcl/zclHeader.js.map +1 -1
- package/dist/zspec/zcl/zclStatusError.d.ts.map +1 -1
- package/dist/zspec/zcl/zclStatusError.js.map +1 -1
- package/dist/zspec/zdo/buffaloZdo.d.ts +3 -3
- package/dist/zspec/zdo/buffaloZdo.d.ts.map +1 -1
- package/dist/zspec/zdo/buffaloZdo.js +92 -92
- package/dist/zspec/zdo/buffaloZdo.js.map +1 -1
- package/dist/zspec/zdo/definition/clusters.d.ts.map +1 -1
- package/dist/zspec/zdo/definition/clusters.js +0 -1
- package/dist/zspec/zdo/definition/clusters.js.map +1 -1
- package/dist/zspec/zdo/definition/consts.d.ts.map +1 -1
- package/dist/zspec/zdo/definition/consts.js.map +1 -1
- package/dist/zspec/zdo/definition/enums.d.ts.map +1 -1
- package/dist/zspec/zdo/definition/enums.js +0 -5
- package/dist/zspec/zdo/definition/enums.js.map +1 -1
- package/dist/zspec/zdo/definition/status.d.ts.map +1 -1
- package/dist/zspec/zdo/definition/status.js +0 -1
- package/dist/zspec/zdo/definition/status.js.map +1 -1
- package/dist/zspec/zdo/definition/tstypes.d.ts +2 -2
- package/dist/zspec/zdo/definition/tstypes.d.ts.map +1 -1
- package/dist/zspec/zdo/utils.d.ts.map +1 -1
- package/dist/zspec/zdo/utils.js +14 -14
- package/dist/zspec/zdo/utils.js.map +1 -1
- package/dist/zspec/zdo/zdoStatusError.d.ts.map +1 -1
- package/dist/zspec/zdo/zdoStatusError.js.map +1 -1
- package/package.json +6 -1
- package/dist/adapter/ember/adapter/requestQueue.d.ts +0 -67
- package/dist/adapter/ember/adapter/requestQueue.d.ts.map +0 -1
- package/dist/adapter/ember/adapter/requestQueue.js +0 -159
- package/dist/adapter/ember/adapter/requestQueue.js.map +0 -1
|
@@ -28,33 +28,31 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
29
|
exports.EmberAdapter = void 0;
|
|
30
30
|
/* istanbul ignore file */
|
|
31
|
+
const crypto_1 = require("crypto");
|
|
31
32
|
const es6_1 = __importDefault(require("fast-deep-equal/es6"));
|
|
32
33
|
const fs_1 = require("fs");
|
|
33
34
|
const path_1 = __importDefault(require("path"));
|
|
34
|
-
const serialPortUtils_1 = __importDefault(require("../../serialPortUtils"));
|
|
35
|
-
const socketPortUtils_1 = __importDefault(require("../../socketPortUtils"));
|
|
36
|
-
const utils_1 = require("../../../utils");
|
|
37
35
|
const __1 = require("../..");
|
|
36
|
+
const utils_1 = require("../../../utils");
|
|
37
|
+
const logger_1 = require("../../../utils/logger");
|
|
38
38
|
const ZSpec = __importStar(require("../../../zspec"));
|
|
39
39
|
const Zcl = __importStar(require("../../../zspec/zcl"));
|
|
40
40
|
const Zdo = __importStar(require("../../../zspec/zdo"));
|
|
41
|
+
const buffaloZdo_1 = require("../../../zspec/zdo/buffaloZdo");
|
|
41
42
|
const events_1 = require("../../events");
|
|
42
|
-
const
|
|
43
|
-
const
|
|
44
|
-
const consts_1 = require("../
|
|
45
|
-
const enums_1 = require("../
|
|
43
|
+
const serialPortUtils_1 = __importDefault(require("../../serialPortUtils"));
|
|
44
|
+
const socketPortUtils_1 = __importDefault(require("../../socketPortUtils"));
|
|
45
|
+
const consts_1 = require("../consts");
|
|
46
|
+
const enums_1 = require("../enums");
|
|
46
47
|
const buffalo_1 = require("../ezsp/buffalo");
|
|
47
|
-
const
|
|
48
|
-
const
|
|
49
|
-
const
|
|
50
|
-
const
|
|
48
|
+
const consts_2 = require("../ezsp/consts");
|
|
49
|
+
const enums_2 = require("../ezsp/enums");
|
|
50
|
+
const ezsp_1 = require("../ezsp/ezsp");
|
|
51
|
+
const ezspError_1 = require("../ezspError");
|
|
51
52
|
const initters_1 = require("../utils/initters");
|
|
52
|
-
const
|
|
53
|
+
const math_1 = require("../utils/math");
|
|
54
|
+
const endpoints_1 = require("./endpoints");
|
|
53
55
|
const oneWaitress_1 = require("./oneWaitress");
|
|
54
|
-
const logger_1 = require("../../../utils/logger");
|
|
55
|
-
const ezspError_1 = require("../ezspError");
|
|
56
|
-
const buffaloZdo_1 = require("../../../zspec/zdo/buffaloZdo");
|
|
57
|
-
// import {EmberTokensManager} from './tokensManager';
|
|
58
56
|
const NS = 'zh:ember';
|
|
59
57
|
/** Enum to pass strings from numbers up to Z2M. */
|
|
60
58
|
var RoutingTableStatus;
|
|
@@ -68,7 +66,6 @@ var RoutingTableStatus;
|
|
|
68
66
|
RoutingTableStatus[RoutingTableStatus["RESERVED2"] = 6] = "RESERVED2";
|
|
69
67
|
RoutingTableStatus[RoutingTableStatus["RESERVED3"] = 7] = "RESERVED3";
|
|
70
68
|
})(RoutingTableStatus || (RoutingTableStatus = {}));
|
|
71
|
-
;
|
|
72
69
|
var NetworkInitAction;
|
|
73
70
|
(function (NetworkInitAction) {
|
|
74
71
|
/** Ain't that nice! */
|
|
@@ -82,7 +79,6 @@ var NetworkInitAction;
|
|
|
82
79
|
/** Re-form the network using full backed-up data. */
|
|
83
80
|
NetworkInitAction[NetworkInitAction["FORM_BACKUP"] = 4] = "FORM_BACKUP";
|
|
84
81
|
})(NetworkInitAction || (NetworkInitAction = {}));
|
|
85
|
-
;
|
|
86
82
|
/** NOTE: Drivers can override `manufacturer`. Verify logic doesn't work in most cases anyway. */
|
|
87
83
|
const autoDetectDefinitions = [
|
|
88
84
|
/** NOTE: Manuf code "0x1321" for "Shenzhen Sonoff Technologies Co., Ltd." */
|
|
@@ -96,7 +92,7 @@ const autoDetectDefinitions = [
|
|
|
96
92
|
* for coordination between the two entities, and allows both to send ZDO
|
|
97
93
|
* messages with non-conflicting sequence numbers.
|
|
98
94
|
*/
|
|
99
|
-
const APPLICATION_ZDO_SEQUENCE_MASK =
|
|
95
|
+
const APPLICATION_ZDO_SEQUENCE_MASK = 0x7f;
|
|
100
96
|
/** Current revision of the spec by zigbee alliance supported by Z2M. */
|
|
101
97
|
const CURRENT_ZIGBEE_SPEC_REVISION = 22;
|
|
102
98
|
/** Each scan period is 15.36ms. Scan for at least 200ms (2^4 + 1 periods) to pick up WiFi beacon frames. */
|
|
@@ -108,6 +104,10 @@ const BACKUP_OLDEST_SUPPORTED_EZSP_VERSION = 12;
|
|
|
108
104
|
* NOTE: This is blocking the request queue, so we shouldn't go crazy high.
|
|
109
105
|
*/
|
|
110
106
|
const BROADCAST_NETWORK_KEY_SWITCH_WAIT_TIME = 15000;
|
|
107
|
+
const QUEUE_HIGH_COUNT = 4;
|
|
108
|
+
const QUEUE_MAX_SEND_ATTEMPTS = 3;
|
|
109
|
+
const QUEUE_BUSY_DEFER_MSEC = 500;
|
|
110
|
+
const QUEUE_NETWORK_DOWN_DEFER_MSEC = 1500;
|
|
111
111
|
/**
|
|
112
112
|
* Default stack configuration values.
|
|
113
113
|
* @see https://www.silabs.com/documents/public/user-guides/ug100-ezsp-reference-guide.pdf 2.3.1 for descriptions/RAM costs
|
|
@@ -130,6 +130,8 @@ const DEFAULT_STACK_CONFIG = {
|
|
|
130
130
|
};
|
|
131
131
|
/** Default behavior is to disable app key requests */
|
|
132
132
|
const ALLOW_APP_KEY_REQUESTS = false;
|
|
133
|
+
/** @see EzspConfigId.TRUST_CENTER_ADDRESS_CACHE_SIZE */
|
|
134
|
+
const TRUST_CENTER_ADDRESS_CACHE_SIZE = 2;
|
|
133
135
|
/**
|
|
134
136
|
* NOTE: This from SDK is currently ignored here because of issues in below links:
|
|
135
137
|
* - BUGZID 12261: Concentrators use MTORRs for route discovery and should not enable route discovery in the APS options.
|
|
@@ -138,7 +140,7 @@ const ALLOW_APP_KEY_REQUESTS = false;
|
|
|
138
140
|
*
|
|
139
141
|
* Removing `ENABLE_ROUTE_DISCOVERY` leads to devices that won't reconnect/go offline, and various other issues. Keeping it for now.
|
|
140
142
|
*/
|
|
141
|
-
const DEFAULT_APS_OPTIONS =
|
|
143
|
+
const DEFAULT_APS_OPTIONS = enums_1.EmberApsOption.RETRY | enums_1.EmberApsOption.ENABLE_ROUTE_DISCOVERY | enums_1.EmberApsOption.ENABLE_ADDRESS_DISCOVERY;
|
|
142
144
|
/** Time for a ZDO request to get a callback response. ASH is 2400*6 for ACK timeout. */
|
|
143
145
|
const DEFAULT_ZDO_REQUEST_TIMEOUT = 15000; // msec
|
|
144
146
|
/** Time for a ZCL request to get a callback response. ASH is 2400*6 for ACK timeout. */
|
|
@@ -156,7 +158,7 @@ const DEFAULT_MANUFACTURER_CODE = Zcl.ManufacturerCode.SILICON_LABORATORIES;
|
|
|
156
158
|
const WORKAROUND_JOIN_MANUF_IEEE_PREFIX_TO_CODE = {
|
|
157
159
|
// NOTE: Lumi has a new prefix registered since 2021, in case they start using that one with new devices, it might need to be added here too...
|
|
158
160
|
// "0x18c23c" https://maclookup.app/vendors/lumi-united-technology-co-ltd
|
|
159
|
-
|
|
161
|
+
'0x54ef44': Zcl.ManufacturerCode.LUMI_UNITED_TECHOLOGY_LTD_SHENZHEN,
|
|
160
162
|
};
|
|
161
163
|
/**
|
|
162
164
|
* Relay calls between Z2M and EZSP-layer and handle any error that might occur via queue & waitress.
|
|
@@ -169,7 +171,7 @@ class EmberAdapter extends __1.Adapter {
|
|
|
169
171
|
stackConfig;
|
|
170
172
|
ezsp;
|
|
171
173
|
version;
|
|
172
|
-
|
|
174
|
+
queue;
|
|
173
175
|
oneWaitress;
|
|
174
176
|
/** Periodically retrieve counters then clear them. */
|
|
175
177
|
watchdogCountersHandle;
|
|
@@ -187,9 +189,9 @@ class EmberAdapter extends __1.Adapter {
|
|
|
187
189
|
constructor(networkOptions, serialPortOptions, backupPath, adapterOptions) {
|
|
188
190
|
super(networkOptions, serialPortOptions, backupPath, adapterOptions);
|
|
189
191
|
this.stackConfig = this.loadStackConfig();
|
|
190
|
-
const delay =
|
|
192
|
+
const delay = typeof this.adapterOptions.delay === 'number' ? Math.min(Math.max(this.adapterOptions.delay, 5), 60) : 5;
|
|
191
193
|
logger_1.logger.debug(`Using delay=${delay}.`, NS);
|
|
192
|
-
this.
|
|
194
|
+
this.queue = new utils_1.Queue(typeof this.adapterOptions.concurrent === 'number' ? Math.min(Math.max(this.adapterOptions.concurrent, 1), 32) : 16);
|
|
193
195
|
this.oneWaitress = new oneWaitress_1.EmberOneWaitress();
|
|
194
196
|
this.ezsp = new ezsp_1.Ezsp(serialPortOptions);
|
|
195
197
|
this.ezsp.on(ezsp_1.EzspEvents.ZDO_RESPONSE, this.onZDOResponse.bind(this));
|
|
@@ -207,16 +209,16 @@ class EmberAdapter extends __1.Adapter {
|
|
|
207
209
|
const customConfig = JSON.parse((0, fs_1.readFileSync)(configPath, 'utf8'));
|
|
208
210
|
// set any undefined config to default
|
|
209
211
|
const config = { ...DEFAULT_STACK_CONFIG, ...customConfig };
|
|
210
|
-
const inRange = (value, min, max) => (value == undefined || value < min || value > max
|
|
212
|
+
const inRange = (value, min, max) => (value == undefined || value < min || value > max ? false : true);
|
|
211
213
|
if (!['high', 'low'].includes(config.CONCENTRATOR_RAM_TYPE)) {
|
|
212
214
|
config.CONCENTRATOR_RAM_TYPE = DEFAULT_STACK_CONFIG.CONCENTRATOR_RAM_TYPE;
|
|
213
215
|
logger_1.logger.error(`[STACK CONFIG] Invalid CONCENTRATOR_RAM_TYPE, using default.`, NS);
|
|
214
216
|
}
|
|
215
|
-
if (!inRange(config.CONCENTRATOR_MIN_TIME, 1, 60) ||
|
|
217
|
+
if (!inRange(config.CONCENTRATOR_MIN_TIME, 1, 60) || config.CONCENTRATOR_MIN_TIME >= config.CONCENTRATOR_MAX_TIME) {
|
|
216
218
|
config.CONCENTRATOR_MIN_TIME = DEFAULT_STACK_CONFIG.CONCENTRATOR_MIN_TIME;
|
|
217
219
|
logger_1.logger.error(`[STACK CONFIG] Invalid CONCENTRATOR_MIN_TIME, using default.`, NS);
|
|
218
220
|
}
|
|
219
|
-
if (!inRange(config.CONCENTRATOR_MAX_TIME, 30, 300) ||
|
|
221
|
+
if (!inRange(config.CONCENTRATOR_MAX_TIME, 30, 300) || config.CONCENTRATOR_MAX_TIME <= config.CONCENTRATOR_MIN_TIME) {
|
|
220
222
|
config.CONCENTRATOR_MAX_TIME = DEFAULT_STACK_CONFIG.CONCENTRATOR_MAX_TIME;
|
|
221
223
|
logger_1.logger.error(`[STACK CONFIG] Invalid CONCENTRATOR_MAX_TIME, using default.`, NS);
|
|
222
224
|
}
|
|
@@ -263,35 +265,35 @@ class EmberAdapter extends __1.Adapter {
|
|
|
263
265
|
// to be extra careful, should clear network cache upon receiving this.
|
|
264
266
|
this.clearNetworkCache();
|
|
265
267
|
switch (status) {
|
|
266
|
-
case
|
|
268
|
+
case enums_1.SLStatus.NETWORK_UP: {
|
|
267
269
|
this.oneWaitress.resolveEvent(oneWaitress_1.OneWaitressEvents.STACK_STATUS_NETWORK_UP);
|
|
268
270
|
logger_1.logger.info(`[STACK STATUS] Network up.`, NS);
|
|
269
271
|
break;
|
|
270
272
|
}
|
|
271
|
-
case
|
|
273
|
+
case enums_1.SLStatus.NETWORK_DOWN: {
|
|
272
274
|
this.oneWaitress.resolveEvent(oneWaitress_1.OneWaitressEvents.STACK_STATUS_NETWORK_DOWN);
|
|
273
275
|
logger_1.logger.info(`[STACK STATUS] Network down.`, NS);
|
|
274
276
|
break;
|
|
275
277
|
}
|
|
276
|
-
case
|
|
278
|
+
case enums_1.SLStatus.ZIGBEE_NETWORK_OPENED: {
|
|
277
279
|
this.oneWaitress.resolveEvent(oneWaitress_1.OneWaitressEvents.STACK_STATUS_NETWORK_OPENED);
|
|
278
280
|
logger_1.logger.info(`[STACK STATUS] Network opened.`, NS);
|
|
279
281
|
break;
|
|
280
282
|
}
|
|
281
|
-
case
|
|
283
|
+
case enums_1.SLStatus.ZIGBEE_NETWORK_CLOSED: {
|
|
282
284
|
this.oneWaitress.resolveEvent(oneWaitress_1.OneWaitressEvents.STACK_STATUS_NETWORK_CLOSED);
|
|
283
285
|
logger_1.logger.info(`[STACK STATUS] Network closed.`, NS);
|
|
284
286
|
break;
|
|
285
287
|
}
|
|
286
|
-
case
|
|
288
|
+
case enums_1.SLStatus.ZIGBEE_CHANNEL_CHANGED: {
|
|
287
289
|
this.oneWaitress.resolveEvent(oneWaitress_1.OneWaitressEvents.STACK_STATUS_CHANNEL_CHANGED);
|
|
288
290
|
// invalidate cache
|
|
289
|
-
this.networkCache.parameters.radioChannel =
|
|
291
|
+
this.networkCache.parameters.radioChannel = consts_1.INVALID_RADIO_CHANNEL;
|
|
290
292
|
logger_1.logger.info(`[STACK STATUS] Channel changed.`, NS);
|
|
291
293
|
break;
|
|
292
294
|
}
|
|
293
295
|
default: {
|
|
294
|
-
logger_1.logger.debug(`[STACK STATUS] ${
|
|
296
|
+
logger_1.logger.debug(`[STACK STATUS] ${enums_1.SLStatus[status]}.`, NS);
|
|
295
297
|
break;
|
|
296
298
|
}
|
|
297
299
|
}
|
|
@@ -307,16 +309,16 @@ class EmberAdapter extends __1.Adapter {
|
|
|
307
309
|
* @param status
|
|
308
310
|
*/
|
|
309
311
|
async onMessageSent(status, type, indexOrDestination, apsFrame, messageTag) {
|
|
310
|
-
if (status ===
|
|
312
|
+
if (status === enums_1.SLStatus.ZIGBEE_DELIVERY_FAILED) {
|
|
311
313
|
// no ACK was received from the destination
|
|
312
314
|
switch (type) {
|
|
313
|
-
case
|
|
314
|
-
case
|
|
315
|
-
case
|
|
316
|
-
case
|
|
315
|
+
case enums_1.EmberOutgoingMessageType.BROADCAST:
|
|
316
|
+
case enums_1.EmberOutgoingMessageType.BROADCAST_WITH_ALIAS:
|
|
317
|
+
case enums_1.EmberOutgoingMessageType.MULTICAST:
|
|
318
|
+
case enums_1.EmberOutgoingMessageType.MULTICAST_WITH_ALIAS: {
|
|
317
319
|
// BC/MC not checking for message sent, avoid unnecessary waitress lookups
|
|
318
|
-
logger_1.logger.error(`Delivery of ${
|
|
319
|
-
|
|
320
|
+
logger_1.logger.error(`Delivery of ${enums_1.EmberOutgoingMessageType[type]} failed for "${indexOrDestination}" ` +
|
|
321
|
+
`[apsFrame=${JSON.stringify(apsFrame)} messageTag=${messageTag}]`, NS);
|
|
320
322
|
break;
|
|
321
323
|
}
|
|
322
324
|
default: {
|
|
@@ -326,9 +328,11 @@ class EmberAdapter extends __1.Adapter {
|
|
|
326
328
|
}
|
|
327
329
|
}
|
|
328
330
|
}
|
|
329
|
-
else if (status ===
|
|
330
|
-
if (type ===
|
|
331
|
-
apsFrame.
|
|
331
|
+
else if (status === enums_1.SLStatus.OK) {
|
|
332
|
+
if (type === enums_1.EmberOutgoingMessageType.MULTICAST &&
|
|
333
|
+
apsFrame.destinationEndpoint === 0xff &&
|
|
334
|
+
apsFrame.groupId < consts_1.EMBER_MIN_BROADCAST_ADDRESS &&
|
|
335
|
+
!this.multicastTable.includes(apsFrame.groupId)) {
|
|
332
336
|
// workaround for devices using multicast for state update (coordinator passthrough)
|
|
333
337
|
const tableIdx = this.multicastTable.length;
|
|
334
338
|
const multicastEntry = {
|
|
@@ -338,22 +342,20 @@ class EmberAdapter extends __1.Adapter {
|
|
|
338
342
|
};
|
|
339
343
|
// set immediately to avoid potential race
|
|
340
344
|
this.multicastTable.push(multicastEntry.multicastId);
|
|
341
|
-
|
|
342
|
-
this.
|
|
343
|
-
const status =
|
|
344
|
-
if (status !==
|
|
345
|
-
|
|
346
|
-
return status;
|
|
345
|
+
try {
|
|
346
|
+
await this.queue.execute(async () => {
|
|
347
|
+
const status = await this.ezsp.ezspSetMulticastTableEntry(tableIdx, multicastEntry);
|
|
348
|
+
if (status !== enums_1.SLStatus.OK) {
|
|
349
|
+
throw new Error(`Failed to register group "${multicastEntry.multicastId}" in multicast table with status=${enums_1.SLStatus[status]}.`);
|
|
347
350
|
}
|
|
348
351
|
logger_1.logger.debug(`Registered multicast table entry (${tableIdx}): ${JSON.stringify(multicastEntry)}.`, NS);
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
});
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
catch (error) {
|
|
355
|
+
// remove to allow retry on next occurrence
|
|
356
|
+
this.multicastTable.splice(tableIdx, 1);
|
|
357
|
+
throw error;
|
|
358
|
+
}
|
|
357
359
|
}
|
|
358
360
|
}
|
|
359
361
|
// shouldn't be any other status
|
|
@@ -373,13 +375,13 @@ class EmberAdapter extends __1.Adapter {
|
|
|
373
375
|
if (apsFrame.clusterId === Zdo.ClusterId.NETWORK_ADDRESS_RESPONSE) {
|
|
374
376
|
this.emit(events_1.Events.networkAddress, {
|
|
375
377
|
networkAddress: payload.nwkAddress,
|
|
376
|
-
ieeeAddr: payload.eui64
|
|
378
|
+
ieeeAddr: payload.eui64,
|
|
377
379
|
});
|
|
378
380
|
}
|
|
379
381
|
else if (apsFrame.clusterId === Zdo.ClusterId.END_DEVICE_ANNOUNCE) {
|
|
380
382
|
this.emit(events_1.Events.deviceAnnounce, {
|
|
381
383
|
networkAddress: payload.nwkAddress,
|
|
382
|
-
ieeeAddr: payload.eui64
|
|
384
|
+
ieeeAddr: payload.eui64,
|
|
383
385
|
});
|
|
384
386
|
}
|
|
385
387
|
}
|
|
@@ -405,7 +407,7 @@ class EmberAdapter extends __1.Adapter {
|
|
|
405
407
|
endpoint: apsFrame.sourceEndpoint,
|
|
406
408
|
linkquality: lastHopLqi,
|
|
407
409
|
groupID: apsFrame.groupId,
|
|
408
|
-
wasBroadcast:
|
|
410
|
+
wasBroadcast: type === enums_1.EmberIncomingMessageType.BROADCAST || type === enums_1.EmberIncomingMessageType.BROADCAST_LOOPBACK,
|
|
409
411
|
destinationEndpoint: apsFrame.destinationEndpoint,
|
|
410
412
|
};
|
|
411
413
|
this.oneWaitress.resolveZCL(payload);
|
|
@@ -490,7 +492,7 @@ class EmberAdapter extends __1.Adapter {
|
|
|
490
492
|
* @param parentOfNewNodeId
|
|
491
493
|
*/
|
|
492
494
|
async onTrustCenterJoin(newNodeId, newNodeEui64, status, policyDecision, parentOfNewNodeId) {
|
|
493
|
-
if (status ===
|
|
495
|
+
if (status === enums_1.EmberDeviceUpdate.DEVICE_LEFT) {
|
|
494
496
|
const payload = {
|
|
495
497
|
networkAddress: newNodeId,
|
|
496
498
|
ieeeAddr: newNodeEui64,
|
|
@@ -498,7 +500,7 @@ class EmberAdapter extends __1.Adapter {
|
|
|
498
500
|
this.emit(events_1.Events.deviceLeave, payload);
|
|
499
501
|
}
|
|
500
502
|
else {
|
|
501
|
-
if (policyDecision !==
|
|
503
|
+
if (policyDecision !== enums_1.EmberJoinDecision.DENY_JOIN) {
|
|
502
504
|
const payload = {
|
|
503
505
|
networkAddress: newNodeId,
|
|
504
506
|
ieeeAddr: newNodeEui64,
|
|
@@ -506,15 +508,11 @@ class EmberAdapter extends __1.Adapter {
|
|
|
506
508
|
// set workaround manuf code if necessary, or revert to default if previous joined device required workaround and new one does not
|
|
507
509
|
const joinManufCode = WORKAROUND_JOIN_MANUF_IEEE_PREFIX_TO_CODE[newNodeEui64.substring(0, 8)] ?? DEFAULT_MANUFACTURER_CODE;
|
|
508
510
|
if (this.manufacturerCode !== joinManufCode) {
|
|
509
|
-
await
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
this.emit(events_1.Events.deviceJoined, payload);
|
|
515
|
-
resolve();
|
|
516
|
-
return enums_2.SLStatus.OK;
|
|
517
|
-
}, reject, true);
|
|
511
|
+
await this.queue.execute(async () => {
|
|
512
|
+
logger_1.logger.debug(`[WORKAROUND] Setting coordinator manufacturer code to ${Zcl.ManufacturerCode[joinManufCode]}.`, NS);
|
|
513
|
+
await this.ezsp.ezspSetManufacturerCode(joinManufCode);
|
|
514
|
+
this.manufacturerCode = joinManufCode;
|
|
515
|
+
this.emit(events_1.Events.deviceJoined, payload);
|
|
518
516
|
});
|
|
519
517
|
}
|
|
520
518
|
else {
|
|
@@ -527,21 +525,18 @@ class EmberAdapter extends __1.Adapter {
|
|
|
527
525
|
}
|
|
528
526
|
}
|
|
529
527
|
async watchdogCounters() {
|
|
530
|
-
await
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
logger_1.logger.info(`[ASH COUNTERS] ${ashCounters.join(',')}`, NS);
|
|
537
|
-
resolve();
|
|
538
|
-
return enums_2.SLStatus.OK;
|
|
539
|
-
}, reject);
|
|
528
|
+
await this.queue.execute(async () => {
|
|
529
|
+
// listed as per EmberCounterType
|
|
530
|
+
const ncpCounters = await this.ezsp.ezspReadAndClearCounters();
|
|
531
|
+
logger_1.logger.info(`[NCP COUNTERS] ${ncpCounters.join(',')}`, NS);
|
|
532
|
+
const ashCounters = this.ezsp.ash.readAndClearCounters();
|
|
533
|
+
logger_1.logger.info(`[ASH COUNTERS] ${ashCounters.join(',')}`, NS);
|
|
540
534
|
});
|
|
541
535
|
}
|
|
542
536
|
initVariables() {
|
|
543
537
|
this.ezsp.removeAllListeners(ezsp_1.EzspEvents.NCP_NEEDS_RESET_AND_INIT);
|
|
544
538
|
clearInterval(this.watchdogCountersHandle);
|
|
539
|
+
this.queue.clear();
|
|
545
540
|
this.zdoRequestSequence = 0; // start at 1
|
|
546
541
|
this.zdoRequestRadius = 255;
|
|
547
542
|
this.interpanLock = false;
|
|
@@ -555,49 +550,50 @@ class EmberAdapter extends __1.Adapter {
|
|
|
555
550
|
* This is called by start and on internal reset.
|
|
556
551
|
*/
|
|
557
552
|
async initEzsp() {
|
|
558
|
-
let result =
|
|
553
|
+
let result = 'resumed';
|
|
559
554
|
// NOTE: something deep in this call can throw too
|
|
560
|
-
const startResult =
|
|
561
|
-
if (startResult !==
|
|
562
|
-
throw new Error(`Failed to start EZSP layer with status=${
|
|
555
|
+
const startResult = await this.ezsp.start();
|
|
556
|
+
if (startResult !== enums_1.EzspStatus.SUCCESS) {
|
|
557
|
+
throw new Error(`Failed to start EZSP layer with status=${enums_1.EzspStatus[startResult]}.`);
|
|
563
558
|
}
|
|
564
559
|
// call before any other command, else fails
|
|
565
560
|
await this.emberVersion();
|
|
561
|
+
/** The address cache needs to be initialized and used with the source routing code for the trust center to operate properly. */
|
|
562
|
+
await this.emberSetEzspConfigValue(enums_2.EzspConfigId.TRUST_CENTER_ADDRESS_CACHE_SIZE, TRUST_CENTER_ADDRESS_CACHE_SIZE);
|
|
566
563
|
/** MAC indirect timeout should be 7.68 secs (STACK_PROFILE_ZIGBEE_PRO) */
|
|
567
|
-
await this.emberSetEzspConfigValue(
|
|
564
|
+
await this.emberSetEzspConfigValue(enums_2.EzspConfigId.INDIRECT_TRANSMISSION_TIMEOUT, 7680);
|
|
568
565
|
/** Max hops should be 2 * nwkMaxDepth, where nwkMaxDepth is 15 (STACK_PROFILE_ZIGBEE_PRO) */
|
|
569
|
-
await this.emberSetEzspConfigValue(
|
|
570
|
-
await this.emberSetEzspConfigValue(
|
|
566
|
+
await this.emberSetEzspConfigValue(enums_2.EzspConfigId.MAX_HOPS, 30);
|
|
567
|
+
await this.emberSetEzspConfigValue(enums_2.EzspConfigId.SUPPORTED_NETWORKS, 1);
|
|
571
568
|
// allow other devices to modify the binding table
|
|
572
|
-
await this.emberSetEzspPolicy(
|
|
569
|
+
await this.emberSetEzspPolicy(enums_2.EzspPolicyId.BINDING_MODIFICATION_POLICY, enums_2.EzspDecisionId.CHECK_BINDING_MODIFICATIONS_ARE_VALID_ENDPOINT_CLUSTERS);
|
|
573
570
|
// return message tag only in ezspMessageSentHandler()
|
|
574
|
-
await this.emberSetEzspPolicy(
|
|
575
|
-
await this.emberSetEzspValue(
|
|
571
|
+
await this.emberSetEzspPolicy(enums_2.EzspPolicyId.MESSAGE_CONTENTS_IN_CALLBACK_POLICY, enums_2.EzspDecisionId.MESSAGE_TAG_ONLY_IN_CALLBACK);
|
|
572
|
+
await this.emberSetEzspValue(enums_2.EzspValueId.TRANSIENT_DEVICE_TIMEOUT, 2, (0, math_1.lowHighBytes)(this.stackConfig.TRANSIENT_DEVICE_TIMEOUT));
|
|
576
573
|
await this.ezsp.ezspSetManufacturerCode(this.manufacturerCode);
|
|
577
574
|
// network security init
|
|
578
|
-
await this.emberSetEzspConfigValue(
|
|
579
|
-
await this.emberSetEzspConfigValue(
|
|
575
|
+
await this.emberSetEzspConfigValue(enums_2.EzspConfigId.STACK_PROFILE, consts_1.STACK_PROFILE_ZIGBEE_PRO);
|
|
576
|
+
await this.emberSetEzspConfigValue(enums_2.EzspConfigId.SECURITY_LEVEL, consts_1.SECURITY_LEVEL_Z3);
|
|
580
577
|
// common configs
|
|
581
|
-
await this.emberSetEzspConfigValue(
|
|
582
|
-
await this.emberSetEzspConfigValue(
|
|
583
|
-
await this.emberSetEzspConfigValue(
|
|
578
|
+
await this.emberSetEzspConfigValue(enums_2.EzspConfigId.MAX_END_DEVICE_CHILDREN, this.stackConfig.MAX_END_DEVICE_CHILDREN);
|
|
579
|
+
await this.emberSetEzspConfigValue(enums_2.EzspConfigId.END_DEVICE_POLL_TIMEOUT, this.stackConfig.END_DEVICE_POLL_TIMEOUT);
|
|
580
|
+
await this.emberSetEzspConfigValue(enums_2.EzspConfigId.TRANSIENT_KEY_TIMEOUT_S, this.stackConfig.TRANSIENT_KEY_TIMEOUT_S);
|
|
584
581
|
// WARNING: From here on EZSP commands that affect memory allocation on the NCP should no longer be called (like resizing tables)
|
|
585
582
|
await this.registerFixedEndpoints();
|
|
586
583
|
this.clearNetworkCache();
|
|
587
|
-
result =
|
|
584
|
+
result = await this.initTrustCenter();
|
|
588
585
|
// after network UP, as per SDK, ensures clean slate
|
|
589
586
|
await this.initNCPConcentrator();
|
|
590
587
|
// populate network cache info
|
|
591
|
-
const [status, , parameters] =
|
|
592
|
-
if (status !==
|
|
593
|
-
throw new Error(`Failed to get network parameters with status=${
|
|
588
|
+
const [status, , parameters] = await this.ezsp.ezspGetNetworkParameters();
|
|
589
|
+
if (status !== enums_1.SLStatus.OK) {
|
|
590
|
+
throw new Error(`Failed to get network parameters with status=${enums_1.SLStatus[status]}.`);
|
|
594
591
|
}
|
|
595
592
|
this.networkCache.parameters = parameters;
|
|
596
|
-
this.networkCache.status =
|
|
597
|
-
this.networkCache.eui64 =
|
|
593
|
+
this.networkCache.status = await this.ezsp.ezspNetworkState();
|
|
594
|
+
this.networkCache.eui64 = await this.ezsp.ezspGetEui64();
|
|
598
595
|
logger_1.logger.debug(`[INIT] Network Ready! ${JSON.stringify(this.networkCache)}`, NS);
|
|
599
596
|
this.watchdogCountersHandle = setInterval(this.watchdogCounters.bind(this), WATCHDOG_COUNTERS_FEED_INTERVAL);
|
|
600
|
-
this.requestQueue.startDispatching();
|
|
601
597
|
return result;
|
|
602
598
|
}
|
|
603
599
|
/**
|
|
@@ -615,11 +611,11 @@ class EmberAdapter extends __1.Adapter {
|
|
|
615
611
|
* (through a target node that is neither the trust center nor one of its neighboring routers.)
|
|
616
612
|
*/
|
|
617
613
|
async initNCPConcentrator() {
|
|
618
|
-
const status =
|
|
619
|
-
if (status !==
|
|
620
|
-
throw new Error(`[CONCENTRATOR] Failed to set concentrator with status=${
|
|
614
|
+
const status = await this.ezsp.ezspSetConcentrator(true, this.stackConfig.CONCENTRATOR_RAM_TYPE === 'low' ? consts_1.EMBER_LOW_RAM_CONCENTRATOR : consts_1.EMBER_HIGH_RAM_CONCENTRATOR, this.stackConfig.CONCENTRATOR_MIN_TIME, this.stackConfig.CONCENTRATOR_MAX_TIME, this.stackConfig.CONCENTRATOR_ROUTE_ERROR_THRESHOLD, this.stackConfig.CONCENTRATOR_DELIVERY_FAILURE_THRESHOLD, this.stackConfig.CONCENTRATOR_MAX_HOPS);
|
|
615
|
+
if (status !== enums_1.SLStatus.OK) {
|
|
616
|
+
throw new Error(`[CONCENTRATOR] Failed to set concentrator with status=${enums_1.SLStatus[status]}.`);
|
|
621
617
|
}
|
|
622
|
-
const remainTilMTORR =
|
|
618
|
+
const remainTilMTORR = await this.ezsp.ezspSetSourceRouteDiscoveryMode(enums_1.EmberSourceRouteDiscoveryMode.RESCHEDULE);
|
|
623
619
|
logger_1.logger.info(`[CONCENTRATOR] Started source route discovery. ${remainTilMTORR}ms until next broadcast.`, NS);
|
|
624
620
|
}
|
|
625
621
|
/**
|
|
@@ -631,18 +627,18 @@ class EmberAdapter extends __1.Adapter {
|
|
|
631
627
|
logger_1.logger.debug(`Multi-network not currently supported. Skipping endpoint ${JSON.stringify(ep)}.`, NS);
|
|
632
628
|
continue;
|
|
633
629
|
}
|
|
634
|
-
const [epStatus
|
|
630
|
+
const [epStatus] = await this.ezsp.ezspGetEndpointFlags(ep.endpoint);
|
|
635
631
|
// endpoint not already registered
|
|
636
|
-
if (epStatus !==
|
|
632
|
+
if (epStatus !== enums_1.SLStatus.OK) {
|
|
637
633
|
// check to see if ezspAddEndpoint needs to be called
|
|
638
634
|
// if ezspInit is called without NCP reset, ezspAddEndpoint is not necessary and will return an error
|
|
639
|
-
const status =
|
|
640
|
-
ep.outClusterList.slice())
|
|
641
|
-
if (status ===
|
|
635
|
+
const status = await this.ezsp.ezspAddEndpoint(ep.endpoint, ep.profileId, ep.deviceId, ep.deviceVersion, ep.inClusterList.slice(), // copy
|
|
636
|
+
ep.outClusterList.slice());
|
|
637
|
+
if (status === enums_1.SLStatus.OK) {
|
|
642
638
|
logger_1.logger.debug(`Registered endpoint '${ep.endpoint}'.`, NS);
|
|
643
639
|
}
|
|
644
640
|
else {
|
|
645
|
-
throw new Error(`Failed to register endpoint "${ep.endpoint}" with status=${
|
|
641
|
+
throw new Error(`Failed to register endpoint "${ep.endpoint}" with status=${enums_1.SLStatus[status]}.`);
|
|
646
642
|
}
|
|
647
643
|
}
|
|
648
644
|
else {
|
|
@@ -654,9 +650,9 @@ class EmberAdapter extends __1.Adapter {
|
|
|
654
650
|
endpoint: ep.endpoint,
|
|
655
651
|
networkIndex: ep.networkIndex,
|
|
656
652
|
};
|
|
657
|
-
const status =
|
|
658
|
-
if (status !==
|
|
659
|
-
throw new Error(`Failed to register group "${multicastId}" in multicast table with status=${
|
|
653
|
+
const status = await this.ezsp.ezspSetMulticastTableEntry(this.multicastTable.length, multicastEntry);
|
|
654
|
+
if (status !== enums_1.SLStatus.OK) {
|
|
655
|
+
throw new Error(`Failed to register group "${multicastId}" in multicast table with status=${enums_1.SLStatus[status]}.`);
|
|
660
656
|
}
|
|
661
657
|
logger_1.logger.debug(`Registered multicast table entry (${this.multicastTable.length}): ${JSON.stringify(multicastEntry)}.`, NS);
|
|
662
658
|
this.multicastTable.push(multicastEntry.multicastId);
|
|
@@ -670,46 +666,48 @@ class EmberAdapter extends __1.Adapter {
|
|
|
670
666
|
async initTrustCenter() {
|
|
671
667
|
// init TC policies
|
|
672
668
|
{
|
|
673
|
-
let status =
|
|
674
|
-
if (status !==
|
|
675
|
-
throw new Error(`[INIT TC] Failed to set EzspPolicyId TC_KEY_REQUEST_POLICY to ALLOW_TC_KEY_REQUESTS_AND_SEND_CURRENT_KEY `
|
|
676
|
-
|
|
669
|
+
let status = await this.emberSetEzspPolicy(enums_2.EzspPolicyId.TC_KEY_REQUEST_POLICY, enums_2.EzspDecisionId.ALLOW_TC_KEY_REQUESTS_AND_SEND_CURRENT_KEY);
|
|
670
|
+
if (status !== enums_1.SLStatus.OK) {
|
|
671
|
+
throw new Error(`[INIT TC] Failed to set EzspPolicyId TC_KEY_REQUEST_POLICY to ALLOW_TC_KEY_REQUESTS_AND_SEND_CURRENT_KEY ` +
|
|
672
|
+
`with status=${enums_1.SLStatus[status]}.`);
|
|
677
673
|
}
|
|
678
|
-
const appKeyRequestsPolicy = ALLOW_APP_KEY_REQUESTS ?
|
|
679
|
-
status = await this.emberSetEzspPolicy(
|
|
680
|
-
if (status !==
|
|
681
|
-
throw new Error(`[INIT TC] Failed to set EzspPolicyId APP_KEY_REQUEST_POLICY to ${
|
|
682
|
-
|
|
674
|
+
const appKeyRequestsPolicy = ALLOW_APP_KEY_REQUESTS ? enums_2.EzspDecisionId.ALLOW_APP_KEY_REQUESTS : enums_2.EzspDecisionId.DENY_APP_KEY_REQUESTS;
|
|
675
|
+
status = await this.emberSetEzspPolicy(enums_2.EzspPolicyId.APP_KEY_REQUEST_POLICY, appKeyRequestsPolicy);
|
|
676
|
+
if (status !== enums_1.SLStatus.OK) {
|
|
677
|
+
throw new Error(`[INIT TC] Failed to set EzspPolicyId APP_KEY_REQUEST_POLICY to ${enums_2.EzspDecisionId[appKeyRequestsPolicy]} ` +
|
|
678
|
+
`with status=${enums_1.SLStatus[status]}.`);
|
|
683
679
|
}
|
|
684
|
-
status =
|
|
685
|
-
if (status !==
|
|
686
|
-
throw new Error(`[INIT TC] Failed to set join policy to USE_PRECONFIGURED_KEY with status=${
|
|
680
|
+
status = await this.emberSetJoinPolicy(enums_1.EmberJoinDecision.USE_PRECONFIGURED_KEY);
|
|
681
|
+
if (status !== enums_1.SLStatus.OK) {
|
|
682
|
+
throw new Error(`[INIT TC] Failed to set join policy to USE_PRECONFIGURED_KEY with status=${enums_1.SLStatus[status]}.`);
|
|
687
683
|
}
|
|
688
684
|
}
|
|
689
685
|
const configNetworkKey = Buffer.from(this.networkOptions.networkKey);
|
|
690
686
|
const networkInitStruct = {
|
|
691
|
-
bitmask:
|
|
687
|
+
bitmask: enums_1.EmberNetworkInitBitmask.PARENT_INFO_IN_TOKEN | enums_1.EmberNetworkInitBitmask.END_DEVICE_REJOIN_ON_REBOOT,
|
|
692
688
|
};
|
|
693
|
-
const initStatus =
|
|
694
|
-
logger_1.logger.debug(`[INIT TC] Network init status=${
|
|
695
|
-
if (
|
|
696
|
-
throw new Error(`[INIT TC] Failed network init request with status=${
|
|
689
|
+
const initStatus = await this.ezsp.ezspNetworkInit(networkInitStruct);
|
|
690
|
+
logger_1.logger.debug(`[INIT TC] Network init status=${enums_1.SLStatus[initStatus]}.`, NS);
|
|
691
|
+
if (initStatus !== enums_1.SLStatus.OK && initStatus !== enums_1.SLStatus.NOT_JOINED) {
|
|
692
|
+
throw new Error(`[INIT TC] Failed network init request with status=${enums_1.SLStatus[initStatus]}.`);
|
|
697
693
|
}
|
|
698
694
|
let action = NetworkInitAction.DONE;
|
|
699
|
-
if (initStatus ===
|
|
695
|
+
if (initStatus === enums_1.SLStatus.OK) {
|
|
700
696
|
// network
|
|
701
697
|
await this.oneWaitress.startWaitingForEvent({ eventName: oneWaitress_1.OneWaitressEvents.STACK_STATUS_NETWORK_UP }, DEFAULT_NETWORK_REQUEST_TIMEOUT, '[INIT TC] Network init');
|
|
702
|
-
const [npStatus, nodeType, netParams] =
|
|
703
|
-
logger_1.logger.debug(`[INIT TC] Current adapter network: nodeType=${
|
|
704
|
-
if (
|
|
705
|
-
|
|
698
|
+
const [npStatus, nodeType, netParams] = await this.ezsp.ezspGetNetworkParameters();
|
|
699
|
+
logger_1.logger.debug(`[INIT TC] Current adapter network: nodeType=${enums_1.EmberNodeType[nodeType]} params=${JSON.stringify(netParams)}`, NS);
|
|
700
|
+
if (npStatus === enums_1.SLStatus.OK &&
|
|
701
|
+
nodeType === enums_1.EmberNodeType.COORDINATOR &&
|
|
702
|
+
this.networkOptions.panID === netParams.panId &&
|
|
703
|
+
(0, es6_1.default)(this.networkOptions.extendedPanID, netParams.extendedPanId)) {
|
|
706
704
|
// config matches adapter so far, no error, we can check the network key
|
|
707
705
|
const context = (0, initters_1.initSecurityManagerContext)();
|
|
708
|
-
context.coreKeyType =
|
|
706
|
+
context.coreKeyType = enums_1.SecManKeyType.NETWORK;
|
|
709
707
|
context.keyIndex = 0;
|
|
710
|
-
const [nkStatus, networkKey] =
|
|
711
|
-
if (nkStatus !==
|
|
712
|
-
throw new Error(`[BACKUP] Failed to export Network Key with status=${
|
|
708
|
+
const [nkStatus, networkKey] = await this.ezsp.ezspExportKey(context);
|
|
709
|
+
if (nkStatus !== enums_1.SLStatus.OK) {
|
|
710
|
+
throw new Error(`[BACKUP] Failed to export Network Key with status=${enums_1.SLStatus[nkStatus]}.`);
|
|
713
711
|
}
|
|
714
712
|
// config doesn't match adapter anymore
|
|
715
713
|
if (!networkKey.contents.equals(configNetworkKey)) {
|
|
@@ -722,9 +720,9 @@ class EmberAdapter extends __1.Adapter {
|
|
|
722
720
|
}
|
|
723
721
|
if (action === NetworkInitAction.LEAVE) {
|
|
724
722
|
logger_1.logger.info(`[INIT TC] Adapter network does not match config. Leaving network...`, NS);
|
|
725
|
-
const leaveStatus =
|
|
726
|
-
if (leaveStatus !==
|
|
727
|
-
throw new Error(`[INIT TC] Failed leave network request with status=${
|
|
723
|
+
const leaveStatus = await this.ezsp.ezspLeaveNetwork();
|
|
724
|
+
if (leaveStatus !== enums_1.SLStatus.OK) {
|
|
725
|
+
throw new Error(`[INIT TC] Failed leave network request with status=${enums_1.SLStatus[leaveStatus]}.`);
|
|
728
726
|
}
|
|
729
727
|
await this.oneWaitress.startWaitingForEvent({ eventName: oneWaitress_1.OneWaitressEvents.STACK_STATUS_NETWORK_DOWN }, DEFAULT_NETWORK_REQUEST_TIMEOUT, '[INIT TC] Leave network');
|
|
730
728
|
await (0, utils_1.Wait)(200); // settle down
|
|
@@ -732,13 +730,13 @@ class EmberAdapter extends __1.Adapter {
|
|
|
732
730
|
}
|
|
733
731
|
}
|
|
734
732
|
const backup = this.getStoredBackup();
|
|
735
|
-
if (
|
|
733
|
+
if (initStatus === enums_1.SLStatus.NOT_JOINED || action === NetworkInitAction.LEFT) {
|
|
736
734
|
// no network
|
|
737
735
|
if (backup != null) {
|
|
738
|
-
if (
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
736
|
+
if (this.networkOptions.panID === backup.networkOptions.panId &&
|
|
737
|
+
Buffer.from(this.networkOptions.extendedPanID).equals(backup.networkOptions.extendedPanId) &&
|
|
738
|
+
this.networkOptions.channelList.includes(backup.logicalChannel) &&
|
|
739
|
+
configNetworkKey.equals(backup.networkOptions.networkKey)) {
|
|
742
740
|
// config matches backup
|
|
743
741
|
action = NetworkInitAction.FORM_BACKUP;
|
|
744
742
|
}
|
|
@@ -762,7 +760,7 @@ class EmberAdapter extends __1.Adapter {
|
|
|
762
760
|
const keyList = backup.devices.map((device) => {
|
|
763
761
|
const octets = Array.from(device.ieeeAddress.reverse());
|
|
764
762
|
return {
|
|
765
|
-
deviceEui64: `0x${octets.map(octet => octet.toString(16).padStart(2, '0')).join('')}`,
|
|
763
|
+
deviceEui64: `0x${octets.map((octet) => octet.toString(16).padStart(2, '0')).join('')}`,
|
|
766
764
|
key: { contents: device.linkKey.key },
|
|
767
765
|
outgoingFrameCounter: device.linkKey.txCounter,
|
|
768
766
|
incomingFrameCounter: device.linkKey.rxCounter,
|
|
@@ -770,13 +768,13 @@ class EmberAdapter extends __1.Adapter {
|
|
|
770
768
|
});
|
|
771
769
|
// before forming
|
|
772
770
|
await this.importLinkKeys(keyList);
|
|
773
|
-
await this.formNetwork(true
|
|
771
|
+
await this.formNetwork(true /*from backup*/, backup.networkOptions.networkKey, backup.networkKeyInfo.sequenceNumber, backup.networkOptions.panId, Array.from(backup.networkOptions.extendedPanId), backup.logicalChannel, backup.ezsp.hashed_tclk);
|
|
774
772
|
result = 'restored';
|
|
775
773
|
break;
|
|
776
774
|
}
|
|
777
775
|
case NetworkInitAction.FORM_CONFIG: {
|
|
778
776
|
logger_1.logger.info(`[INIT TC] Forming from config.`, NS);
|
|
779
|
-
await this.formNetwork(false
|
|
777
|
+
await this.formNetwork(false /*from config*/, configNetworkKey, 0, this.networkOptions.panID, this.networkOptions.extendedPanID, this.networkOptions.channelList[0], (0, crypto_1.randomBytes)(consts_2.EMBER_ENCRYPTION_KEY_SIZE));
|
|
780
778
|
result = 'reset';
|
|
781
779
|
break;
|
|
782
780
|
}
|
|
@@ -789,7 +787,7 @@ class EmberAdapter extends __1.Adapter {
|
|
|
789
787
|
}
|
|
790
788
|
}
|
|
791
789
|
// can't let frame counter wrap to zero (uint32_t), will force a broadcast after init if getting too close
|
|
792
|
-
if (backup != null &&
|
|
790
|
+
if (backup != null && backup.networkKeyInfo.frameCounter > 0xfeeeeeee) {
|
|
793
791
|
// XXX: while this remains a pretty low occurrence in most (small) networks,
|
|
794
792
|
// currently Z2M won't support the key update because of one-way config...
|
|
795
793
|
// need to investigate handling this properly
|
|
@@ -812,30 +810,32 @@ class EmberAdapter extends __1.Adapter {
|
|
|
812
810
|
*/
|
|
813
811
|
async formNetwork(fromBackup, networkKey, networkKeySequenceNumber, panId, extendedPanId, radioChannel, tcLinkKey) {
|
|
814
812
|
const state = {
|
|
815
|
-
bitmask:
|
|
816
|
-
|
|
817
|
-
|
|
813
|
+
bitmask: enums_1.EmberInitialSecurityBitmask.TRUST_CENTER_GLOBAL_LINK_KEY |
|
|
814
|
+
enums_1.EmberInitialSecurityBitmask.HAVE_PRECONFIGURED_KEY |
|
|
815
|
+
enums_1.EmberInitialSecurityBitmask.HAVE_NETWORK_KEY |
|
|
816
|
+
enums_1.EmberInitialSecurityBitmask.TRUST_CENTER_USES_HASHED_LINK_KEY |
|
|
817
|
+
enums_1.EmberInitialSecurityBitmask.REQUIRE_ENCRYPTED_KEY,
|
|
818
818
|
preconfiguredKey: { contents: tcLinkKey },
|
|
819
819
|
networkKey: { contents: networkKey },
|
|
820
820
|
networkKeySequenceNumber: networkKeySequenceNumber,
|
|
821
821
|
preconfiguredTrustCenterEui64: ZSpec.BLANK_EUI64,
|
|
822
822
|
};
|
|
823
823
|
if (fromBackup) {
|
|
824
|
-
state.bitmask |=
|
|
824
|
+
state.bitmask |= enums_1.EmberInitialSecurityBitmask.NO_FRAME_COUNTER_RESET;
|
|
825
825
|
}
|
|
826
|
-
let status =
|
|
827
|
-
if (status !==
|
|
828
|
-
throw new Error(`[INIT FORM] Failed to set initial security state with status=${
|
|
826
|
+
let status = await this.ezsp.ezspSetInitialSecurityState(state);
|
|
827
|
+
if (status !== enums_1.SLStatus.OK) {
|
|
828
|
+
throw new Error(`[INIT FORM] Failed to set initial security state with status=${enums_1.SLStatus[status]}.`);
|
|
829
829
|
}
|
|
830
|
-
const extended =
|
|
831
|
-
status =
|
|
832
|
-
if (status !==
|
|
833
|
-
throw new Error(`[INIT FORM] Failed to set extended security bitmask to ${extended} with status=${
|
|
830
|
+
const extended = enums_1.EmberExtendedSecurityBitmask.JOINER_GLOBAL_LINK_KEY | enums_1.EmberExtendedSecurityBitmask.NWK_LEAVE_REQUEST_NOT_ALLOWED;
|
|
831
|
+
status = await this.ezsp.ezspSetExtendedSecurityBitmask(extended);
|
|
832
|
+
if (status !== enums_1.SLStatus.OK) {
|
|
833
|
+
throw new Error(`[INIT FORM] Failed to set extended security bitmask to ${extended} with status=${enums_1.SLStatus[status]}.`);
|
|
834
834
|
}
|
|
835
835
|
if (!fromBackup) {
|
|
836
836
|
status = await this.ezsp.ezspClearKeyTable();
|
|
837
|
-
if (status !==
|
|
838
|
-
logger_1.logger.error(`[INIT FORM] Failed to clear key table with status=${
|
|
837
|
+
if (status !== enums_1.SLStatus.OK) {
|
|
838
|
+
logger_1.logger.error(`[INIT FORM] Failed to clear key table with status=${enums_1.SLStatus[status]}.`, NS);
|
|
839
839
|
}
|
|
840
840
|
}
|
|
841
841
|
const netParams = {
|
|
@@ -843,19 +843,19 @@ class EmberAdapter extends __1.Adapter {
|
|
|
843
843
|
extendedPanId,
|
|
844
844
|
radioTxPower: 5,
|
|
845
845
|
radioChannel,
|
|
846
|
-
joinMethod:
|
|
846
|
+
joinMethod: enums_1.EmberJoinMethod.MAC_ASSOCIATION,
|
|
847
847
|
nwkManagerId: ZSpec.COORDINATOR_ADDRESS,
|
|
848
848
|
nwkUpdateId: 0,
|
|
849
|
-
channels:
|
|
849
|
+
channels: consts_1.EMBER_ALL_802_15_4_CHANNELS_MASK,
|
|
850
850
|
};
|
|
851
851
|
logger_1.logger.info(`[INIT FORM] Forming new network with: ${JSON.stringify(netParams)}`, NS);
|
|
852
|
-
status =
|
|
853
|
-
if (status !==
|
|
854
|
-
throw new Error(`[INIT FORM] Failed form network request with status=${
|
|
852
|
+
status = await this.ezsp.ezspFormNetwork(netParams);
|
|
853
|
+
if (status !== enums_1.SLStatus.OK) {
|
|
854
|
+
throw new Error(`[INIT FORM] Failed form network request with status=${enums_1.SLStatus[status]}.`);
|
|
855
855
|
}
|
|
856
856
|
await this.oneWaitress.startWaitingForEvent({ eventName: oneWaitress_1.OneWaitressEvents.STACK_STATUS_NETWORK_UP }, DEFAULT_NETWORK_REQUEST_TIMEOUT, '[INIT FORM] Form network');
|
|
857
857
|
status = await this.ezsp.ezspStartWritingStackTokens();
|
|
858
|
-
logger_1.logger.debug(`[INIT FORM] Start writing stack tokens status=${
|
|
858
|
+
logger_1.logger.debug(`[INIT FORM] Start writing stack tokens status=${enums_1.SLStatus[status]}.`, NS);
|
|
859
859
|
logger_1.logger.info(`[INIT FORM] New network formed!`, NS);
|
|
860
860
|
}
|
|
861
861
|
/**
|
|
@@ -867,12 +867,12 @@ class EmberAdapter extends __1.Adapter {
|
|
|
867
867
|
}
|
|
868
868
|
let data;
|
|
869
869
|
try {
|
|
870
|
-
data = JSON.parse((
|
|
870
|
+
data = JSON.parse((0, fs_1.readFileSync)(this.backupPath).toString());
|
|
871
871
|
}
|
|
872
872
|
catch (error) {
|
|
873
873
|
throw new Error(`[BACKUP] Coordinator backup is corrupted.`);
|
|
874
874
|
}
|
|
875
|
-
if (data.metadata?.format ===
|
|
875
|
+
if (data.metadata?.format === 'zigpy/open-coordinator-backup' && data.metadata?.version) {
|
|
876
876
|
if (data.metadata?.version !== 1) {
|
|
877
877
|
throw new Error(`[BACKUP] Unsupported open coordinator backup version (version=${data.metadata?.version}).`);
|
|
878
878
|
}
|
|
@@ -896,9 +896,9 @@ class EmberAdapter extends __1.Adapter {
|
|
|
896
896
|
* @return List of keys data with AES hashed keys
|
|
897
897
|
*/
|
|
898
898
|
async exportLinkKeys() {
|
|
899
|
-
const [confStatus, keyTableSize] =
|
|
900
|
-
if (confStatus !==
|
|
901
|
-
throw new Error(`[BACKUP] Failed to retrieve key table size from NCP with status=${
|
|
899
|
+
const [confStatus, keyTableSize] = await this.ezsp.ezspGetConfigurationValue(enums_2.EzspConfigId.KEY_TABLE_SIZE);
|
|
900
|
+
if (confStatus !== enums_1.SLStatus.OK) {
|
|
901
|
+
throw new Error(`[BACKUP] Failed to retrieve key table size from NCP with status=${enums_1.SLStatus[confStatus]}.`);
|
|
902
902
|
}
|
|
903
903
|
let context;
|
|
904
904
|
let plaintextKey;
|
|
@@ -906,15 +906,15 @@ class EmberAdapter extends __1.Adapter {
|
|
|
906
906
|
let status;
|
|
907
907
|
const keyList = [];
|
|
908
908
|
for (let i = 0; i < keyTableSize; i++) {
|
|
909
|
-
[status, context, plaintextKey, apsKeyMeta] =
|
|
910
|
-
logger_1.logger.debug(`[BACKUP] Export link key at index ${i}, status=${
|
|
909
|
+
[status, context, plaintextKey, apsKeyMeta] = await this.ezsp.ezspExportLinkKeyByIndex(i);
|
|
910
|
+
logger_1.logger.debug(`[BACKUP] Export link key at index ${i}, status=${enums_1.SLStatus[status]}.`, NS);
|
|
911
911
|
// only include key if we could retrieve one at index and hash it properly
|
|
912
|
-
if (status ===
|
|
912
|
+
if (status === enums_1.SLStatus.OK) {
|
|
913
913
|
// Rather than give the real link key, the backup contains a hashed version of the key.
|
|
914
914
|
// This is done to prevent a compromise of the backup data from compromising the current link keys.
|
|
915
915
|
// This is per the Smart Energy spec.
|
|
916
|
-
const [hashStatus, hashedKey] =
|
|
917
|
-
if (hashStatus ===
|
|
916
|
+
const [hashStatus, hashedKey] = await this.emberAesHashSimple(plaintextKey.contents);
|
|
917
|
+
if (hashStatus === enums_1.SLStatus.OK) {
|
|
918
918
|
keyList.push({
|
|
919
919
|
deviceEui64: context.eui64,
|
|
920
920
|
key: { contents: hashedKey },
|
|
@@ -924,7 +924,7 @@ class EmberAdapter extends __1.Adapter {
|
|
|
924
924
|
}
|
|
925
925
|
else {
|
|
926
926
|
// this should never happen?
|
|
927
|
-
logger_1.logger.error(`[BACKUP] Failed to hash link key at index ${i} with status=${
|
|
927
|
+
logger_1.logger.error(`[BACKUP] Failed to hash link key at index ${i} with status=${enums_1.SLStatus[hashStatus]}. Omitting from backup.`, NS);
|
|
928
928
|
}
|
|
929
929
|
}
|
|
930
930
|
}
|
|
@@ -940,25 +940,27 @@ class EmberAdapter extends __1.Adapter {
|
|
|
940
940
|
if (!backupData?.length) {
|
|
941
941
|
return;
|
|
942
942
|
}
|
|
943
|
-
const [confStatus, keyTableSize] =
|
|
944
|
-
if (confStatus !==
|
|
945
|
-
throw new Error(`[BACKUP] Failed to retrieve key table size from NCP with status=${
|
|
943
|
+
const [confStatus, keyTableSize] = await this.ezsp.ezspGetConfigurationValue(enums_2.EzspConfigId.KEY_TABLE_SIZE);
|
|
944
|
+
if (confStatus !== enums_1.SLStatus.OK) {
|
|
945
|
+
throw new Error(`[BACKUP] Failed to retrieve key table size from NCP with status=${enums_1.SLStatus[confStatus]}.`);
|
|
946
946
|
}
|
|
947
947
|
if (backupData.length > keyTableSize) {
|
|
948
948
|
throw new Error(`[BACKUP] Current key table of ${keyTableSize} is too small to import backup of ${backupData.length}!`);
|
|
949
949
|
}
|
|
950
|
-
const networkStatus =
|
|
951
|
-
if (networkStatus !==
|
|
952
|
-
throw new Error(`[BACKUP] Cannot import TC data while network is up, networkStatus=${
|
|
950
|
+
const networkStatus = await this.emberNetworkState();
|
|
951
|
+
if (networkStatus !== enums_1.EmberNetworkStatus.NO_NETWORK) {
|
|
952
|
+
throw new Error(`[BACKUP] Cannot import TC data while network is up, networkStatus=${enums_1.EmberNetworkStatus[networkStatus]}.`);
|
|
953
953
|
}
|
|
954
954
|
let status;
|
|
955
955
|
for (let i = 0; i < keyTableSize; i++) {
|
|
956
956
|
// erase any key index not present in backup but available on the NCP
|
|
957
|
-
status =
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
957
|
+
status =
|
|
958
|
+
i >= backupData.length
|
|
959
|
+
? await this.ezsp.ezspEraseKeyTableEntry(i)
|
|
960
|
+
: await this.ezsp.ezspImportLinkKey(i, backupData[i].deviceEui64, backupData[i].key);
|
|
961
|
+
if (status !== enums_1.SLStatus.OK) {
|
|
962
|
+
throw new Error(`[BACKUP] Failed to ${i >= backupData.length ? 'erase' : 'set'} key table entry at index ${i} ` +
|
|
963
|
+
`with status=${enums_1.SLStatus[status]}`);
|
|
962
964
|
}
|
|
963
965
|
}
|
|
964
966
|
logger_1.logger.info(`[BACKUP] Imported ${backupData.length} keys.`, NS);
|
|
@@ -970,27 +972,21 @@ class EmberAdapter extends __1.Adapter {
|
|
|
970
972
|
* On the other hand, the more often this runs, the more secure the network is...
|
|
971
973
|
*/
|
|
972
974
|
async broadcastNetworkKeyUpdate() {
|
|
973
|
-
return
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
logger_1.logger.error(`[TRUST CENTER] Failed to broadcast network key switch with status=${enums_2.SLStatus[status]}.`, NS);
|
|
989
|
-
return status;
|
|
990
|
-
}
|
|
991
|
-
resolve();
|
|
992
|
-
return status;
|
|
993
|
-
}, reject);
|
|
975
|
+
return this.queue.execute(async () => {
|
|
976
|
+
logger_1.logger.warning(`[TRUST CENTER] Performing a network key update. This might take a while and disrupt normal operation.`, NS);
|
|
977
|
+
// zero-filled = let stack generate new random network key
|
|
978
|
+
let status = await this.ezsp.ezspBroadcastNextNetworkKey({ contents: Buffer.alloc(consts_2.EMBER_ENCRYPTION_KEY_SIZE) });
|
|
979
|
+
if (status !== enums_1.SLStatus.OK) {
|
|
980
|
+
throw new Error(`[TRUST CENTER] Failed to broadcast next network key with status=${enums_1.SLStatus[status]}.`);
|
|
981
|
+
}
|
|
982
|
+
// XXX: this will block other requests for a while, but should ensure the key propagates without interference?
|
|
983
|
+
// could also stop dispatching entirely and do this outside the queue if necessary/better
|
|
984
|
+
await (0, utils_1.Wait)(BROADCAST_NETWORK_KEY_SWITCH_WAIT_TIME);
|
|
985
|
+
status = await this.ezsp.ezspBroadcastNetworkKeySwitch();
|
|
986
|
+
if (status !== enums_1.SLStatus.OK) {
|
|
987
|
+
// XXX: Not sure how likely this is, but this is bad, probably should hard fail?
|
|
988
|
+
throw new Error(`[TRUST CENTER] Failed to broadcast network key switch with status=${enums_1.SLStatus[status]}.`);
|
|
989
|
+
}
|
|
994
990
|
});
|
|
995
991
|
}
|
|
996
992
|
/**
|
|
@@ -998,9 +994,9 @@ class EmberAdapter extends __1.Adapter {
|
|
|
998
994
|
* @param status
|
|
999
995
|
*/
|
|
1000
996
|
async onNcpNeedsResetAndInit(status) {
|
|
1001
|
-
logger_1.logger.error(`!!! ADAPTER FATAL ERROR reason=${
|
|
1002
|
-
if (this.
|
|
1003
|
-
logger_1.logger.info(`Request queue is high (${this.
|
|
997
|
+
logger_1.logger.error(`!!! ADAPTER FATAL ERROR reason=${enums_1.EzspStatus[status]}. !!!`, NS);
|
|
998
|
+
if (this.queue.count() > QUEUE_HIGH_COUNT) {
|
|
999
|
+
logger_1.logger.info(`Request queue is high (${this.queue.count()}), triggering full restart to prevent stressing the adapter.`, NS);
|
|
1004
1000
|
this.emit(events_1.Events.disconnected);
|
|
1005
1001
|
}
|
|
1006
1002
|
else {
|
|
@@ -1031,8 +1027,8 @@ class EmberAdapter extends __1.Adapter {
|
|
|
1031
1027
|
* Check against UNKNOWN_NETWORK_STATE for validity.
|
|
1032
1028
|
*/
|
|
1033
1029
|
async emberNetworkState() {
|
|
1034
|
-
if (this.networkCache.status ===
|
|
1035
|
-
const networkStatus =
|
|
1030
|
+
if (this.networkCache.status === consts_1.UNKNOWN_NETWORK_STATE) {
|
|
1031
|
+
const networkStatus = await this.ezsp.ezspNetworkState();
|
|
1036
1032
|
this.networkCache.status = networkStatus;
|
|
1037
1033
|
}
|
|
1038
1034
|
return this.networkCache.status;
|
|
@@ -1044,7 +1040,7 @@ class EmberAdapter extends __1.Adapter {
|
|
|
1044
1040
|
*/
|
|
1045
1041
|
async emberGetEui64() {
|
|
1046
1042
|
if (this.networkCache.eui64 === ZSpec.BLANK_EUI64) {
|
|
1047
|
-
this.networkCache.eui64 =
|
|
1043
|
+
this.networkCache.eui64 = await this.ezsp.ezspGetEui64();
|
|
1048
1044
|
}
|
|
1049
1045
|
return this.networkCache.eui64;
|
|
1050
1046
|
}
|
|
@@ -1055,12 +1051,12 @@ class EmberAdapter extends __1.Adapter {
|
|
|
1055
1051
|
*/
|
|
1056
1052
|
async emberGetPanId() {
|
|
1057
1053
|
if (this.networkCache.parameters.panId === ZSpec.INVALID_PAN_ID) {
|
|
1058
|
-
const [status, , parameters] =
|
|
1059
|
-
if (status ===
|
|
1054
|
+
const [status, , parameters] = await this.ezsp.ezspGetNetworkParameters();
|
|
1055
|
+
if (status === enums_1.SLStatus.OK) {
|
|
1060
1056
|
this.networkCache.parameters = parameters;
|
|
1061
1057
|
}
|
|
1062
1058
|
else {
|
|
1063
|
-
logger_1.logger.error(`Failed to get PAN ID (via network parameters) with status=${
|
|
1059
|
+
logger_1.logger.error(`Failed to get PAN ID (via network parameters) with status=${enums_1.SLStatus[status]}.`, NS);
|
|
1064
1060
|
}
|
|
1065
1061
|
}
|
|
1066
1062
|
return this.networkCache.parameters.panId;
|
|
@@ -1072,12 +1068,12 @@ class EmberAdapter extends __1.Adapter {
|
|
|
1072
1068
|
*/
|
|
1073
1069
|
async emberGetExtendedPanId() {
|
|
1074
1070
|
if ((0, es6_1.default)(this.networkCache.parameters.extendedPanId, ZSpec.BLANK_EXTENDED_PAN_ID)) {
|
|
1075
|
-
const [status, , parameters] =
|
|
1076
|
-
if (status ===
|
|
1071
|
+
const [status, , parameters] = await this.ezsp.ezspGetNetworkParameters();
|
|
1072
|
+
if (status === enums_1.SLStatus.OK) {
|
|
1077
1073
|
this.networkCache.parameters = parameters;
|
|
1078
1074
|
}
|
|
1079
1075
|
else {
|
|
1080
|
-
logger_1.logger.error(`Failed to get Extended PAN ID (via network parameters) with status=${
|
|
1076
|
+
logger_1.logger.error(`Failed to get Extended PAN ID (via network parameters) with status=${enums_1.SLStatus[status]}.`, NS);
|
|
1081
1077
|
}
|
|
1082
1078
|
}
|
|
1083
1079
|
return this.networkCache.parameters.extendedPanId;
|
|
@@ -1088,30 +1084,25 @@ class EmberAdapter extends __1.Adapter {
|
|
|
1088
1084
|
* Check against INVALID_RADIO_CHANNEL for validity.
|
|
1089
1085
|
*/
|
|
1090
1086
|
async emberGetRadioChannel() {
|
|
1091
|
-
if (this.networkCache.parameters.radioChannel ===
|
|
1092
|
-
const [status, , parameters] =
|
|
1093
|
-
if (status ===
|
|
1087
|
+
if (this.networkCache.parameters.radioChannel === consts_1.INVALID_RADIO_CHANNEL) {
|
|
1088
|
+
const [status, , parameters] = await this.ezsp.ezspGetNetworkParameters();
|
|
1089
|
+
if (status === enums_1.SLStatus.OK) {
|
|
1094
1090
|
this.networkCache.parameters = parameters;
|
|
1095
1091
|
}
|
|
1096
1092
|
else {
|
|
1097
|
-
logger_1.logger.error(`Failed to get radio channel (via network parameters) with status=${
|
|
1093
|
+
logger_1.logger.error(`Failed to get radio channel (via network parameters) with status=${enums_1.SLStatus[status]}.`, NS);
|
|
1098
1094
|
}
|
|
1099
1095
|
}
|
|
1100
1096
|
return this.networkCache.parameters.radioChannel;
|
|
1101
1097
|
}
|
|
1102
1098
|
// queued
|
|
1103
1099
|
async emberStartEnergyScan() {
|
|
1104
|
-
return
|
|
1105
|
-
this.
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
}
|
|
1111
|
-
// TODO: result in logs only atm, since UI doesn't support it
|
|
1112
|
-
resolve();
|
|
1113
|
-
return enums_2.SLStatus.OK;
|
|
1114
|
-
}, reject);
|
|
1100
|
+
return this.queue.execute(async () => {
|
|
1101
|
+
const status = await this.ezsp.ezspStartScan(enums_1.EzspNetworkScanType.ENERGY_SCAN, consts_1.EMBER_ALL_802_15_4_CHANNELS_MASK, ENERGY_SCAN_DURATION);
|
|
1102
|
+
if (status !== enums_1.SLStatus.OK) {
|
|
1103
|
+
throw new Error(`Failed energy scan request with status=${enums_1.SLStatus[status]}.`);
|
|
1104
|
+
}
|
|
1105
|
+
// TODO: result in logs only atm, since UI doesn't support it
|
|
1115
1106
|
});
|
|
1116
1107
|
}
|
|
1117
1108
|
//---- END Cache-enabled EZSP wrappers
|
|
@@ -1127,36 +1118,36 @@ class EmberAdapter extends __1.Adapter {
|
|
|
1127
1118
|
async emberVersion() {
|
|
1128
1119
|
// send the Host version number to the NCP.
|
|
1129
1120
|
// The NCP returns the EZSP version that the NCP is running along with the stackType and stackVersion
|
|
1130
|
-
let [ncpEzspProtocolVer, ncpStackType, ncpStackVer] = await this.ezsp.ezspVersion(
|
|
1121
|
+
let [ncpEzspProtocolVer, ncpStackType, ncpStackVer] = await this.ezsp.ezspVersion(consts_2.EZSP_PROTOCOL_VERSION);
|
|
1131
1122
|
// verify that the stack type is what is expected
|
|
1132
|
-
if (ncpStackType !==
|
|
1123
|
+
if (ncpStackType !== consts_2.EZSP_STACK_TYPE_MESH) {
|
|
1133
1124
|
throw new Error(`Stack type ${ncpStackType} is not expected!`);
|
|
1134
1125
|
}
|
|
1135
|
-
if (ncpEzspProtocolVer ===
|
|
1126
|
+
if (ncpEzspProtocolVer === consts_2.EZSP_PROTOCOL_VERSION) {
|
|
1136
1127
|
logger_1.logger.debug(`Adapter EZSP protocol version (${ncpEzspProtocolVer}) matches Host.`, NS);
|
|
1137
1128
|
}
|
|
1138
|
-
else if (ncpEzspProtocolVer <
|
|
1129
|
+
else if (ncpEzspProtocolVer < consts_2.EZSP_PROTOCOL_VERSION && ncpEzspProtocolVer >= consts_2.EZSP_MIN_PROTOCOL_VERSION) {
|
|
1139
1130
|
[ncpEzspProtocolVer, ncpStackType, ncpStackVer] = await this.ezsp.ezspVersion(ncpEzspProtocolVer);
|
|
1140
1131
|
logger_1.logger.info(`Adapter EZSP protocol version (${ncpEzspProtocolVer}) lower than Host. Switched.`, NS);
|
|
1141
1132
|
}
|
|
1142
1133
|
else {
|
|
1143
|
-
throw new Error(`Adapter EZSP protocol version (${ncpEzspProtocolVer}) is not supported `
|
|
1144
|
-
|
|
1134
|
+
throw new Error(`Adapter EZSP protocol version (${ncpEzspProtocolVer}) is not supported ` +
|
|
1135
|
+
`by Host [${consts_2.EZSP_MIN_PROTOCOL_VERSION}-${consts_2.EZSP_PROTOCOL_VERSION}].`);
|
|
1145
1136
|
}
|
|
1146
1137
|
this.ezsp.setProtocolVersion(ncpEzspProtocolVer);
|
|
1147
1138
|
logger_1.logger.debug(`Adapter info: EZSPVersion=${ncpEzspProtocolVer} StackType=${ncpStackType} StackVersion=${ncpStackVer}`, NS);
|
|
1148
|
-
const [status, versionStruct] =
|
|
1149
|
-
if (status !==
|
|
1139
|
+
const [status, versionStruct] = await this.ezsp.ezspGetVersionStruct();
|
|
1140
|
+
if (status !== enums_1.SLStatus.OK) {
|
|
1150
1141
|
// Should never happen with support of only EZSP v13+
|
|
1151
1142
|
throw new Error(`NCP has old-style version number. Not supported.`);
|
|
1152
1143
|
}
|
|
1153
1144
|
this.version = {
|
|
1154
1145
|
ezsp: ncpEzspProtocolVer,
|
|
1155
|
-
revision: `${versionStruct.major}.${versionStruct.minor}.${versionStruct.patch} [${
|
|
1146
|
+
revision: `${versionStruct.major}.${versionStruct.minor}.${versionStruct.patch} [${enums_1.EmberVersionType[versionStruct.type]}]`,
|
|
1156
1147
|
...versionStruct,
|
|
1157
1148
|
};
|
|
1158
|
-
if (versionStruct.type !==
|
|
1159
|
-
logger_1.logger.warning(`Adapter is running a non-GA version (${
|
|
1149
|
+
if (versionStruct.type !== enums_1.EmberVersionType.GA) {
|
|
1150
|
+
logger_1.logger.warning(`Adapter is running a non-GA version (${enums_1.EmberVersionType[versionStruct.type]}).`, NS);
|
|
1160
1151
|
}
|
|
1161
1152
|
logger_1.logger.info(`Adapter version info: ${JSON.stringify(this.version)}`, NS);
|
|
1162
1153
|
}
|
|
@@ -1169,11 +1160,11 @@ class EmberAdapter extends __1.Adapter {
|
|
|
1169
1160
|
* @returns
|
|
1170
1161
|
*/
|
|
1171
1162
|
async emberSetEzspConfigValue(configId, value) {
|
|
1172
|
-
const status =
|
|
1173
|
-
logger_1.logger.debug(`[EzspConfigId] SET "${
|
|
1174
|
-
if (status !==
|
|
1175
|
-
logger_1.logger.info(`[EzspConfigId] Failed to SET "${
|
|
1176
|
-
|
|
1163
|
+
const status = await this.ezsp.ezspSetConfigurationValue(configId, value);
|
|
1164
|
+
logger_1.logger.debug(`[EzspConfigId] SET "${enums_2.EzspConfigId[configId]}" TO "${value}" with status=${enums_1.SLStatus[status]}.`, NS);
|
|
1165
|
+
if (status !== enums_1.SLStatus.OK) {
|
|
1166
|
+
logger_1.logger.info(`[EzspConfigId] Failed to SET "${enums_2.EzspConfigId[configId]}" TO "${value}" with status=${enums_1.SLStatus[status]}. ` +
|
|
1167
|
+
`Firmware value will be used instead.`, NS);
|
|
1177
1168
|
}
|
|
1178
1169
|
return status;
|
|
1179
1170
|
}
|
|
@@ -1185,8 +1176,8 @@ class EmberAdapter extends __1.Adapter {
|
|
|
1185
1176
|
* @returns
|
|
1186
1177
|
*/
|
|
1187
1178
|
async emberSetEzspValue(valueId, valueLength, value) {
|
|
1188
|
-
const status =
|
|
1189
|
-
logger_1.logger.debug(`[EzspValueId] SET "${
|
|
1179
|
+
const status = await this.ezsp.ezspSetValue(valueId, valueLength, value);
|
|
1180
|
+
logger_1.logger.debug(`[EzspValueId] SET "${enums_2.EzspValueId[valueId]}" TO "${value}" with status=${enums_1.SLStatus[status]}.`, NS);
|
|
1190
1181
|
return status;
|
|
1191
1182
|
}
|
|
1192
1183
|
/**
|
|
@@ -1196,8 +1187,8 @@ class EmberAdapter extends __1.Adapter {
|
|
|
1196
1187
|
* @returns
|
|
1197
1188
|
*/
|
|
1198
1189
|
async emberSetEzspPolicy(policyId, decisionId) {
|
|
1199
|
-
const status =
|
|
1200
|
-
logger_1.logger.debug(`[EzspPolicyId] SET "${
|
|
1190
|
+
const status = await this.ezsp.ezspSetPolicy(policyId, decisionId);
|
|
1191
|
+
logger_1.logger.debug(`[EzspPolicyId] SET "${enums_2.EzspPolicyId[policyId]}" TO "${decisionId}" with status=${enums_1.SLStatus[status]}.`, NS);
|
|
1201
1192
|
return status;
|
|
1202
1193
|
}
|
|
1203
1194
|
/**
|
|
@@ -1214,9 +1205,9 @@ class EmberAdapter extends __1.Adapter {
|
|
|
1214
1205
|
async aesMmoHash(context, finalize, data) {
|
|
1215
1206
|
if (data.length > 255) {
|
|
1216
1207
|
// will be caught by request queue and rejected internally.
|
|
1217
|
-
throw new ezspError_1.EzspError(
|
|
1208
|
+
throw new ezspError_1.EzspError(enums_1.EzspStatus.ERROR_INVALID_CALL);
|
|
1218
1209
|
}
|
|
1219
|
-
const [status, reContext] =
|
|
1210
|
+
const [status, reContext] = await this.ezsp.ezspAesMmoHash(context, finalize, data);
|
|
1220
1211
|
return [status, reContext];
|
|
1221
1212
|
}
|
|
1222
1213
|
/**
|
|
@@ -1270,7 +1261,7 @@ class EmberAdapter extends __1.Adapter {
|
|
|
1270
1261
|
*/
|
|
1271
1262
|
async emberAesHashSimple(data) {
|
|
1272
1263
|
const context = (0, initters_1.aesMmoHashInit)();
|
|
1273
|
-
const [status, reContext] =
|
|
1264
|
+
const [status, reContext] = await this.emberAesMmoHashFinal(context, data);
|
|
1274
1265
|
return [status, reContext?.result];
|
|
1275
1266
|
}
|
|
1276
1267
|
/**
|
|
@@ -1287,14 +1278,13 @@ class EmberAdapter extends __1.Adapter {
|
|
|
1287
1278
|
* @returns messageTag The tag passed to ezspSend${x} function.
|
|
1288
1279
|
*/
|
|
1289
1280
|
async emberPermitJoining(duration, broadcastMgmtPermitJoin) {
|
|
1290
|
-
let status =
|
|
1281
|
+
let status = await this.ezsp.ezspPermitJoining(duration);
|
|
1291
1282
|
let apsFrame = null;
|
|
1292
1283
|
let messageTag = null;
|
|
1293
1284
|
logger_1.logger.debug(`Permit joining for ${duration} sec. status=${[status]}`, NS);
|
|
1294
1285
|
if (broadcastMgmtPermitJoin) {
|
|
1295
1286
|
// `authentication`: TC significance always 1 (zb specs)
|
|
1296
1287
|
const zdoPayload = buffaloZdo_1.BuffaloZdo.buildPermitJoining(duration, 1, []);
|
|
1297
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1298
1288
|
[status, apsFrame, messageTag] = await this.sendZDORequest(ZSpec.BroadcastAddress.DEFAULT, Zdo.ClusterId.PERMIT_JOINING_REQUEST, zdoPayload, DEFAULT_APS_OPTIONS);
|
|
1299
1289
|
}
|
|
1300
1290
|
return [status, apsFrame, messageTag];
|
|
@@ -1305,17 +1295,17 @@ class EmberAdapter extends __1.Adapter {
|
|
|
1305
1295
|
* @returns
|
|
1306
1296
|
*/
|
|
1307
1297
|
async emberSetJoinPolicy(decision) {
|
|
1308
|
-
let policy =
|
|
1309
|
-
if (decision ==
|
|
1310
|
-
policy =
|
|
1298
|
+
let policy = enums_2.EzspDecisionBitmask.DEFAULT_CONFIGURATION;
|
|
1299
|
+
if (decision == enums_1.EmberJoinDecision.USE_PRECONFIGURED_KEY) {
|
|
1300
|
+
policy = enums_2.EzspDecisionBitmask.ALLOW_JOINS | enums_2.EzspDecisionBitmask.ALLOW_UNSECURED_REJOINS;
|
|
1311
1301
|
}
|
|
1312
|
-
else if (decision ==
|
|
1313
|
-
policy =
|
|
1302
|
+
else if (decision == enums_1.EmberJoinDecision.SEND_KEY_IN_THE_CLEAR) {
|
|
1303
|
+
policy = enums_2.EzspDecisionBitmask.ALLOW_JOINS | enums_2.EzspDecisionBitmask.ALLOW_UNSECURED_REJOINS | enums_2.EzspDecisionBitmask.SEND_KEY_IN_CLEAR;
|
|
1314
1304
|
}
|
|
1315
|
-
else if (decision ==
|
|
1316
|
-
policy =
|
|
1305
|
+
else if (decision == enums_1.EmberJoinDecision.ALLOW_REJOINS_ONLY) {
|
|
1306
|
+
policy = enums_2.EzspDecisionBitmask.ALLOW_UNSECURED_REJOINS;
|
|
1317
1307
|
}
|
|
1318
|
-
return this.emberSetEzspPolicy(
|
|
1308
|
+
return this.emberSetEzspPolicy(enums_2.EzspPolicyId.TRUST_CENTER_POLICY, policy);
|
|
1319
1309
|
}
|
|
1320
1310
|
//---- END EZSP wrappers
|
|
1321
1311
|
//---- START Ember ZDO
|
|
@@ -1348,7 +1338,7 @@ class EmberAdapter extends __1.Adapter {
|
|
|
1348
1338
|
* @return uint8_t The next device request sequence number
|
|
1349
1339
|
*/
|
|
1350
1340
|
nextZDORequestSequence() {
|
|
1351
|
-
return (this.zdoRequestSequence =
|
|
1341
|
+
return (this.zdoRequestSequence = ++this.zdoRequestSequence & APPLICATION_ZDO_SEQUENCE_MASK);
|
|
1352
1342
|
}
|
|
1353
1343
|
/**
|
|
1354
1344
|
* ZDO
|
|
@@ -1362,8 +1352,8 @@ class EmberAdapter extends __1.Adapter {
|
|
|
1362
1352
|
* @returns messageTag The tag passed to ezspSend${x} function.
|
|
1363
1353
|
*/
|
|
1364
1354
|
async sendZDORequest(destination, clusterId, messageContents, options) {
|
|
1365
|
-
if (messageContents.length >
|
|
1366
|
-
return [
|
|
1355
|
+
if (messageContents.length > consts_2.EZSP_MAX_FRAME_LENGTH) {
|
|
1356
|
+
return [enums_1.SLStatus.MESSAGE_TOO_LONG, null, null];
|
|
1367
1357
|
}
|
|
1368
1358
|
const messageTag = this.nextZDORequestSequence();
|
|
1369
1359
|
messageContents[0] = messageTag;
|
|
@@ -1376,23 +1366,24 @@ class EmberAdapter extends __1.Adapter {
|
|
|
1376
1366
|
groupId: 0,
|
|
1377
1367
|
sequence: 0, // set by stack
|
|
1378
1368
|
};
|
|
1379
|
-
if (destination === ZSpec.BroadcastAddress.DEFAULT ||
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1369
|
+
if (destination === ZSpec.BroadcastAddress.DEFAULT ||
|
|
1370
|
+
destination === ZSpec.BroadcastAddress.RX_ON_WHEN_IDLE ||
|
|
1371
|
+
destination === ZSpec.BroadcastAddress.SLEEPY) {
|
|
1372
|
+
logger_1.logger.debug(`~~~> [ZDO ${Zdo.ClusterId[clusterId]} BROADCAST to=${destination} messageTag=${messageTag} ` +
|
|
1373
|
+
`messageContents=${messageContents.toString('hex')}]`, NS);
|
|
1383
1374
|
const [status, apsSequence] = await this.ezsp.ezspSendBroadcast(ZSpec.NULL_NODE_ID, // alias
|
|
1384
1375
|
destination, 0, // nwkSequence
|
|
1385
1376
|
apsFrame, this.getZDORequestRadius(), messageTag, messageContents);
|
|
1386
1377
|
apsFrame.sequence = apsSequence;
|
|
1387
|
-
logger_1.logger.debug(`~~~> [SENT ZDO type=BROADCAST apsSequence=${apsSequence} messageTag=${messageTag} status=${
|
|
1378
|
+
logger_1.logger.debug(`~~~> [SENT ZDO type=BROADCAST apsSequence=${apsSequence} messageTag=${messageTag} status=${enums_1.SLStatus[status]}`, NS);
|
|
1388
1379
|
return [status, apsFrame, messageTag];
|
|
1389
1380
|
}
|
|
1390
1381
|
else {
|
|
1391
|
-
logger_1.logger.debug(`~~~> [ZDO ${Zdo.ClusterId[clusterId]} UNICAST to=${destination} messageTag=${messageTag} `
|
|
1392
|
-
|
|
1393
|
-
const [status, apsSequence] = await this.ezsp.ezspSendUnicast(
|
|
1382
|
+
logger_1.logger.debug(`~~~> [ZDO ${Zdo.ClusterId[clusterId]} UNICAST to=${destination} messageTag=${messageTag} ` +
|
|
1383
|
+
`messageContents=${messageContents.toString('hex')}]`, NS);
|
|
1384
|
+
const [status, apsSequence] = await this.ezsp.ezspSendUnicast(enums_1.EmberOutgoingMessageType.DIRECT, destination, apsFrame, messageTag, messageContents);
|
|
1394
1385
|
apsFrame.sequence = apsSequence;
|
|
1395
|
-
logger_1.logger.debug(`~~~> [SENT ZDO type=DIRECT apsSequence=${apsSequence} messageTag=${messageTag} status=${
|
|
1386
|
+
logger_1.logger.debug(`~~~> [SENT ZDO type=DIRECT apsSequence=${apsSequence} messageTag=${messageTag} status=${enums_1.SLStatus[status]}`, NS);
|
|
1396
1387
|
return [status, apsFrame, messageTag];
|
|
1397
1388
|
}
|
|
1398
1389
|
}
|
|
@@ -1413,7 +1404,7 @@ class EmberAdapter extends __1.Adapter {
|
|
|
1413
1404
|
}
|
|
1414
1405
|
static async autoDetectPath() {
|
|
1415
1406
|
const paths = await serialPortUtils_1.default.find(autoDetectDefinitions);
|
|
1416
|
-
paths.sort((a, b) => (a < b
|
|
1407
|
+
paths.sort((a, b) => (a < b ? -1 : 1));
|
|
1417
1408
|
return paths.length > 0 ? paths[0] : null;
|
|
1418
1409
|
}
|
|
1419
1410
|
async start() {
|
|
@@ -1423,34 +1414,30 @@ class EmberAdapter extends __1.Adapter {
|
|
|
1423
1414
|
return result;
|
|
1424
1415
|
}
|
|
1425
1416
|
async stop() {
|
|
1426
|
-
this.requestQueue.stopDispatching();
|
|
1427
1417
|
await this.ezsp.stop();
|
|
1428
1418
|
this.initVariables();
|
|
1429
1419
|
logger_1.logger.info(`======== Ember Adapter Stopped ========`, NS);
|
|
1430
1420
|
}
|
|
1431
1421
|
// queued, non-InterPAN
|
|
1432
1422
|
async getCoordinator() {
|
|
1433
|
-
return
|
|
1434
|
-
this.
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
});
|
|
1452
|
-
return enums_2.SLStatus.OK;
|
|
1453
|
-
}, reject);
|
|
1423
|
+
return this.queue.execute(async () => {
|
|
1424
|
+
this.checkInterpanLock();
|
|
1425
|
+
// in all likelihood this will be retrieved from cache
|
|
1426
|
+
const ieeeAddr = await this.emberGetEui64();
|
|
1427
|
+
return {
|
|
1428
|
+
ieeeAddr,
|
|
1429
|
+
networkAddress: ZSpec.COORDINATOR_ADDRESS,
|
|
1430
|
+
manufacturerID: DEFAULT_MANUFACTURER_CODE,
|
|
1431
|
+
endpoints: endpoints_1.FIXED_ENDPOINTS.map((ep) => {
|
|
1432
|
+
return {
|
|
1433
|
+
profileID: ep.profileId,
|
|
1434
|
+
ID: ep.endpoint,
|
|
1435
|
+
deviceID: ep.deviceId,
|
|
1436
|
+
inputClusters: ep.inClusterList.slice(), // copy
|
|
1437
|
+
outputClusters: ep.outClusterList.slice(), // copy
|
|
1438
|
+
};
|
|
1439
|
+
}),
|
|
1440
|
+
};
|
|
1454
1441
|
});
|
|
1455
1442
|
}
|
|
1456
1443
|
async getCoordinatorVersion() {
|
|
@@ -1459,7 +1446,7 @@ class EmberAdapter extends __1.Adapter {
|
|
|
1459
1446
|
// queued
|
|
1460
1447
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1461
1448
|
async reset(type) {
|
|
1462
|
-
return Promise.reject(new Error(
|
|
1449
|
+
return Promise.reject(new Error('Not supported'));
|
|
1463
1450
|
// NOTE: although this function is legacy atm, a couple of new untested EZSP functions that could also prove useful:
|
|
1464
1451
|
// this.ezsp.ezspTokenFactoryReset(true/*excludeOutgoingFC*/, true/*excludeBootCounter*/);
|
|
1465
1452
|
// this.ezsp.ezspResetNode()
|
|
@@ -1470,94 +1457,86 @@ class EmberAdapter extends __1.Adapter {
|
|
|
1470
1457
|
// queued
|
|
1471
1458
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1472
1459
|
async backup(ieeeAddressesInDatabase) {
|
|
1473
|
-
return
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1460
|
+
return this.queue.execute(async () => {
|
|
1461
|
+
// grab fresh version here, bypass cache
|
|
1462
|
+
const [netStatus, , netParams] = await this.ezsp.ezspGetNetworkParameters();
|
|
1463
|
+
if (netStatus !== enums_1.SLStatus.OK) {
|
|
1464
|
+
throw new Error(`[BACKUP] Failed to get network parameters with status=${enums_1.SLStatus[netStatus]}.`);
|
|
1465
|
+
}
|
|
1466
|
+
// update cache
|
|
1467
|
+
this.networkCache.parameters = netParams;
|
|
1468
|
+
this.networkCache.eui64 = await this.ezsp.ezspGetEui64();
|
|
1469
|
+
const [netKeyStatus, netKeyInfo] = await this.ezsp.ezspGetNetworkKeyInfo();
|
|
1470
|
+
if (netKeyStatus !== enums_1.SLStatus.OK) {
|
|
1471
|
+
throw new Error(`[BACKUP] Failed to get network keys info with status=${enums_1.SLStatus[netKeyStatus]}.`);
|
|
1472
|
+
}
|
|
1473
|
+
if (!netKeyInfo.networkKeySet) {
|
|
1474
|
+
throw new Error(`[BACKUP] No network key set.`);
|
|
1475
|
+
}
|
|
1476
|
+
const keyList = ALLOW_APP_KEY_REQUESTS ? await this.exportLinkKeys() : [];
|
|
1477
|
+
let context = (0, initters_1.initSecurityManagerContext)();
|
|
1478
|
+
context.coreKeyType = enums_1.SecManKeyType.TC_LINK;
|
|
1479
|
+
const [tclkStatus, tcLinkKey] = await this.ezsp.ezspExportKey(context);
|
|
1480
|
+
if (tclkStatus !== enums_1.SLStatus.OK) {
|
|
1481
|
+
throw new Error(`[BACKUP] Failed to export TC Link Key with status=${enums_1.SLStatus[tclkStatus]}.`);
|
|
1482
|
+
}
|
|
1483
|
+
context = (0, initters_1.initSecurityManagerContext)(); // make sure it's back to zeroes
|
|
1484
|
+
context.coreKeyType = enums_1.SecManKeyType.NETWORK;
|
|
1485
|
+
context.keyIndex = 0;
|
|
1486
|
+
const [nkStatus, networkKey] = await this.ezsp.ezspExportKey(context);
|
|
1487
|
+
if (nkStatus !== enums_1.SLStatus.OK) {
|
|
1488
|
+
throw new Error(`[BACKUP] Failed to export Network Key with status=${enums_1.SLStatus[nkStatus]}.`);
|
|
1489
|
+
}
|
|
1490
|
+
const zbChannels = Array.from(Array(consts_1.EMBER_NUM_802_15_4_CHANNELS), (e, i) => i + consts_1.EMBER_MIN_802_15_4_CHANNEL_NUMBER);
|
|
1491
|
+
return {
|
|
1492
|
+
networkOptions: {
|
|
1493
|
+
panId: netParams.panId, // uint16_t
|
|
1494
|
+
extendedPanId: Buffer.from(netParams.extendedPanId),
|
|
1495
|
+
channelList: zbChannels.map((c) => ((2 ** c) & netParams.channels ? c : null)).filter((x) => x),
|
|
1496
|
+
networkKey: networkKey.contents,
|
|
1497
|
+
networkKeyDistribute: false,
|
|
1498
|
+
},
|
|
1499
|
+
logicalChannel: netParams.radioChannel,
|
|
1500
|
+
networkKeyInfo: {
|
|
1501
|
+
sequenceNumber: netKeyInfo.networkKeySequenceNumber,
|
|
1502
|
+
frameCounter: netKeyInfo.networkKeyFrameCounter,
|
|
1503
|
+
},
|
|
1504
|
+
securityLevel: consts_1.SECURITY_LEVEL_Z3,
|
|
1505
|
+
networkUpdateId: netParams.nwkUpdateId,
|
|
1506
|
+
coordinatorIeeeAddress: Buffer.from(this.networkCache.eui64.substring(2) /*take out 0x*/, 'hex').reverse(),
|
|
1507
|
+
devices: keyList.map((key) => ({
|
|
1508
|
+
networkAddress: null, // not used for restore, no reason to make NCP calls for nothing
|
|
1509
|
+
ieeeAddress: Buffer.from(key.deviceEui64.substring(2) /*take out 0x*/, 'hex').reverse(),
|
|
1510
|
+
isDirectChild: false, // not used
|
|
1511
|
+
linkKey: {
|
|
1512
|
+
key: key.key.contents,
|
|
1513
|
+
rxCounter: key.incomingFrameCounter,
|
|
1514
|
+
txCounter: key.outgoingFrameCounter,
|
|
1519
1515
|
},
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
key: key.key.contents,
|
|
1529
|
-
rxCounter: key.incomingFrameCounter,
|
|
1530
|
-
txCounter: key.outgoingFrameCounter,
|
|
1531
|
-
},
|
|
1532
|
-
})),
|
|
1533
|
-
ezsp: {
|
|
1534
|
-
version: this.version.ezsp,
|
|
1535
|
-
hashed_tclk: tcLinkKey.contents,
|
|
1536
|
-
// tokens: tokensBuf.toString('hex'),
|
|
1537
|
-
// altNetworkKey: altNetworkKey.contents,
|
|
1538
|
-
}
|
|
1539
|
-
});
|
|
1540
|
-
return enums_2.SLStatus.OK;
|
|
1541
|
-
}, reject, true);
|
|
1516
|
+
})),
|
|
1517
|
+
ezsp: {
|
|
1518
|
+
version: this.version.ezsp,
|
|
1519
|
+
hashed_tclk: tcLinkKey.contents,
|
|
1520
|
+
// tokens: tokensBuf.toString('hex'),
|
|
1521
|
+
// altNetworkKey: altNetworkKey.contents,
|
|
1522
|
+
},
|
|
1523
|
+
};
|
|
1542
1524
|
});
|
|
1543
1525
|
}
|
|
1544
1526
|
// queued, non-InterPAN
|
|
1545
1527
|
async getNetworkParameters() {
|
|
1546
|
-
return
|
|
1547
|
-
this.
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
});
|
|
1559
|
-
return enums_2.SLStatus.OK;
|
|
1560
|
-
}, reject);
|
|
1528
|
+
return this.queue.execute(async () => {
|
|
1529
|
+
this.checkInterpanLock();
|
|
1530
|
+
// first call will cache for the others, but in all likelihood, it will all be from freshly cached after init
|
|
1531
|
+
// since Controller caches this also.
|
|
1532
|
+
const channel = await this.emberGetRadioChannel();
|
|
1533
|
+
const panID = await this.emberGetPanId();
|
|
1534
|
+
const extendedPanID = await this.emberGetExtendedPanId();
|
|
1535
|
+
return {
|
|
1536
|
+
panID,
|
|
1537
|
+
extendedPanID: parseInt(Buffer.from(extendedPanID).toString('hex'), 16),
|
|
1538
|
+
channel,
|
|
1539
|
+
};
|
|
1561
1540
|
});
|
|
1562
1541
|
}
|
|
1563
1542
|
async supportsChangeChannel() {
|
|
@@ -1565,61 +1544,44 @@ class EmberAdapter extends __1.Adapter {
|
|
|
1565
1544
|
}
|
|
1566
1545
|
// queued
|
|
1567
1546
|
async changeChannel(newChannel) {
|
|
1568
|
-
return
|
|
1569
|
-
this.
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
}
|
|
1578
|
-
await this.oneWaitress.startWaitingForEvent({ eventName: oneWaitress_1.OneWaitressEvents.STACK_STATUS_CHANNEL_CHANGED }, DEFAULT_NETWORK_REQUEST_TIMEOUT * 2, // observed to ~9sec
|
|
1579
|
-
'[ZDO] Change Channel');
|
|
1580
|
-
resolve();
|
|
1581
|
-
return enums_2.SLStatus.OK;
|
|
1582
|
-
}, reject);
|
|
1547
|
+
return this.queue.execute(async () => {
|
|
1548
|
+
this.checkInterpanLock();
|
|
1549
|
+
const zdoPayload = buffaloZdo_1.BuffaloZdo.buildChannelChangeRequest(newChannel, null);
|
|
1550
|
+
const [status] = await this.sendZDORequest(ZSpec.BroadcastAddress.SLEEPY, Zdo.ClusterId.NWK_UPDATE_REQUEST, zdoPayload, DEFAULT_APS_OPTIONS);
|
|
1551
|
+
if (status !== enums_1.SLStatus.OK) {
|
|
1552
|
+
throw new Error(`[ZDO] Failed broadcast channel change to "${newChannel}" with status=${enums_1.SLStatus[status]}.`);
|
|
1553
|
+
}
|
|
1554
|
+
await this.oneWaitress.startWaitingForEvent({ eventName: oneWaitress_1.OneWaitressEvents.STACK_STATUS_CHANNEL_CHANGED }, DEFAULT_NETWORK_REQUEST_TIMEOUT * 2, // observed to ~9sec
|
|
1555
|
+
'[ZDO] Change Channel');
|
|
1583
1556
|
});
|
|
1584
1557
|
}
|
|
1585
1558
|
// queued
|
|
1586
1559
|
async scanChannels(networkAddress, channels, duration, count) {
|
|
1587
|
-
return
|
|
1588
|
-
this.
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
responseClusterId: Zdo.ClusterId.NWK_UPDATE_RESPONSE,
|
|
1601
|
-
}, DEFAULT_ZDO_REQUEST_TIMEOUT + (((((2 ** duration) + 1) * (16 * 960)) / 1000) * count * channels.length)); // time for scan
|
|
1602
|
-
resolve(result);
|
|
1603
|
-
return enums_2.SLStatus.OK;
|
|
1604
|
-
}, reject);
|
|
1560
|
+
return this.queue.execute(async () => {
|
|
1561
|
+
this.checkInterpanLock();
|
|
1562
|
+
const zdoPayload = buffaloZdo_1.BuffaloZdo.buildScanChannelsRequest(channels, duration, count);
|
|
1563
|
+
const [status, apsFrame] = await this.sendZDORequest(networkAddress, Zdo.ClusterId.NWK_UPDATE_REQUEST, zdoPayload, DEFAULT_APS_OPTIONS);
|
|
1564
|
+
if (status !== enums_1.SLStatus.OK) {
|
|
1565
|
+
throw new Error(`[ZDO] Failed to scan channels '${channels}' on '${networkAddress} with status=${enums_1.SLStatus[status]}.`);
|
|
1566
|
+
}
|
|
1567
|
+
const result = await this.oneWaitress.startWaitingFor({
|
|
1568
|
+
target: networkAddress,
|
|
1569
|
+
apsFrame,
|
|
1570
|
+
responseClusterId: Zdo.ClusterId.NWK_UPDATE_RESPONSE,
|
|
1571
|
+
}, DEFAULT_ZDO_REQUEST_TIMEOUT + (((2 ** duration + 1) * (16 * 960)) / 1000) * count * channels.length); // time for scan
|
|
1572
|
+
return result;
|
|
1605
1573
|
});
|
|
1606
1574
|
}
|
|
1607
1575
|
// queued
|
|
1608
1576
|
async setTransmitPower(value) {
|
|
1609
1577
|
if (typeof value !== 'number') {
|
|
1610
|
-
|
|
1611
|
-
return;
|
|
1578
|
+
throw new Error(`Tried to set transmit power to non-number. Value ${value} of type ${typeof value}.`);
|
|
1612
1579
|
}
|
|
1613
|
-
return
|
|
1614
|
-
this.
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
return status;
|
|
1619
|
-
}
|
|
1620
|
-
resolve();
|
|
1621
|
-
return enums_2.SLStatus.OK;
|
|
1622
|
-
}, reject);
|
|
1580
|
+
return this.queue.execute(async () => {
|
|
1581
|
+
const status = await this.ezsp.ezspSetRadioPower(value);
|
|
1582
|
+
if (status !== enums_1.SLStatus.OK) {
|
|
1583
|
+
throw new Error(`Failed to set transmit power to ${value} status=${enums_1.SLStatus[status]}.`);
|
|
1584
|
+
}
|
|
1623
1585
|
});
|
|
1624
1586
|
}
|
|
1625
1587
|
// queued
|
|
@@ -1628,47 +1590,41 @@ class EmberAdapter extends __1.Adapter {
|
|
|
1628
1590
|
throw new Error(`[ADD INSTALL CODE] Failed for '${ieeeAddress}'; no code given.`);
|
|
1629
1591
|
}
|
|
1630
1592
|
// codes with CRC, check CRC before sending to NCP, otherwise let NCP handle
|
|
1631
|
-
if (
|
|
1593
|
+
if (consts_1.EMBER_INSTALL_CODE_SIZES.indexOf(key.length) !== -1) {
|
|
1632
1594
|
// Reverse the bits in a byte (uint8_t)
|
|
1633
1595
|
const reverse = (b) => {
|
|
1634
|
-
return (((b * 0x0802 & 0x22110) | (b * 0x8020 & 0x88440)) * 0x10101 >> 16) &
|
|
1596
|
+
return (((((b * 0x0802) & 0x22110) | ((b * 0x8020) & 0x88440)) * 0x10101) >> 16) & 0xff;
|
|
1635
1597
|
};
|
|
1636
|
-
let crc =
|
|
1598
|
+
let crc = 0xffff; // uint16_t
|
|
1637
1599
|
// Compute the CRC and verify that it matches.
|
|
1638
1600
|
// The bit reversals, byte swap, and ones' complement are due to differences between halCommonCrc16 and the Smart Energy version.
|
|
1639
|
-
for (let index = 0; index <
|
|
1601
|
+
for (let index = 0; index < key.length - consts_1.EMBER_INSTALL_CODE_CRC_SIZE; index++) {
|
|
1640
1602
|
crc = (0, math_1.halCommonCrc16)(reverse(key[index]), crc);
|
|
1641
1603
|
}
|
|
1642
|
-
crc =
|
|
1643
|
-
if (key[key.length -
|
|
1644
|
-
|
|
1604
|
+
crc = ~(0, math_1.highLowToInt)(reverse((0, math_1.lowByte)(crc)), reverse((0, math_1.highByte)(crc))) & 0xffff;
|
|
1605
|
+
if (key[key.length - consts_1.EMBER_INSTALL_CODE_CRC_SIZE] !== (0, math_1.lowByte)(crc) ||
|
|
1606
|
+
key[key.length - consts_1.EMBER_INSTALL_CODE_CRC_SIZE + 1] !== (0, math_1.highByte)(crc)) {
|
|
1645
1607
|
throw new Error(`[ADD INSTALL CODE] Failed for '${ieeeAddress}'; invalid code CRC.`);
|
|
1646
1608
|
}
|
|
1647
1609
|
else {
|
|
1648
1610
|
logger_1.logger.debug(`[ADD INSTALL CODE] CRC validated for '${ieeeAddress}'.`, NS);
|
|
1649
1611
|
}
|
|
1650
1612
|
}
|
|
1651
|
-
return
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
}
|
|
1665
|
-
|
|
1666
|
-
logger_1.logger.error(`[ADD INSTALL CODE] Failed for '${ieeeAddress}' with status=${enums_2.SLStatus[impStatus]}.`, NS);
|
|
1667
|
-
return enums_2.SLStatus.FAIL;
|
|
1668
|
-
}
|
|
1669
|
-
resolve();
|
|
1670
|
-
return enums_2.SLStatus.OK;
|
|
1671
|
-
}, reject);
|
|
1613
|
+
return this.queue.execute(async () => {
|
|
1614
|
+
// Compute the key from the install code and CRC.
|
|
1615
|
+
const [aesStatus, keyContents] = await this.emberAesHashSimple(key);
|
|
1616
|
+
if (aesStatus !== enums_1.SLStatus.OK) {
|
|
1617
|
+
throw new Error(`[ADD INSTALL CODE] Failed AES hash for '${ieeeAddress}' with status=${enums_1.SLStatus[aesStatus]}.`);
|
|
1618
|
+
}
|
|
1619
|
+
// Add the key to the transient key table.
|
|
1620
|
+
// This will be used while the DUT joins.
|
|
1621
|
+
const impStatus = await this.ezsp.ezspImportTransientKey(ieeeAddress, { contents: keyContents });
|
|
1622
|
+
if (impStatus == enums_1.SLStatus.OK) {
|
|
1623
|
+
logger_1.logger.debug(`[ADD INSTALL CODE] Success for '${ieeeAddress}'.`, NS);
|
|
1624
|
+
}
|
|
1625
|
+
else {
|
|
1626
|
+
throw new Error(`[ADD INSTALL CODE] Failed for '${ieeeAddress}' with status=${enums_1.SLStatus[impStatus]}.`);
|
|
1627
|
+
}
|
|
1672
1628
|
});
|
|
1673
1629
|
}
|
|
1674
1630
|
/** WARNING: Adapter impl. Starts timer immediately upon returning */
|
|
@@ -1683,7 +1639,7 @@ class EmberAdapter extends __1.Adapter {
|
|
|
1683
1639
|
sourceEndpoint: sourceEndpointInfo.endpoint,
|
|
1684
1640
|
destinationEndpoint: endpoint,
|
|
1685
1641
|
groupId: 0,
|
|
1686
|
-
options:
|
|
1642
|
+
options: enums_1.EmberApsOption.NONE,
|
|
1687
1643
|
},
|
|
1688
1644
|
zclSequence: transactionSequenceNumber,
|
|
1689
1645
|
commandIdentifier,
|
|
@@ -1698,18 +1654,15 @@ class EmberAdapter extends __1.Adapter {
|
|
|
1698
1654
|
async permitJoin(seconds, networkAddress) {
|
|
1699
1655
|
const preJoining = async () => {
|
|
1700
1656
|
if (seconds) {
|
|
1701
|
-
const plaintextKey = { contents: Buffer.from(
|
|
1702
|
-
const impKeyStatus =
|
|
1703
|
-
if (impKeyStatus !==
|
|
1704
|
-
|
|
1705
|
-
return enums_2.SLStatus.FAIL;
|
|
1657
|
+
const plaintextKey = { contents: Buffer.from(consts_1.ZIGBEE_PROFILE_INTEROPERABILITY_LINK_KEY) };
|
|
1658
|
+
const impKeyStatus = await this.ezsp.ezspImportTransientKey(ZSpec.BLANK_EUI64, plaintextKey);
|
|
1659
|
+
if (impKeyStatus !== enums_1.SLStatus.OK) {
|
|
1660
|
+
throw new Error(`[ZDO] Failed import transient key with status=${enums_1.SLStatus[impKeyStatus]}.`);
|
|
1706
1661
|
}
|
|
1707
|
-
const setJPstatus =
|
|
1708
|
-
if (setJPstatus !==
|
|
1709
|
-
|
|
1710
|
-
return enums_2.SLStatus.FAIL;
|
|
1662
|
+
const setJPstatus = await this.emberSetJoinPolicy(enums_1.EmberJoinDecision.USE_PRECONFIGURED_KEY);
|
|
1663
|
+
if (setJPstatus !== enums_1.SLStatus.OK) {
|
|
1664
|
+
throw new Error(`[ZDO] Failed set join policy with status=${enums_1.SLStatus[setJPstatus]}.`);
|
|
1711
1665
|
}
|
|
1712
|
-
return enums_2.SLStatus.OK;
|
|
1713
1666
|
}
|
|
1714
1667
|
else {
|
|
1715
1668
|
if (this.manufacturerCode !== DEFAULT_MANUFACTURER_CODE) {
|
|
@@ -1718,316 +1671,243 @@ class EmberAdapter extends __1.Adapter {
|
|
|
1718
1671
|
this.manufacturerCode = DEFAULT_MANUFACTURER_CODE;
|
|
1719
1672
|
}
|
|
1720
1673
|
await this.ezsp.ezspClearTransientLinkKeys();
|
|
1721
|
-
const setJPstatus =
|
|
1722
|
-
if (setJPstatus !==
|
|
1723
|
-
|
|
1724
|
-
return enums_2.SLStatus.FAIL;
|
|
1674
|
+
const setJPstatus = await this.emberSetJoinPolicy(enums_1.EmberJoinDecision.ALLOW_REJOINS_ONLY);
|
|
1675
|
+
if (setJPstatus !== enums_1.SLStatus.OK) {
|
|
1676
|
+
throw new Error(`[ZDO] Failed set join policy for with status=${enums_1.SLStatus[setJPstatus]}.`);
|
|
1725
1677
|
}
|
|
1726
|
-
return enums_2.SLStatus.OK;
|
|
1727
1678
|
}
|
|
1728
1679
|
};
|
|
1729
1680
|
if (networkAddress) {
|
|
1730
1681
|
// specific device that is not `Coordinator`
|
|
1731
|
-
return
|
|
1732
|
-
this.
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
}
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
return status;
|
|
1746
|
-
}
|
|
1747
|
-
(await this.oneWaitress.startWaitingFor({
|
|
1748
|
-
target: networkAddress,
|
|
1749
|
-
apsFrame,
|
|
1750
|
-
responseClusterId: Zdo.ClusterId.PERMIT_JOINING_RESPONSE,
|
|
1751
|
-
}, DEFAULT_ZDO_REQUEST_TIMEOUT));
|
|
1752
|
-
resolve();
|
|
1753
|
-
return enums_2.SLStatus.OK;
|
|
1754
|
-
}, reject);
|
|
1682
|
+
return this.queue.execute(async () => {
|
|
1683
|
+
this.checkInterpanLock();
|
|
1684
|
+
await preJoining();
|
|
1685
|
+
// `authentication`: TC significance always 1 (zb specs)
|
|
1686
|
+
const zdoPayload = buffaloZdo_1.BuffaloZdo.buildPermitJoining(seconds, 1, []);
|
|
1687
|
+
const [status, apsFrame] = await this.sendZDORequest(networkAddress, Zdo.ClusterId.PERMIT_JOINING_REQUEST, zdoPayload, DEFAULT_APS_OPTIONS);
|
|
1688
|
+
if (status !== enums_1.SLStatus.OK) {
|
|
1689
|
+
throw new Error(`[ZDO] Failed permit joining request for "${networkAddress}" with status=${enums_1.SLStatus[status]}.`);
|
|
1690
|
+
}
|
|
1691
|
+
await this.oneWaitress.startWaitingFor({
|
|
1692
|
+
target: networkAddress,
|
|
1693
|
+
apsFrame,
|
|
1694
|
+
responseClusterId: Zdo.ClusterId.PERMIT_JOINING_RESPONSE,
|
|
1695
|
+
}, DEFAULT_ZDO_REQUEST_TIMEOUT);
|
|
1755
1696
|
});
|
|
1756
1697
|
}
|
|
1757
1698
|
else {
|
|
1758
1699
|
// coordinator-only, or all
|
|
1759
|
-
return
|
|
1760
|
-
this.
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
// DEFAULT_ZCL_REQUEST_TIMEOUT,
|
|
1785
|
-
// '[ZDO] Permit Joining',
|
|
1786
|
-
// );
|
|
1787
|
-
// } else {
|
|
1788
|
-
// // NOTE: CLOSED stack status is not triggered if the network was not OPENED in the first place, so don't wait for it
|
|
1789
|
-
// // same kind of problem as described above (upstream always tries to close after start, but EZSP already is)
|
|
1790
|
-
// }
|
|
1791
|
-
resolve();
|
|
1792
|
-
return enums_2.SLStatus.OK;
|
|
1793
|
-
}, reject);
|
|
1700
|
+
return this.queue.execute(async () => {
|
|
1701
|
+
this.checkInterpanLock();
|
|
1702
|
+
await preJoining();
|
|
1703
|
+
// local permit join if `Coordinator`-only requested, else local + broadcast
|
|
1704
|
+
const [status] = await this.emberPermitJoining(seconds, networkAddress === ZSpec.COORDINATOR_ADDRESS ? false : true);
|
|
1705
|
+
if (status !== enums_1.SLStatus.OK) {
|
|
1706
|
+
throw new Error(`[ZDO] Failed permit joining request with status=${enums_1.SLStatus[status]}.`);
|
|
1707
|
+
}
|
|
1708
|
+
// NOTE: because Z2M is refreshing the permit join duration early to prevent it from closing
|
|
1709
|
+
// (every 200sec, even if only opened for 254sec), we can't wait for the stack opened status,
|
|
1710
|
+
// as it won't trigger again if already opened... so instead we assume it worked
|
|
1711
|
+
// NOTE2: with EZSP, 255=forever, and 254=max, but since upstream logic uses fixed 254 with interval refresh,
|
|
1712
|
+
// we can't simply bypass upstream calls if called for "forever" to prevent useless NCP calls (3-4 each time),
|
|
1713
|
+
// until called with 0 (disable), since we don't know if it was requested for forever or not...
|
|
1714
|
+
// TLDR: upstream logic change required to allow this
|
|
1715
|
+
// if (seconds) {
|
|
1716
|
+
// await this.oneWaitress.startWaitingForEvent(
|
|
1717
|
+
// {eventName: OneWaitressEvents.STACK_STATUS_NETWORK_OPENED},
|
|
1718
|
+
// DEFAULT_ZCL_REQUEST_TIMEOUT,
|
|
1719
|
+
// '[ZDO] Permit Joining',
|
|
1720
|
+
// );
|
|
1721
|
+
// } else {
|
|
1722
|
+
// // NOTE: CLOSED stack status is not triggered if the network was not OPENED in the first place, so don't wait for it
|
|
1723
|
+
// // same kind of problem as described above (upstream always tries to close after start, but EZSP already is)
|
|
1724
|
+
// }
|
|
1794
1725
|
});
|
|
1795
1726
|
}
|
|
1796
1727
|
}
|
|
1797
1728
|
// queued, non-InterPAN
|
|
1798
1729
|
async lqi(networkAddress) {
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
const
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
}
|
|
1808
|
-
const result = (await this.oneWaitress.startWaitingFor({
|
|
1809
|
-
target: networkAddress,
|
|
1810
|
-
apsFrame,
|
|
1811
|
-
responseClusterId: Zdo.ClusterId.LQI_TABLE_RESPONSE,
|
|
1812
|
-
}, DEFAULT_ZDO_REQUEST_TIMEOUT));
|
|
1813
|
-
for (const entry of result.entryList) {
|
|
1814
|
-
neighbors.push({
|
|
1815
|
-
ieeeAddr: entry.eui64,
|
|
1816
|
-
networkAddress: entry.nwkAddress,
|
|
1817
|
-
linkquality: entry.lqi,
|
|
1818
|
-
relationship: entry.relationship,
|
|
1819
|
-
depth: entry.depth,
|
|
1820
|
-
});
|
|
1821
|
-
}
|
|
1822
|
-
return [enums_2.SLStatus.OK, result.neighborTableEntries, result.entryList.length];
|
|
1823
|
-
};
|
|
1824
|
-
return new Promise((resolve, reject) => {
|
|
1825
|
-
this.requestQueue.enqueue(async () => {
|
|
1826
|
-
this.checkInterpanLock();
|
|
1827
|
-
let [status, tableEntries, entryCount] = (await request(0));
|
|
1828
|
-
if (status !== enums_2.SLStatus.OK) {
|
|
1829
|
-
return status;
|
|
1730
|
+
return this.queue.execute(async () => {
|
|
1731
|
+
this.checkInterpanLock();
|
|
1732
|
+
const neighbors = [];
|
|
1733
|
+
const request = async (startIndex) => {
|
|
1734
|
+
const zdoPayload = buffaloZdo_1.BuffaloZdo.buildLqiTableRequest(startIndex);
|
|
1735
|
+
const [status, apsFrame] = await this.sendZDORequest(networkAddress, Zdo.ClusterId.LQI_TABLE_REQUEST, zdoPayload, DEFAULT_APS_OPTIONS);
|
|
1736
|
+
if (status !== enums_1.SLStatus.OK) {
|
|
1737
|
+
throw new Error(`[ZDO] Failed LQI request for "${networkAddress}" (index "${startIndex}") with status=${enums_1.SLStatus[status]}.`);
|
|
1830
1738
|
}
|
|
1831
|
-
const
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1739
|
+
const result = await this.oneWaitress.startWaitingFor({
|
|
1740
|
+
target: networkAddress,
|
|
1741
|
+
apsFrame,
|
|
1742
|
+
responseClusterId: Zdo.ClusterId.LQI_TABLE_RESPONSE,
|
|
1743
|
+
}, DEFAULT_ZDO_REQUEST_TIMEOUT);
|
|
1744
|
+
for (const entry of result.entryList) {
|
|
1745
|
+
neighbors.push({
|
|
1746
|
+
ieeeAddr: entry.eui64,
|
|
1747
|
+
networkAddress: entry.nwkAddress,
|
|
1748
|
+
linkquality: entry.lqi,
|
|
1749
|
+
relationship: entry.relationship,
|
|
1750
|
+
depth: entry.depth,
|
|
1751
|
+
});
|
|
1839
1752
|
}
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1753
|
+
return [result.neighborTableEntries, result.entryList.length];
|
|
1754
|
+
};
|
|
1755
|
+
let [tableEntries, entryCount] = await request(0);
|
|
1756
|
+
const size = tableEntries;
|
|
1757
|
+
let nextStartIndex = entryCount;
|
|
1758
|
+
while (neighbors.length < size) {
|
|
1759
|
+
[tableEntries, entryCount] = await request(nextStartIndex);
|
|
1760
|
+
nextStartIndex += entryCount;
|
|
1761
|
+
}
|
|
1762
|
+
return { neighbors };
|
|
1843
1763
|
});
|
|
1844
1764
|
}
|
|
1845
1765
|
// queued, non-InterPAN
|
|
1846
1766
|
async routingTable(networkAddress) {
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
const
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
}
|
|
1856
|
-
const result = (await this.oneWaitress.startWaitingFor({
|
|
1857
|
-
target: networkAddress,
|
|
1858
|
-
apsFrame,
|
|
1859
|
-
responseClusterId: Zdo.ClusterId.ROUTING_TABLE_RESPONSE,
|
|
1860
|
-
}, DEFAULT_ZDO_REQUEST_TIMEOUT));
|
|
1861
|
-
for (const entry of result.entryList) {
|
|
1862
|
-
table.push({
|
|
1863
|
-
destinationAddress: entry.destinationAddress,
|
|
1864
|
-
status: RoutingTableStatus[entry.status], // get str value from enum to satisfy upstream's needs
|
|
1865
|
-
nextHop: entry.nextHopAddress,
|
|
1866
|
-
});
|
|
1867
|
-
}
|
|
1868
|
-
return [enums_2.SLStatus.OK, result.routingTableEntries, result.entryList.length];
|
|
1869
|
-
};
|
|
1870
|
-
return new Promise((resolve, reject) => {
|
|
1871
|
-
this.requestQueue.enqueue(async () => {
|
|
1872
|
-
this.checkInterpanLock();
|
|
1873
|
-
let [status, tableEntries, entryCount] = (await request(0));
|
|
1874
|
-
if (status !== enums_2.SLStatus.OK) {
|
|
1875
|
-
return status;
|
|
1767
|
+
return this.queue.execute(async () => {
|
|
1768
|
+
this.checkInterpanLock();
|
|
1769
|
+
const table = [];
|
|
1770
|
+
const request = async (startIndex) => {
|
|
1771
|
+
const zdoPayload = buffaloZdo_1.BuffaloZdo.buildRoutingTableRequest(startIndex);
|
|
1772
|
+
const [status, apsFrame] = await this.sendZDORequest(networkAddress, Zdo.ClusterId.ROUTING_TABLE_REQUEST, zdoPayload, DEFAULT_APS_OPTIONS);
|
|
1773
|
+
if (status !== enums_1.SLStatus.OK) {
|
|
1774
|
+
throw new Error(`[ZDO] Failed routing table request for "${networkAddress}" (index "${startIndex}") with status=${enums_1.SLStatus[status]}.`);
|
|
1876
1775
|
}
|
|
1877
|
-
const
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1776
|
+
const result = await this.oneWaitress.startWaitingFor({
|
|
1777
|
+
target: networkAddress,
|
|
1778
|
+
apsFrame,
|
|
1779
|
+
responseClusterId: Zdo.ClusterId.ROUTING_TABLE_RESPONSE,
|
|
1780
|
+
}, DEFAULT_ZDO_REQUEST_TIMEOUT);
|
|
1781
|
+
for (const entry of result.entryList) {
|
|
1782
|
+
table.push({
|
|
1783
|
+
destinationAddress: entry.destinationAddress,
|
|
1784
|
+
status: RoutingTableStatus[entry.status], // get str value from enum to satisfy upstream's needs
|
|
1785
|
+
nextHop: entry.nextHopAddress,
|
|
1786
|
+
});
|
|
1885
1787
|
}
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1788
|
+
return [result.routingTableEntries, result.entryList.length];
|
|
1789
|
+
};
|
|
1790
|
+
let [tableEntries, entryCount] = await request(0);
|
|
1791
|
+
const size = tableEntries;
|
|
1792
|
+
let nextStartIndex = entryCount;
|
|
1793
|
+
while (table.length < size) {
|
|
1794
|
+
[tableEntries, entryCount] = await request(nextStartIndex);
|
|
1795
|
+
nextStartIndex += entryCount;
|
|
1796
|
+
}
|
|
1797
|
+
return { table };
|
|
1889
1798
|
});
|
|
1890
1799
|
}
|
|
1891
1800
|
// queued, non-InterPAN
|
|
1892
1801
|
async nodeDescriptor(networkAddress) {
|
|
1893
|
-
return
|
|
1894
|
-
this.
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
}
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
+ `of the ZigBee specification (current revision: ${CURRENT_ZIGBEE_SPEC_REVISION}).`, NS);
|
|
1925
|
-
}
|
|
1926
|
-
resolve({ type, manufacturerCode: result.manufacturerCode });
|
|
1927
|
-
return enums_2.SLStatus.OK;
|
|
1928
|
-
}, reject);
|
|
1802
|
+
return this.queue.execute(async () => {
|
|
1803
|
+
this.checkInterpanLock();
|
|
1804
|
+
const zdoPayload = buffaloZdo_1.BuffaloZdo.buildNodeDescriptorRequest(networkAddress);
|
|
1805
|
+
const [status, apsFrame] = await this.sendZDORequest(networkAddress, Zdo.ClusterId.NODE_DESCRIPTOR_REQUEST, zdoPayload, DEFAULT_APS_OPTIONS);
|
|
1806
|
+
if (status !== enums_1.SLStatus.OK) {
|
|
1807
|
+
throw new Error(`[ZDO] Failed node descriptor for "${networkAddress}" with status=${enums_1.SLStatus[status]}.`);
|
|
1808
|
+
}
|
|
1809
|
+
const result = await this.oneWaitress.startWaitingFor({
|
|
1810
|
+
target: networkAddress,
|
|
1811
|
+
apsFrame,
|
|
1812
|
+
responseClusterId: Zdo.ClusterId.NODE_DESCRIPTOR_RESPONSE,
|
|
1813
|
+
}, DEFAULT_ZDO_REQUEST_TIMEOUT);
|
|
1814
|
+
let type = 'Unknown';
|
|
1815
|
+
switch (result.logicalType) {
|
|
1816
|
+
case 0x0:
|
|
1817
|
+
type = 'Coordinator';
|
|
1818
|
+
break;
|
|
1819
|
+
case 0x1:
|
|
1820
|
+
type = 'Router';
|
|
1821
|
+
break;
|
|
1822
|
+
case 0x2:
|
|
1823
|
+
type = 'EndDevice';
|
|
1824
|
+
break;
|
|
1825
|
+
}
|
|
1826
|
+
// always 0 before rev. 21 where field was added
|
|
1827
|
+
if (result.serverMask.stackComplianceResivion < CURRENT_ZIGBEE_SPEC_REVISION) {
|
|
1828
|
+
logger_1.logger.warning(`[ZDO] Node descriptor for '${networkAddress}' reports device is only compliant to revision ` +
|
|
1829
|
+
`'${result.serverMask.stackComplianceResivion < 21 ? 'pre-21' : result.serverMask.stackComplianceResivion}' ` +
|
|
1830
|
+
`of the ZigBee specification (current revision: ${CURRENT_ZIGBEE_SPEC_REVISION}).`, NS);
|
|
1831
|
+
}
|
|
1832
|
+
return { type, manufacturerCode: result.manufacturerCode };
|
|
1929
1833
|
});
|
|
1930
1834
|
}
|
|
1931
1835
|
// queued, non-InterPAN
|
|
1932
1836
|
async activeEndpoints(networkAddress) {
|
|
1933
|
-
return
|
|
1934
|
-
this.
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
responseClusterId: Zdo.ClusterId.ACTIVE_ENDPOINTS_RESPONSE,
|
|
1947
|
-
}, DEFAULT_ZDO_REQUEST_TIMEOUT));
|
|
1948
|
-
resolve({ endpoints: result.endpointList });
|
|
1949
|
-
return enums_2.SLStatus.OK;
|
|
1950
|
-
}, reject);
|
|
1837
|
+
return this.queue.execute(async () => {
|
|
1838
|
+
this.checkInterpanLock();
|
|
1839
|
+
const zdoPayload = buffaloZdo_1.BuffaloZdo.buildActiveEndpointsRequest(networkAddress);
|
|
1840
|
+
const [status, apsFrame] = await this.sendZDORequest(networkAddress, Zdo.ClusterId.ACTIVE_ENDPOINTS_REQUEST, zdoPayload, DEFAULT_APS_OPTIONS);
|
|
1841
|
+
if (status !== enums_1.SLStatus.OK) {
|
|
1842
|
+
throw new Error(`[ZDO] Failed active endpoints request for "${networkAddress}" with status=${enums_1.SLStatus[status]}.`);
|
|
1843
|
+
}
|
|
1844
|
+
const result = await this.oneWaitress.startWaitingFor({
|
|
1845
|
+
target: networkAddress,
|
|
1846
|
+
apsFrame,
|
|
1847
|
+
responseClusterId: Zdo.ClusterId.ACTIVE_ENDPOINTS_RESPONSE,
|
|
1848
|
+
}, DEFAULT_ZDO_REQUEST_TIMEOUT);
|
|
1849
|
+
return { endpoints: result.endpointList };
|
|
1951
1850
|
});
|
|
1952
1851
|
}
|
|
1953
1852
|
// queued, non-InterPAN
|
|
1954
1853
|
async simpleDescriptor(networkAddress, endpointID) {
|
|
1955
|
-
return
|
|
1956
|
-
this.
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
deviceID: result.deviceId,
|
|
1975
|
-
inputClusters: result.inClusterList,
|
|
1976
|
-
outputClusters: result.outClusterList,
|
|
1977
|
-
});
|
|
1978
|
-
return enums_2.SLStatus.OK;
|
|
1979
|
-
}, reject);
|
|
1854
|
+
return this.queue.execute(async () => {
|
|
1855
|
+
this.checkInterpanLock();
|
|
1856
|
+
const zdoPayload = buffaloZdo_1.BuffaloZdo.buildSimpleDescriptorRequest(networkAddress, endpointID);
|
|
1857
|
+
const [status, apsFrame] = await this.sendZDORequest(networkAddress, Zdo.ClusterId.SIMPLE_DESCRIPTOR_REQUEST, zdoPayload, DEFAULT_APS_OPTIONS);
|
|
1858
|
+
if (status !== enums_1.SLStatus.OK) {
|
|
1859
|
+
throw new Error(`[ZDO] Failed simple descriptor request for "${networkAddress}" endpoint "${endpointID}" ` + `with status=${enums_1.SLStatus[status]}.`);
|
|
1860
|
+
}
|
|
1861
|
+
const result = await this.oneWaitress.startWaitingFor({
|
|
1862
|
+
target: networkAddress,
|
|
1863
|
+
apsFrame,
|
|
1864
|
+
responseClusterId: Zdo.ClusterId.SIMPLE_DESCRIPTOR_RESPONSE,
|
|
1865
|
+
}, DEFAULT_ZDO_REQUEST_TIMEOUT);
|
|
1866
|
+
return {
|
|
1867
|
+
profileID: result.profileId,
|
|
1868
|
+
endpointID: result.endpoint,
|
|
1869
|
+
deviceID: result.deviceId,
|
|
1870
|
+
inputClusters: result.inClusterList,
|
|
1871
|
+
outputClusters: result.outClusterList,
|
|
1872
|
+
};
|
|
1980
1873
|
});
|
|
1981
1874
|
}
|
|
1982
1875
|
// queued, non-InterPAN
|
|
1983
1876
|
async bind(destinationNetworkAddress, sourceIeeeAddress, sourceEndpoint, clusterID, destinationAddressOrGroup, type, destinationEndpoint) {
|
|
1984
1877
|
if (typeof destinationAddressOrGroup === 'string' && type === 'endpoint') {
|
|
1985
1878
|
// dest address is EUI64 (str), so type should always be endpoint (unicast)
|
|
1986
|
-
return
|
|
1987
|
-
this.
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
apsFrame,
|
|
2001
|
-
responseClusterId: Zdo.ClusterId.BIND_RESPONSE,
|
|
2002
|
-
}, DEFAULT_ZDO_REQUEST_TIMEOUT);
|
|
2003
|
-
resolve();
|
|
2004
|
-
return enums_2.SLStatus.OK;
|
|
2005
|
-
}, reject);
|
|
1879
|
+
return this.queue.execute(async () => {
|
|
1880
|
+
this.checkInterpanLock();
|
|
1881
|
+
const zdoPayload = buffaloZdo_1.BuffaloZdo.buildBindRequest(sourceIeeeAddress, sourceEndpoint, clusterID, Zdo.UNICAST_BINDING, destinationAddressOrGroup, undefined, // not used with UNICAST_BINDING
|
|
1882
|
+
destinationEndpoint);
|
|
1883
|
+
const [status, apsFrame] = await this.sendZDORequest(destinationNetworkAddress, Zdo.ClusterId.BIND_REQUEST, zdoPayload, DEFAULT_APS_OPTIONS);
|
|
1884
|
+
if (status !== enums_1.SLStatus.OK) {
|
|
1885
|
+
throw new Error(`[ZDO] Failed bind request for "${destinationNetworkAddress}" destination "${destinationAddressOrGroup}" ` +
|
|
1886
|
+
`endpoint "${destinationEndpoint}" with status=${enums_1.SLStatus[status]}.`);
|
|
1887
|
+
}
|
|
1888
|
+
await this.oneWaitress.startWaitingFor({
|
|
1889
|
+
target: destinationNetworkAddress,
|
|
1890
|
+
apsFrame,
|
|
1891
|
+
responseClusterId: Zdo.ClusterId.BIND_RESPONSE,
|
|
1892
|
+
}, DEFAULT_ZDO_REQUEST_TIMEOUT);
|
|
2006
1893
|
});
|
|
2007
1894
|
}
|
|
2008
1895
|
else if (typeof destinationAddressOrGroup === 'number' && type === 'group') {
|
|
2009
1896
|
// dest is group num, so type should always be group (multicast)
|
|
2010
|
-
return
|
|
2011
|
-
this.
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
target: destinationNetworkAddress,
|
|
2025
|
-
apsFrame,
|
|
2026
|
-
responseClusterId: Zdo.ClusterId.BIND_RESPONSE,
|
|
2027
|
-
}, DEFAULT_ZDO_REQUEST_TIMEOUT);
|
|
2028
|
-
resolve();
|
|
2029
|
-
return enums_2.SLStatus.OK;
|
|
2030
|
-
}, reject);
|
|
1897
|
+
return this.queue.execute(async () => {
|
|
1898
|
+
this.checkInterpanLock();
|
|
1899
|
+
const zdoPayload = buffaloZdo_1.BuffaloZdo.buildBindRequest(sourceIeeeAddress, sourceEndpoint, clusterID, Zdo.MULTICAST_BINDING, undefined, // not used with MULTICAST_BINDING
|
|
1900
|
+
destinationAddressOrGroup, undefined);
|
|
1901
|
+
const [status, apsFrame] = await this.sendZDORequest(destinationNetworkAddress, Zdo.ClusterId.BIND_REQUEST, zdoPayload, DEFAULT_APS_OPTIONS);
|
|
1902
|
+
if (status !== enums_1.SLStatus.OK) {
|
|
1903
|
+
throw new Error(`[ZDO] Failed bind request for "${destinationNetworkAddress}" group "${destinationAddressOrGroup}" ` +
|
|
1904
|
+
`with status=${enums_1.SLStatus[status]}.`);
|
|
1905
|
+
}
|
|
1906
|
+
await this.oneWaitress.startWaitingFor({
|
|
1907
|
+
target: destinationNetworkAddress,
|
|
1908
|
+
apsFrame,
|
|
1909
|
+
responseClusterId: Zdo.ClusterId.BIND_RESPONSE,
|
|
1910
|
+
}, DEFAULT_ZDO_REQUEST_TIMEOUT);
|
|
2031
1911
|
});
|
|
2032
1912
|
}
|
|
2033
1913
|
}
|
|
@@ -2035,82 +1915,61 @@ class EmberAdapter extends __1.Adapter {
|
|
|
2035
1915
|
async unbind(destinationNetworkAddress, sourceIeeeAddress, sourceEndpoint, clusterID, destinationAddressOrGroup, type, destinationEndpoint) {
|
|
2036
1916
|
if (typeof destinationAddressOrGroup === 'string' && type === 'endpoint') {
|
|
2037
1917
|
// dest address is EUI64 (str), so type should always be endpoint (unicast)
|
|
2038
|
-
return
|
|
2039
|
-
this.
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
apsFrame,
|
|
2053
|
-
responseClusterId: Zdo.ClusterId.UNBIND_RESPONSE,
|
|
2054
|
-
}, DEFAULT_ZDO_REQUEST_TIMEOUT);
|
|
2055
|
-
resolve();
|
|
2056
|
-
return enums_2.SLStatus.OK;
|
|
2057
|
-
}, reject);
|
|
1918
|
+
return this.queue.execute(async () => {
|
|
1919
|
+
this.checkInterpanLock();
|
|
1920
|
+
const zdoPayload = buffaloZdo_1.BuffaloZdo.buildUnbindRequest(sourceIeeeAddress, sourceEndpoint, clusterID, Zdo.UNICAST_BINDING, destinationAddressOrGroup, undefined, // not used with UNICAST_BINDING
|
|
1921
|
+
destinationEndpoint);
|
|
1922
|
+
const [status, apsFrame] = await this.sendZDORequest(destinationNetworkAddress, Zdo.ClusterId.UNBIND_REQUEST, zdoPayload, DEFAULT_APS_OPTIONS);
|
|
1923
|
+
if (status !== enums_1.SLStatus.OK) {
|
|
1924
|
+
throw new Error(`[ZDO] Failed unbind request for "${destinationNetworkAddress}" destination "${destinationAddressOrGroup}" ` +
|
|
1925
|
+
`endpoint "${destinationEndpoint}" with status=${enums_1.SLStatus[status]}.`);
|
|
1926
|
+
}
|
|
1927
|
+
await this.oneWaitress.startWaitingFor({
|
|
1928
|
+
target: destinationNetworkAddress,
|
|
1929
|
+
apsFrame,
|
|
1930
|
+
responseClusterId: Zdo.ClusterId.UNBIND_RESPONSE,
|
|
1931
|
+
}, DEFAULT_ZDO_REQUEST_TIMEOUT);
|
|
2058
1932
|
});
|
|
2059
1933
|
}
|
|
2060
1934
|
else if (typeof destinationAddressOrGroup === 'number' && type === 'group') {
|
|
2061
1935
|
// dest is group num, so type should always be group (multicast)
|
|
2062
|
-
return new Promise((
|
|
2063
|
-
this.requestQueue.enqueue(async () => {
|
|
2064
|
-
this.checkInterpanLock();
|
|
2065
|
-
const zdoPayload = buffaloZdo_1.BuffaloZdo.buildUnbindRequest(sourceIeeeAddress, sourceEndpoint, clusterID, Zdo.MULTICAST_BINDING, undefined, // not used with MULTICAST_BINDING
|
|
2066
|
-
destinationAddressOrGroup, undefined // not used with MULTICAST_BINDING
|
|
2067
|
-
);
|
|
2068
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
2069
|
-
const [status, apsFrame, messageTag] = await this.sendZDORequest(destinationNetworkAddress, Zdo.ClusterId.UNBIND_REQUEST, zdoPayload, DEFAULT_APS_OPTIONS);
|
|
2070
|
-
if (status !== enums_2.SLStatus.OK) {
|
|
2071
|
-
logger_1.logger.error(`[ZDO] Failed unbind request for "${destinationNetworkAddress}" group "${destinationAddressOrGroup}" `
|
|
2072
|
-
+ `with status=${enums_2.SLStatus[status]}.`, NS);
|
|
2073
|
-
return status;
|
|
2074
|
-
}
|
|
2075
|
-
await this.oneWaitress.startWaitingFor({
|
|
2076
|
-
target: destinationNetworkAddress,
|
|
2077
|
-
apsFrame,
|
|
2078
|
-
responseClusterId: Zdo.ClusterId.UNBIND_RESPONSE,
|
|
2079
|
-
}, DEFAULT_ZDO_REQUEST_TIMEOUT);
|
|
2080
|
-
resolve();
|
|
2081
|
-
return enums_2.SLStatus.OK;
|
|
2082
|
-
}, reject);
|
|
2083
|
-
});
|
|
2084
|
-
}
|
|
2085
|
-
}
|
|
2086
|
-
// queued, non-InterPAN
|
|
2087
|
-
async removeDevice(networkAddress, ieeeAddr) {
|
|
2088
|
-
return new Promise((resolve, reject) => {
|
|
2089
|
-
this.requestQueue.enqueue(async () => {
|
|
1936
|
+
return new Promise(async () => {
|
|
2090
1937
|
this.checkInterpanLock();
|
|
2091
|
-
const zdoPayload = buffaloZdo_1.BuffaloZdo.
|
|
2092
|
-
|
|
2093
|
-
const [status, apsFrame
|
|
2094
|
-
if (status !==
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
return status;
|
|
1938
|
+
const zdoPayload = buffaloZdo_1.BuffaloZdo.buildUnbindRequest(sourceIeeeAddress, sourceEndpoint, clusterID, Zdo.MULTICAST_BINDING, undefined, // not used with MULTICAST_BINDING
|
|
1939
|
+
destinationAddressOrGroup, undefined);
|
|
1940
|
+
const [status, apsFrame] = await this.sendZDORequest(destinationNetworkAddress, Zdo.ClusterId.UNBIND_REQUEST, zdoPayload, DEFAULT_APS_OPTIONS);
|
|
1941
|
+
if (status !== enums_1.SLStatus.OK) {
|
|
1942
|
+
throw new Error(`[ZDO] Failed unbind request for "${destinationNetworkAddress}" group "${destinationAddressOrGroup}" ` +
|
|
1943
|
+
`with status=${enums_1.SLStatus[status]}.`);
|
|
2098
1944
|
}
|
|
2099
1945
|
await this.oneWaitress.startWaitingFor({
|
|
2100
|
-
target:
|
|
1946
|
+
target: destinationNetworkAddress,
|
|
2101
1947
|
apsFrame,
|
|
2102
|
-
responseClusterId: Zdo.ClusterId.
|
|
1948
|
+
responseClusterId: Zdo.ClusterId.UNBIND_RESPONSE,
|
|
2103
1949
|
}, DEFAULT_ZDO_REQUEST_TIMEOUT);
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
1950
|
+
});
|
|
1951
|
+
}
|
|
1952
|
+
}
|
|
1953
|
+
// queued, non-InterPAN
|
|
1954
|
+
async removeDevice(networkAddress, ieeeAddr) {
|
|
1955
|
+
return this.queue.execute(async () => {
|
|
1956
|
+
this.checkInterpanLock();
|
|
1957
|
+
const zdoPayload = buffaloZdo_1.BuffaloZdo.buildLeaveRequest(ieeeAddr, Zdo.LeaveRequestFlags.WITHOUT_REJOIN);
|
|
1958
|
+
const [status, apsFrame] = await this.sendZDORequest(networkAddress, Zdo.ClusterId.LEAVE_REQUEST, zdoPayload, DEFAULT_APS_OPTIONS);
|
|
1959
|
+
if (status !== enums_1.SLStatus.OK) {
|
|
1960
|
+
throw new Error(`[ZDO] Failed remove device request for "${networkAddress}" target "${ieeeAddr}" ` + `with status=${enums_1.SLStatus[status]}.`);
|
|
1961
|
+
}
|
|
1962
|
+
await this.oneWaitress.startWaitingFor({
|
|
1963
|
+
target: networkAddress,
|
|
1964
|
+
apsFrame,
|
|
1965
|
+
responseClusterId: Zdo.ClusterId.LEAVE_RESPONSE,
|
|
1966
|
+
}, DEFAULT_ZDO_REQUEST_TIMEOUT);
|
|
2107
1967
|
});
|
|
2108
1968
|
}
|
|
2109
1969
|
//---- ZCL
|
|
2110
1970
|
// queued, non-InterPAN
|
|
2111
1971
|
async sendZclFrameToEndpoint(ieeeAddr, networkAddress, endpoint, zclFrame, timeout, disableResponse, disableRecovery, sourceEndpoint) {
|
|
2112
|
-
const sourceEndpointInfo = typeof sourceEndpoint === 'number' ?
|
|
2113
|
-
endpoints_1.FIXED_ENDPOINTS.find((epi) => (epi.endpoint === sourceEndpoint)) : endpoints_1.FIXED_ENDPOINTS[0];
|
|
1972
|
+
const sourceEndpointInfo = typeof sourceEndpoint === 'number' ? endpoints_1.FIXED_ENDPOINTS.find((epi) => epi.endpoint === sourceEndpoint) : endpoints_1.FIXED_ENDPOINTS[0];
|
|
2114
1973
|
const command = zclFrame.command;
|
|
2115
1974
|
let commandResponseId = null;
|
|
2116
1975
|
if (command.hasOwnProperty('response') && disableResponse === false) {
|
|
@@ -2123,48 +1982,65 @@ class EmberAdapter extends __1.Adapter {
|
|
|
2123
1982
|
profileId: sourceEndpointInfo.profileId,
|
|
2124
1983
|
clusterId: zclFrame.cluster.ID,
|
|
2125
1984
|
sourceEndpoint: sourceEndpointInfo.endpoint,
|
|
2126
|
-
destinationEndpoint:
|
|
1985
|
+
destinationEndpoint: typeof endpoint === 'number' ? endpoint : endpoints_1.FIXED_ENDPOINTS[0].endpoint,
|
|
2127
1986
|
options: DEFAULT_APS_OPTIONS,
|
|
2128
1987
|
groupId: 0,
|
|
2129
1988
|
sequence: 0, // set by stack
|
|
2130
1989
|
};
|
|
2131
1990
|
// don't RETRY if no response expected
|
|
2132
1991
|
if (commandResponseId == null) {
|
|
2133
|
-
apsFrame.options &= ~
|
|
1992
|
+
apsFrame.options &= ~enums_1.EmberApsOption.RETRY;
|
|
2134
1993
|
}
|
|
2135
1994
|
const data = zclFrame.toBuffer();
|
|
2136
|
-
return
|
|
2137
|
-
this.
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
logger_1.logger.error(`~x~> [ZCL to=${networkAddress}] Failed to send request with status=${enums_2.SLStatus[status]}.`, NS);
|
|
2145
|
-
return status; // let queue handle retry based on status
|
|
1995
|
+
return this.queue.execute(async () => {
|
|
1996
|
+
this.checkInterpanLock();
|
|
1997
|
+
logger_1.logger.debug(`~~~> [ZCL to=${networkAddress} apsFrame=${JSON.stringify(apsFrame)} header=${JSON.stringify(zclFrame.header)}]`, NS);
|
|
1998
|
+
for (let i = 1; i <= QUEUE_MAX_SEND_ATTEMPTS; i++) {
|
|
1999
|
+
let status = enums_1.SLStatus.FAIL;
|
|
2000
|
+
try {
|
|
2001
|
+
[status] = await this.ezsp.send(enums_1.EmberOutgoingMessageType.DIRECT, networkAddress, apsFrame, data, 0, // alias
|
|
2002
|
+
0);
|
|
2146
2003
|
}
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2004
|
+
catch (error) {
|
|
2005
|
+
if (error instanceof ezspError_1.EzspError) {
|
|
2006
|
+
if (error.code === enums_1.EzspStatus.NO_TX_SPACE) {
|
|
2007
|
+
status === enums_1.SLStatus.BUSY;
|
|
2008
|
+
}
|
|
2009
|
+
else if (error.code === enums_1.EzspStatus.NOT_CONNECTED) {
|
|
2010
|
+
status === enums_1.SLStatus.NETWORK_DOWN;
|
|
2011
|
+
}
|
|
2012
|
+
}
|
|
2156
2013
|
}
|
|
2157
|
-
else
|
|
2158
|
-
|
|
2159
|
-
|
|
2014
|
+
// `else if` order matters
|
|
2015
|
+
if (status === enums_1.SLStatus.OK) {
|
|
2016
|
+
break;
|
|
2160
2017
|
}
|
|
2161
|
-
|
|
2018
|
+
else if (disableRecovery || i == QUEUE_MAX_SEND_ATTEMPTS) {
|
|
2019
|
+
throw new Error(`~x~> [ZCL to=${networkAddress}] Failed to send request with status=${enums_1.SLStatus[status]}.`);
|
|
2020
|
+
}
|
|
2021
|
+
else if (status === enums_1.SLStatus.ZIGBEE_MAX_MESSAGE_LIMIT_REACHED || status === enums_1.SLStatus.BUSY) {
|
|
2022
|
+
await (0, utils_1.Wait)(QUEUE_BUSY_DEFER_MSEC);
|
|
2023
|
+
}
|
|
2024
|
+
else if (status === enums_1.SLStatus.NETWORK_DOWN) {
|
|
2025
|
+
await (0, utils_1.Wait)(QUEUE_NETWORK_DOWN_DEFER_MSEC);
|
|
2026
|
+
}
|
|
2027
|
+
}
|
|
2028
|
+
if (commandResponseId != null) {
|
|
2029
|
+
// NOTE: aps sequence number will have been set by send function
|
|
2030
|
+
const result = await this.oneWaitress.startWaitingFor({
|
|
2031
|
+
target: networkAddress,
|
|
2032
|
+
apsFrame,
|
|
2033
|
+
zclSequence: zclFrame.header.transactionSequenceNumber,
|
|
2034
|
+
commandIdentifier: commandResponseId,
|
|
2035
|
+
}, timeout || DEFAULT_ZCL_REQUEST_TIMEOUT);
|
|
2036
|
+
return result;
|
|
2037
|
+
}
|
|
2038
|
+
return null;
|
|
2162
2039
|
});
|
|
2163
2040
|
}
|
|
2164
2041
|
// queued, non-InterPAN
|
|
2165
2042
|
async sendZclFrameToGroup(groupID, zclFrame, sourceEndpoint) {
|
|
2166
|
-
const sourceEndpointInfo = typeof sourceEndpoint === 'number' ?
|
|
2167
|
-
endpoints_1.FIXED_ENDPOINTS.find((epi) => (epi.endpoint === sourceEndpoint)) : endpoints_1.FIXED_ENDPOINTS[0];
|
|
2043
|
+
const sourceEndpointInfo = typeof sourceEndpoint === 'number' ? endpoints_1.FIXED_ENDPOINTS.find((epi) => epi.endpoint === sourceEndpoint) : endpoints_1.FIXED_ENDPOINTS[0];
|
|
2168
2044
|
const apsFrame = {
|
|
2169
2045
|
profileId: sourceEndpointInfo.profileId,
|
|
2170
2046
|
clusterId: zclFrame.cluster.ID,
|
|
@@ -2175,53 +2051,44 @@ class EmberAdapter extends __1.Adapter {
|
|
|
2175
2051
|
sequence: 0, // set by stack
|
|
2176
2052
|
};
|
|
2177
2053
|
const data = zclFrame.toBuffer();
|
|
2178
|
-
return
|
|
2179
|
-
this.
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
// NOTE: since ezspMessageSentHandler could take a while here, we don't block, it'll just be logged if the delivery failed
|
|
2191
|
-
resolve();
|
|
2192
|
-
return enums_2.SLStatus.OK;
|
|
2193
|
-
}, reject);
|
|
2054
|
+
return this.queue.execute(async () => {
|
|
2055
|
+
this.checkInterpanLock();
|
|
2056
|
+
logger_1.logger.debug(`~~~> [ZCL GROUP apsFrame=${JSON.stringify(apsFrame)} header=${JSON.stringify(zclFrame.header)}]`, NS);
|
|
2057
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
2058
|
+
const [status, messageTag] = await this.ezsp.send(enums_1.EmberOutgoingMessageType.MULTICAST, apsFrame.groupId, // not used with MULTICAST
|
|
2059
|
+
apsFrame, data, 0, // alias
|
|
2060
|
+
0);
|
|
2061
|
+
if (status !== enums_1.SLStatus.OK) {
|
|
2062
|
+
throw new Error(`~x~> [ZCL GROUP] Failed to send with status=${enums_1.SLStatus[status]}.`);
|
|
2063
|
+
}
|
|
2064
|
+
// NOTE: since ezspMessageSentHandler could take a while here, we don't block, it'll just be logged if the delivery failed
|
|
2065
|
+
await (0, utils_1.Wait)(QUEUE_BUSY_DEFER_MSEC);
|
|
2194
2066
|
});
|
|
2195
2067
|
}
|
|
2196
2068
|
// queued, non-InterPAN
|
|
2197
2069
|
async sendZclFrameToAll(endpoint, zclFrame, sourceEndpoint, destination) {
|
|
2198
|
-
const sourceEndpointInfo = typeof sourceEndpoint === 'number' ?
|
|
2199
|
-
endpoints_1.FIXED_ENDPOINTS.find((epi) => (epi.endpoint === sourceEndpoint)) : endpoints_1.FIXED_ENDPOINTS[0];
|
|
2070
|
+
const sourceEndpointInfo = typeof sourceEndpoint === 'number' ? endpoints_1.FIXED_ENDPOINTS.find((epi) => epi.endpoint === sourceEndpoint) : endpoints_1.FIXED_ENDPOINTS[0];
|
|
2200
2071
|
const apsFrame = {
|
|
2201
2072
|
profileId: sourceEndpointInfo.profileId,
|
|
2202
2073
|
clusterId: zclFrame.cluster.ID,
|
|
2203
2074
|
sourceEndpoint: sourceEndpointInfo.endpoint,
|
|
2204
|
-
destinationEndpoint:
|
|
2075
|
+
destinationEndpoint: typeof endpoint === 'number' ? endpoint : endpoints_1.FIXED_ENDPOINTS[0].endpoint,
|
|
2205
2076
|
options: DEFAULT_APS_OPTIONS,
|
|
2206
2077
|
groupId: destination,
|
|
2207
2078
|
sequence: 0, // set by stack
|
|
2208
2079
|
};
|
|
2209
2080
|
const data = zclFrame.toBuffer();
|
|
2210
|
-
return
|
|
2211
|
-
this.
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
// NOTE: since ezspMessageSentHandler could take a while here, we don't block, it'll just be logged if the delivery failed
|
|
2222
|
-
resolve();
|
|
2223
|
-
return enums_2.SLStatus.OK;
|
|
2224
|
-
}, reject);
|
|
2081
|
+
return this.queue.execute(async () => {
|
|
2082
|
+
this.checkInterpanLock();
|
|
2083
|
+
logger_1.logger.debug(`~~~> [ZCL BROADCAST apsFrame=${JSON.stringify(apsFrame)} header=${JSON.stringify(zclFrame.header)}]`, NS);
|
|
2084
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
2085
|
+
const [status, messageTag] = await this.ezsp.send(enums_1.EmberOutgoingMessageType.BROADCAST, destination, apsFrame, data, 0, // alias
|
|
2086
|
+
0);
|
|
2087
|
+
if (status !== enums_1.SLStatus.OK) {
|
|
2088
|
+
throw new Error(`~x~> [ZCL BROADCAST] Failed to send with status=${enums_1.SLStatus[status]}.`);
|
|
2089
|
+
}
|
|
2090
|
+
// NOTE: since ezspMessageSentHandler could take a while here, we don't block, it'll just be logged if the delivery failed
|
|
2091
|
+
await (0, utils_1.Wait)(QUEUE_BUSY_DEFER_MSEC);
|
|
2225
2092
|
});
|
|
2226
2093
|
}
|
|
2227
2094
|
//---- InterPAN for Touchlink
|
|
@@ -2233,48 +2100,38 @@ class EmberAdapter extends __1.Adapter {
|
|
|
2233
2100
|
logger_1.logger.error(`Tried to set channel InterPAN to non-number. Channel ${channel} of type ${typeof channel}.`, NS);
|
|
2234
2101
|
return;
|
|
2235
2102
|
}
|
|
2236
|
-
return
|
|
2237
|
-
this.
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
return status;
|
|
2244
|
-
}
|
|
2245
|
-
resolve();
|
|
2246
|
-
return status;
|
|
2247
|
-
}, reject);
|
|
2103
|
+
return this.queue.execute(async () => {
|
|
2104
|
+
this.interpanLock = true;
|
|
2105
|
+
const status = await this.ezsp.ezspSetLogicalAndRadioChannel(channel);
|
|
2106
|
+
if (status !== enums_1.SLStatus.OK) {
|
|
2107
|
+
this.interpanLock = false; // XXX: ok?
|
|
2108
|
+
throw new Error(`Failed to set InterPAN channel to ${channel} with status=${enums_1.SLStatus[status]}.`);
|
|
2109
|
+
}
|
|
2248
2110
|
});
|
|
2249
2111
|
}
|
|
2250
2112
|
// queued
|
|
2251
2113
|
async sendZclFrameInterPANToIeeeAddr(zclFrame, ieeeAddress) {
|
|
2252
|
-
return
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
}
|
|
2274
|
-
// NOTE: can use ezspRawTransmitCompleteHandler if needed here
|
|
2275
|
-
resolve();
|
|
2276
|
-
return status;
|
|
2277
|
-
}, reject);
|
|
2114
|
+
return this.queue.execute(async () => {
|
|
2115
|
+
const msgBuffalo = new buffalo_1.EzspBuffalo(Buffer.alloc(consts_1.MAXIMUM_INTERPAN_LENGTH));
|
|
2116
|
+
// cache-enabled getters
|
|
2117
|
+
const sourcePanId = await this.emberGetPanId();
|
|
2118
|
+
const sourceEui64 = await this.emberGetEui64();
|
|
2119
|
+
msgBuffalo.writeUInt16(consts_1.LONG_DEST_FRAME_CONTROL | consts_1.MAC_ACK_REQUIRED); // macFrameControl
|
|
2120
|
+
msgBuffalo.writeUInt8(0); // sequence Skip Sequence number, stack sets the sequence number.
|
|
2121
|
+
msgBuffalo.writeUInt16(ZSpec.INVALID_PAN_ID); // destPanId
|
|
2122
|
+
msgBuffalo.writeIeeeAddr(ieeeAddress); // destAddress (longAddress)
|
|
2123
|
+
msgBuffalo.writeUInt16(sourcePanId); // sourcePanId
|
|
2124
|
+
msgBuffalo.writeIeeeAddr(sourceEui64); // sourceAddress
|
|
2125
|
+
msgBuffalo.writeUInt16(consts_1.STUB_NWK_FRAME_CONTROL); // nwkFrameControl
|
|
2126
|
+
msgBuffalo.writeUInt8(enums_1.EmberInterpanMessageType.UNICAST | consts_1.INTERPAN_APS_FRAME_TYPE); // apsFrameControl
|
|
2127
|
+
msgBuffalo.writeUInt16(zclFrame.cluster.ID);
|
|
2128
|
+
msgBuffalo.writeUInt16(ZSpec.TOUCHLINK_PROFILE_ID);
|
|
2129
|
+
logger_1.logger.debug(`~~~> [ZCL TOUCHLINK to=${ieeeAddress} header=${JSON.stringify(zclFrame.header)}]`, NS);
|
|
2130
|
+
const status = await this.ezsp.ezspSendRawMessage(Buffer.concat([msgBuffalo.getWritten(), zclFrame.toBuffer()]), enums_1.EmberTransmitPriority.NORMAL, true);
|
|
2131
|
+
if (status !== enums_1.SLStatus.OK) {
|
|
2132
|
+
throw new Error(`~x~> [ZCL TOUCHLINK to=${ieeeAddress}] Failed to send with status=${enums_1.SLStatus[status]}.`);
|
|
2133
|
+
}
|
|
2134
|
+
// NOTE: can use ezspRawTransmitCompleteHandler if needed here
|
|
2278
2135
|
});
|
|
2279
2136
|
}
|
|
2280
2137
|
// queued
|
|
@@ -2289,60 +2146,51 @@ class EmberAdapter extends __1.Adapter {
|
|
|
2289
2146
|
clusterId: zclFrame.cluster.ID,
|
|
2290
2147
|
sourceEndpoint: 0,
|
|
2291
2148
|
destinationEndpoint: 0,
|
|
2292
|
-
options:
|
|
2149
|
+
options: enums_1.EmberApsOption.NONE,
|
|
2293
2150
|
groupId: ZSpec.BroadcastAddress.SLEEPY,
|
|
2294
2151
|
sequence: 0, // set by stack
|
|
2295
2152
|
};
|
|
2296
|
-
return
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
}, timeout || DEFAULT_ZCL_REQUEST_TIMEOUT * 2)); // XXX: touchlink timeout?
|
|
2326
|
-
resolve(result);
|
|
2327
|
-
return enums_2.SLStatus.OK;
|
|
2328
|
-
}, reject);
|
|
2153
|
+
return this.queue.execute(async () => {
|
|
2154
|
+
const msgBuffalo = new buffalo_1.EzspBuffalo(Buffer.alloc(consts_1.MAXIMUM_INTERPAN_LENGTH));
|
|
2155
|
+
// cache-enabled getters
|
|
2156
|
+
const sourcePanId = await this.emberGetPanId();
|
|
2157
|
+
const sourceEui64 = await this.emberGetEui64();
|
|
2158
|
+
msgBuffalo.writeUInt16(consts_1.SHORT_DEST_FRAME_CONTROL); // macFrameControl
|
|
2159
|
+
msgBuffalo.writeUInt8(0); // sequence Skip Sequence number, stack sets the sequence number.
|
|
2160
|
+
msgBuffalo.writeUInt16(ZSpec.INVALID_PAN_ID); // destPanId
|
|
2161
|
+
msgBuffalo.writeUInt16(apsFrame.groupId); // destAddress (longAddress)
|
|
2162
|
+
msgBuffalo.writeUInt16(sourcePanId); // sourcePanId
|
|
2163
|
+
msgBuffalo.writeIeeeAddr(sourceEui64); // sourceAddress
|
|
2164
|
+
msgBuffalo.writeUInt16(consts_1.STUB_NWK_FRAME_CONTROL); // nwkFrameControl
|
|
2165
|
+
msgBuffalo.writeUInt8(enums_1.EmberInterpanMessageType.BROADCAST | consts_1.INTERPAN_APS_FRAME_TYPE); // apsFrameControl
|
|
2166
|
+
msgBuffalo.writeUInt16(apsFrame.clusterId);
|
|
2167
|
+
msgBuffalo.writeUInt16(apsFrame.profileId);
|
|
2168
|
+
const data = Buffer.concat([msgBuffalo.getWritten(), zclFrame.toBuffer()]);
|
|
2169
|
+
logger_1.logger.debug(`~~~> [ZCL TOUCHLINK BROADCAST header=${JSON.stringify(zclFrame.header)}]`, NS);
|
|
2170
|
+
const status = await this.ezsp.ezspSendRawMessage(data, enums_1.EmberTransmitPriority.NORMAL, true);
|
|
2171
|
+
if (status !== enums_1.SLStatus.OK) {
|
|
2172
|
+
throw new Error(`~x~> [ZCL TOUCHLINK BROADCAST] Failed to send with status=${enums_1.SLStatus[status]}.`);
|
|
2173
|
+
}
|
|
2174
|
+
// NOTE: can use ezspRawTransmitCompleteHandler if needed here
|
|
2175
|
+
const result = await this.oneWaitress.startWaitingFor({
|
|
2176
|
+
target: null,
|
|
2177
|
+
apsFrame: apsFrame,
|
|
2178
|
+
zclSequence: zclFrame.header.transactionSequenceNumber,
|
|
2179
|
+
commandIdentifier: command.response,
|
|
2180
|
+
}, timeout || DEFAULT_ZCL_REQUEST_TIMEOUT * 2); // XXX: touchlink timeout?
|
|
2181
|
+
return result;
|
|
2329
2182
|
});
|
|
2330
2183
|
}
|
|
2331
2184
|
// queued
|
|
2332
2185
|
async restoreChannelInterPAN() {
|
|
2333
|
-
return
|
|
2334
|
-
this.
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
await (0, utils_1.Wait)(3000);
|
|
2342
|
-
this.interpanLock = false;
|
|
2343
|
-
resolve();
|
|
2344
|
-
return status;
|
|
2345
|
-
}, reject);
|
|
2186
|
+
return this.queue.execute(async () => {
|
|
2187
|
+
const status = await this.ezsp.ezspSetLogicalAndRadioChannel(this.networkOptions.channelList[0]);
|
|
2188
|
+
if (status !== enums_1.SLStatus.OK) {
|
|
2189
|
+
throw new Error(`Failed to restore InterPAN channel to ${this.networkOptions.channelList[0]} with status=${enums_1.SLStatus[status]}.`);
|
|
2190
|
+
}
|
|
2191
|
+
// let adapter settle down
|
|
2192
|
+
await (0, utils_1.Wait)(QUEUE_NETWORK_DOWN_DEFER_MSEC);
|
|
2193
|
+
this.interpanLock = false;
|
|
2346
2194
|
});
|
|
2347
2195
|
}
|
|
2348
2196
|
//-- END Adapter implementation
|
|
@@ -2350,7 +2198,7 @@ class EmberAdapter extends __1.Adapter {
|
|
|
2350
2198
|
if (this.interpanLock) {
|
|
2351
2199
|
logger_1.logger.error(`[INTERPAN MODE] Cannot execute non-InterPAN commands.`, NS);
|
|
2352
2200
|
// will be caught by request queue and rejected internally.
|
|
2353
|
-
throw new ezspError_1.EzspError(
|
|
2201
|
+
throw new ezspError_1.EzspError(enums_1.EzspStatus.ERROR_INVALID_CALL);
|
|
2354
2202
|
}
|
|
2355
2203
|
}
|
|
2356
2204
|
}
|