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