zigbee-herdsman 0.50.1 → 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 +20 -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 +27 -445
- package/dist/adapter/ember/adapter/emberAdapter.d.ts.map +1 -1
- package/dist/adapter/ember/adapter/emberAdapter.js +888 -1681
- 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 +5 -4
- package/dist/adapter/ember/adapter/oneWaitress.d.ts.map +1 -1
- package/dist/adapter/ember/adapter/oneWaitress.js +44 -30
- package/dist/adapter/ember/adapter/oneWaitress.js.map +1 -1
- package/dist/adapter/ember/adapter/tokensManager.d.ts +11 -10
- package/dist/adapter/ember/adapter/tokensManager.d.ts.map +1 -1
- package/dist/adapter/ember/adapter/tokensManager.js +118 -117
- package/dist/adapter/ember/adapter/tokensManager.js.map +1 -1
- package/dist/adapter/ember/consts.d.ts +1 -0
- package/dist/adapter/ember/consts.d.ts.map +1 -1
- package/dist/adapter/ember/consts.js +29 -27
- package/dist/adapter/ember/consts.js.map +1 -1
- package/dist/adapter/ember/enums.d.ts +130 -409
- package/dist/adapter/ember/enums.d.ts.map +1 -1
- package/dist/adapter/ember/enums.js +146 -484
- package/dist/adapter/ember/enums.js.map +1 -1
- package/dist/adapter/ember/ezsp/buffalo.d.ts +15 -4
- package/dist/adapter/ember/ezsp/buffalo.d.ts.map +1 -1
- package/dist/adapter/ember/ezsp/buffalo.js +148 -38
- package/dist/adapter/ember/ezsp/buffalo.js.map +1 -1
- package/dist/adapter/ember/ezsp/consts.d.ts +2 -1
- package/dist/adapter/ember/ezsp/consts.d.ts.map +1 -1
- package/dist/adapter/ember/ezsp/consts.js +6 -5
- package/dist/adapter/ember/ezsp/consts.js.map +1 -1
- package/dist/adapter/ember/ezsp/enums.d.ts +160 -49
- package/dist/adapter/ember/ezsp/enums.d.ts.map +1 -1
- package/dist/adapter/ember/ezsp/enums.js +177 -49
- package/dist/adapter/ember/ezsp/enums.js.map +1 -1
- package/dist/adapter/ember/ezsp/ezsp.d.ts +991 -729
- package/dist/adapter/ember/ezsp/ezsp.d.ts.map +1 -1
- package/dist/adapter/ember/ezsp/ezsp.js +3219 -2683
- package/dist/adapter/ember/ezsp/ezsp.js.map +1 -1
- package/dist/adapter/ember/ezspError.d.ts +6 -0
- package/dist/adapter/ember/ezspError.d.ts.map +1 -0
- package/dist/adapter/ember/ezspError.js +13 -0
- package/dist/adapter/ember/ezspError.js.map +1 -0
- package/dist/adapter/ember/types.d.ts +91 -43
- package/dist/adapter/ember/types.d.ts.map +1 -1
- package/dist/adapter/ember/uart/ash.d.ts +16 -12
- package/dist/adapter/ember/uart/ash.d.ts.map +1 -1
- package/dist/adapter/ember/uart/ash.js +81 -82
- 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 +0 -8
- package/dist/adapter/ember/utils/math.d.ts.map +1 -1
- package/dist/adapter/ember/utils/math.js +12 -31
- 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 -57
- package/dist/adapter/ember/adapter/requestQueue.d.ts.map +0 -1
- package/dist/adapter/ember/adapter/requestQueue.js +0 -139
- package/dist/adapter/ember/adapter/requestQueue.js.map +0 -1
- package/dist/adapter/ember/zdo.d.ts +0 -925
- package/dist/adapter/ember/zdo.d.ts.map +0 -1
- package/dist/adapter/ember/zdo.js +0 -723
- package/dist/adapter/ember/zdo.js.map +0 -1
|
@@ -28,32 +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
|
+
const ZSpec = __importStar(require("../../../zspec"));
|
|
38
39
|
const Zcl = __importStar(require("../../../zspec/zcl"));
|
|
39
|
-
const
|
|
40
|
-
const
|
|
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
|
|
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
|
|
51
|
-
const endpoints_1 = require("./endpoints");
|
|
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");
|
|
52
52
|
const initters_1 = require("../utils/initters");
|
|
53
|
-
const
|
|
53
|
+
const math_1 = require("../utils/math");
|
|
54
|
+
const endpoints_1 = require("./endpoints");
|
|
54
55
|
const oneWaitress_1 = require("./oneWaitress");
|
|
55
|
-
const logger_1 = require("../../../utils/logger");
|
|
56
|
-
// import {EmberTokensManager} from "./tokensManager";
|
|
57
56
|
const NS = 'zh:ember';
|
|
58
57
|
/** Enum to pass strings from numbers up to Z2M. */
|
|
59
58
|
var RoutingTableStatus;
|
|
@@ -67,7 +66,6 @@ var RoutingTableStatus;
|
|
|
67
66
|
RoutingTableStatus[RoutingTableStatus["RESERVED2"] = 6] = "RESERVED2";
|
|
68
67
|
RoutingTableStatus[RoutingTableStatus["RESERVED3"] = 7] = "RESERVED3";
|
|
69
68
|
})(RoutingTableStatus || (RoutingTableStatus = {}));
|
|
70
|
-
;
|
|
71
69
|
var NetworkInitAction;
|
|
72
70
|
(function (NetworkInitAction) {
|
|
73
71
|
/** Ain't that nice! */
|
|
@@ -81,7 +79,6 @@ var NetworkInitAction;
|
|
|
81
79
|
/** Re-form the network using full backed-up data. */
|
|
82
80
|
NetworkInitAction[NetworkInitAction["FORM_BACKUP"] = 4] = "FORM_BACKUP";
|
|
83
81
|
})(NetworkInitAction || (NetworkInitAction = {}));
|
|
84
|
-
;
|
|
85
82
|
/** NOTE: Drivers can override `manufacturer`. Verify logic doesn't work in most cases anyway. */
|
|
86
83
|
const autoDetectDefinitions = [
|
|
87
84
|
/** NOTE: Manuf code "0x1321" for "Shenzhen Sonoff Technologies Co., Ltd." */
|
|
@@ -95,9 +92,9 @@ const autoDetectDefinitions = [
|
|
|
95
92
|
* for coordination between the two entities, and allows both to send ZDO
|
|
96
93
|
* messages with non-conflicting sequence numbers.
|
|
97
94
|
*/
|
|
98
|
-
const APPLICATION_ZDO_SEQUENCE_MASK =
|
|
99
|
-
/** Current revision of the spec by zigbee alliance
|
|
100
|
-
const CURRENT_ZIGBEE_SPEC_REVISION =
|
|
95
|
+
const APPLICATION_ZDO_SEQUENCE_MASK = 0x7f;
|
|
96
|
+
/** Current revision of the spec by zigbee alliance supported by Z2M. */
|
|
97
|
+
const CURRENT_ZIGBEE_SPEC_REVISION = 22;
|
|
101
98
|
/** Each scan period is 15.36ms. Scan for at least 200ms (2^4 + 1 periods) to pick up WiFi beacon frames. */
|
|
102
99
|
const ENERGY_SCAN_DURATION = 4;
|
|
103
100
|
/** Oldest supported EZSP version for backups. Don't take the risk to restore a broken network until older backup versions can be investigated. */
|
|
@@ -107,6 +104,10 @@ const BACKUP_OLDEST_SUPPORTED_EZSP_VERSION = 12;
|
|
|
107
104
|
* NOTE: This is blocking the request queue, so we shouldn't go crazy high.
|
|
108
105
|
*/
|
|
109
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;
|
|
110
111
|
/**
|
|
111
112
|
* Default stack configuration values.
|
|
112
113
|
* @see https://www.silabs.com/documents/public/user-guides/ug100-ezsp-reference-guide.pdf 2.3.1 for descriptions/RAM costs
|
|
@@ -123,20 +124,12 @@ const DEFAULT_STACK_CONFIG = {
|
|
|
123
124
|
CONCENTRATOR_DELIVERY_FAILURE_THRESHOLD: 1, // zigpc: 1, ZigbeeMinimalHost: 3
|
|
124
125
|
CONCENTRATOR_MAX_HOPS: 0, // zigpc: 0
|
|
125
126
|
MAX_END_DEVICE_CHILDREN: 32, // zigpc: 6, nabucasa: 32, Dongle-E (Sonoff firmware): 32
|
|
126
|
-
APS_UNICAST_MESSAGE_COUNT: 32, // zigpc: 10, darkxst: 20, nabucasa: 20
|
|
127
|
-
RETRY_QUEUE_SIZE: 16, // nabucasa: 16
|
|
128
|
-
ADDRESS_TABLE_SIZE: 16, // zigpc: 32, darkxst: 16, nabucasa: 16
|
|
129
|
-
TRUST_CENTER_ADDRESS_CACHE_SIZE: 2,
|
|
130
|
-
KEY_TABLE_SIZE: 0, // zigpc: 4
|
|
131
|
-
BINDING_TABLE_SIZE: 32, // zigpc: 2, Z3GatewayGPCombo: 5, nabucasa: 32
|
|
132
|
-
BROADCAST_TABLE_SIZE: 15, // zigpc: 15, Z3GatewayGPCombo: 35 - NOTE: Sonoff Dongle-E fails at 35
|
|
133
|
-
MULTICAST_TABLE_SIZE: 16, // darkxst: 16, nabucasa: 16 - NOTE: should always be at least enough to register FIXED_ENDPOINTS multicastIds
|
|
134
|
-
NEIGHBOR_TABLE_SIZE: 26, // zigpc: 16, darkxst: 26, nabucasa: 26
|
|
135
|
-
SOURCE_ROUTE_TABLE_SIZE: 200, // Z3GatewayGPCombo: 100, darkxst: 200, nabucasa: 200
|
|
136
127
|
TRANSIENT_DEVICE_TIMEOUT: 10000,
|
|
137
128
|
END_DEVICE_POLL_TIMEOUT: 8, // zigpc: 8
|
|
138
129
|
TRANSIENT_KEY_TIMEOUT_S: 300, // zigpc: 65535
|
|
139
130
|
};
|
|
131
|
+
/** Default behavior is to disable app key requests */
|
|
132
|
+
const ALLOW_APP_KEY_REQUESTS = false;
|
|
140
133
|
/**
|
|
141
134
|
* NOTE: This from SDK is currently ignored here because of issues in below links:
|
|
142
135
|
* - BUGZID 12261: Concentrators use MTORRs for route discovery and should not enable route discovery in the APS options.
|
|
@@ -145,13 +138,7 @@ const DEFAULT_STACK_CONFIG = {
|
|
|
145
138
|
*
|
|
146
139
|
* Removing `ENABLE_ROUTE_DISCOVERY` leads to devices that won't reconnect/go offline, and various other issues. Keeping it for now.
|
|
147
140
|
*/
|
|
148
|
-
const DEFAULT_APS_OPTIONS =
|
|
149
|
-
/**
|
|
150
|
-
* Enabling this allows to immediately reject requests that won't be able to get to their destination.
|
|
151
|
-
* However, it causes more NCP calls, notably to get the source route overhead.
|
|
152
|
-
* XXX: Needs further testing before enabling
|
|
153
|
-
*/
|
|
154
|
-
const CHECK_APS_PAYLOAD_LENGTH = false;
|
|
141
|
+
const DEFAULT_APS_OPTIONS = enums_1.EmberApsOption.RETRY | enums_1.EmberApsOption.ENABLE_ROUTE_DISCOVERY | enums_1.EmberApsOption.ENABLE_ADDRESS_DISCOVERY;
|
|
155
142
|
/** Time for a ZDO request to get a callback response. ASH is 2400*6 for ACK timeout. */
|
|
156
143
|
const DEFAULT_ZDO_REQUEST_TIMEOUT = 15000; // msec
|
|
157
144
|
/** Time for a ZCL request to get a callback response. ASH is 2400*6 for ACK timeout. */
|
|
@@ -169,7 +156,7 @@ const DEFAULT_MANUFACTURER_CODE = Zcl.ManufacturerCode.SILICON_LABORATORIES;
|
|
|
169
156
|
const WORKAROUND_JOIN_MANUF_IEEE_PREFIX_TO_CODE = {
|
|
170
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...
|
|
171
158
|
// "0x18c23c" https://maclookup.app/vendors/lumi-united-technology-co-ltd
|
|
172
|
-
|
|
159
|
+
'0x54ef44': Zcl.ManufacturerCode.LUMI_UNITED_TECHOLOGY_LTD_SHENZHEN,
|
|
173
160
|
};
|
|
174
161
|
/**
|
|
175
162
|
* Relay calls between Z2M and EZSP-layer and handle any error that might occur via queue & waitress.
|
|
@@ -182,12 +169,10 @@ class EmberAdapter extends __1.Adapter {
|
|
|
182
169
|
stackConfig;
|
|
183
170
|
ezsp;
|
|
184
171
|
version;
|
|
185
|
-
|
|
172
|
+
queue;
|
|
186
173
|
oneWaitress;
|
|
187
174
|
/** Periodically retrieve counters then clear them. */
|
|
188
175
|
watchdogCountersHandle;
|
|
189
|
-
/** Hold ZDO request in process. */
|
|
190
|
-
zdoRequestBuffalo;
|
|
191
176
|
/** Sequence number used for ZDO requests. static uint8_t */
|
|
192
177
|
zdoRequestSequence;
|
|
193
178
|
/** Default radius used for broadcast ZDO requests. uint8_t */
|
|
@@ -202,20 +187,18 @@ class EmberAdapter extends __1.Adapter {
|
|
|
202
187
|
constructor(networkOptions, serialPortOptions, backupPath, adapterOptions) {
|
|
203
188
|
super(networkOptions, serialPortOptions, backupPath, adapterOptions);
|
|
204
189
|
this.stackConfig = this.loadStackConfig();
|
|
205
|
-
const delay =
|
|
190
|
+
const delay = typeof this.adapterOptions.delay === 'number' ? Math.min(Math.max(this.adapterOptions.delay, 5), 60) : 5;
|
|
206
191
|
logger_1.logger.debug(`Using delay=${delay}.`, NS);
|
|
207
|
-
this.
|
|
192
|
+
this.queue = new utils_1.Queue(typeof this.adapterOptions.concurrent === 'number' ? Math.min(Math.max(this.adapterOptions.concurrent, 1), 32) : 16);
|
|
208
193
|
this.oneWaitress = new oneWaitress_1.EmberOneWaitress();
|
|
209
|
-
this.
|
|
210
|
-
this.ezsp = new ezsp_1.Ezsp(delay, serialPortOptions);
|
|
211
|
-
this.ezsp.on(ezsp_1.EzspEvents.STACK_STATUS, this.onStackStatus.bind(this));
|
|
212
|
-
this.ezsp.on(ezsp_1.EzspEvents.MESSAGE_SENT, this.onMessageSent.bind(this));
|
|
194
|
+
this.ezsp = new ezsp_1.Ezsp(serialPortOptions);
|
|
213
195
|
this.ezsp.on(ezsp_1.EzspEvents.ZDO_RESPONSE, this.onZDOResponse.bind(this));
|
|
214
|
-
this.ezsp.on(ezsp_1.EzspEvents.END_DEVICE_ANNOUNCE, this.onEndDeviceAnnounce.bind(this));
|
|
215
196
|
this.ezsp.on(ezsp_1.EzspEvents.INCOMING_MESSAGE, this.onIncomingMessage.bind(this));
|
|
216
197
|
this.ezsp.on(ezsp_1.EzspEvents.TOUCHLINK_MESSAGE, this.onTouchlinkMessage.bind(this));
|
|
217
|
-
this.ezsp.on(ezsp_1.EzspEvents.
|
|
198
|
+
this.ezsp.on(ezsp_1.EzspEvents.STACK_STATUS, this.onStackStatus.bind(this));
|
|
218
199
|
this.ezsp.on(ezsp_1.EzspEvents.TRUST_CENTER_JOIN, this.onTrustCenterJoin.bind(this));
|
|
200
|
+
this.ezsp.on(ezsp_1.EzspEvents.MESSAGE_SENT, this.onMessageSent.bind(this));
|
|
201
|
+
this.ezsp.on(ezsp_1.EzspEvents.GREENPOWER_MESSAGE, this.onGreenpowerMessage.bind(this));
|
|
219
202
|
}
|
|
220
203
|
loadStackConfig() {
|
|
221
204
|
// store stack config in same dir as backup
|
|
@@ -224,16 +207,16 @@ class EmberAdapter extends __1.Adapter {
|
|
|
224
207
|
const customConfig = JSON.parse((0, fs_1.readFileSync)(configPath, 'utf8'));
|
|
225
208
|
// set any undefined config to default
|
|
226
209
|
const config = { ...DEFAULT_STACK_CONFIG, ...customConfig };
|
|
227
|
-
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);
|
|
228
211
|
if (!['high', 'low'].includes(config.CONCENTRATOR_RAM_TYPE)) {
|
|
229
212
|
config.CONCENTRATOR_RAM_TYPE = DEFAULT_STACK_CONFIG.CONCENTRATOR_RAM_TYPE;
|
|
230
213
|
logger_1.logger.error(`[STACK CONFIG] Invalid CONCENTRATOR_RAM_TYPE, using default.`, NS);
|
|
231
214
|
}
|
|
232
|
-
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) {
|
|
233
216
|
config.CONCENTRATOR_MIN_TIME = DEFAULT_STACK_CONFIG.CONCENTRATOR_MIN_TIME;
|
|
234
217
|
logger_1.logger.error(`[STACK CONFIG] Invalid CONCENTRATOR_MIN_TIME, using default.`, NS);
|
|
235
218
|
}
|
|
236
|
-
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) {
|
|
237
220
|
config.CONCENTRATOR_MAX_TIME = DEFAULT_STACK_CONFIG.CONCENTRATOR_MAX_TIME;
|
|
238
221
|
logger_1.logger.error(`[STACK CONFIG] Invalid CONCENTRATOR_MAX_TIME, using default.`, NS);
|
|
239
222
|
}
|
|
@@ -253,47 +236,6 @@ class EmberAdapter extends __1.Adapter {
|
|
|
253
236
|
config.MAX_END_DEVICE_CHILDREN = DEFAULT_STACK_CONFIG.MAX_END_DEVICE_CHILDREN;
|
|
254
237
|
logger_1.logger.error(`[STACK CONFIG] Invalid MAX_END_DEVICE_CHILDREN, using default.`, NS);
|
|
255
238
|
}
|
|
256
|
-
if (!inRange(config.APS_UNICAST_MESSAGE_COUNT, 1, 255)) {
|
|
257
|
-
config.APS_UNICAST_MESSAGE_COUNT = DEFAULT_STACK_CONFIG.APS_UNICAST_MESSAGE_COUNT;
|
|
258
|
-
logger_1.logger.error(`[STACK CONFIG] Invalid APS_UNICAST_MESSAGE_COUNT, using default.`, NS);
|
|
259
|
-
}
|
|
260
|
-
if (!inRange(config.RETRY_QUEUE_SIZE, 0, 255)) {
|
|
261
|
-
config.RETRY_QUEUE_SIZE = DEFAULT_STACK_CONFIG.RETRY_QUEUE_SIZE;
|
|
262
|
-
logger_1.logger.error(`[STACK CONFIG] Invalid RETRY_QUEUE_SIZE, using default.`, NS);
|
|
263
|
-
}
|
|
264
|
-
if (!inRange(config.ADDRESS_TABLE_SIZE, 1, 250)) {
|
|
265
|
-
config.ADDRESS_TABLE_SIZE = DEFAULT_STACK_CONFIG.ADDRESS_TABLE_SIZE;
|
|
266
|
-
logger_1.logger.error(`[STACK CONFIG] Invalid ADDRESS_TABLE_SIZE, using default.`, NS);
|
|
267
|
-
}
|
|
268
|
-
if (!inRange(config.TRUST_CENTER_ADDRESS_CACHE_SIZE, 0, 4)) {
|
|
269
|
-
config.TRUST_CENTER_ADDRESS_CACHE_SIZE = DEFAULT_STACK_CONFIG.TRUST_CENTER_ADDRESS_CACHE_SIZE;
|
|
270
|
-
logger_1.logger.error(`[STACK CONFIG] Invalid TRUST_CENTER_ADDRESS_CACHE_SIZE, using default.`, NS);
|
|
271
|
-
}
|
|
272
|
-
if (!inRange(config.KEY_TABLE_SIZE, 0, 127)) {
|
|
273
|
-
config.KEY_TABLE_SIZE = DEFAULT_STACK_CONFIG.KEY_TABLE_SIZE;
|
|
274
|
-
logger_1.logger.error(`[STACK CONFIG] Invalid KEY_TABLE_SIZE, using default.`, NS);
|
|
275
|
-
}
|
|
276
|
-
if (!inRange(config.BINDING_TABLE_SIZE, 0, 127)) {
|
|
277
|
-
config.BINDING_TABLE_SIZE = DEFAULT_STACK_CONFIG.BINDING_TABLE_SIZE;
|
|
278
|
-
logger_1.logger.error(`[STACK CONFIG] Invalid BINDING_TABLE_SIZE, using default.`, NS);
|
|
279
|
-
}
|
|
280
|
-
if (!inRange(config.BROADCAST_TABLE_SIZE, 15, 254)) {
|
|
281
|
-
config.BROADCAST_TABLE_SIZE = DEFAULT_STACK_CONFIG.BROADCAST_TABLE_SIZE;
|
|
282
|
-
logger_1.logger.error(`[STACK CONFIG] Invalid BROADCAST_TABLE_SIZE, using default.`, NS);
|
|
283
|
-
}
|
|
284
|
-
// min should always be enough to cover `multicastIds` in `FIXED_ENDPOINTS`
|
|
285
|
-
if (!inRange(config.MULTICAST_TABLE_SIZE, 5, 250)) {
|
|
286
|
-
config.MULTICAST_TABLE_SIZE = DEFAULT_STACK_CONFIG.MULTICAST_TABLE_SIZE;
|
|
287
|
-
logger_1.logger.error(`[STACK CONFIG] Invalid MULTICAST_TABLE_SIZE, using default.`, NS);
|
|
288
|
-
}
|
|
289
|
-
if (![16, 26].includes(config.NEIGHBOR_TABLE_SIZE)) {
|
|
290
|
-
config.NEIGHBOR_TABLE_SIZE = DEFAULT_STACK_CONFIG.NEIGHBOR_TABLE_SIZE;
|
|
291
|
-
logger_1.logger.error(`[STACK CONFIG] Invalid NEIGHBOR_TABLE_SIZE, using default.`, NS);
|
|
292
|
-
}
|
|
293
|
-
if (!inRange(config.SOURCE_ROUTE_TABLE_SIZE, 0, 254)) {
|
|
294
|
-
config.SOURCE_ROUTE_TABLE_SIZE = DEFAULT_STACK_CONFIG.SOURCE_ROUTE_TABLE_SIZE;
|
|
295
|
-
logger_1.logger.error(`[STACK CONFIG] Invalid SOURCE_ROUTE_TABLE_SIZE, using default.`, NS);
|
|
296
|
-
}
|
|
297
239
|
if (!inRange(config.TRANSIENT_DEVICE_TIMEOUT, 0, 65535)) {
|
|
298
240
|
config.TRANSIENT_DEVICE_TIMEOUT = DEFAULT_STACK_CONFIG.TRANSIENT_DEVICE_TIMEOUT;
|
|
299
241
|
logger_1.logger.error(`[STACK CONFIG] Invalid TRANSIENT_DEVICE_TIMEOUT, using default.`, NS);
|
|
@@ -321,35 +263,35 @@ class EmberAdapter extends __1.Adapter {
|
|
|
321
263
|
// to be extra careful, should clear network cache upon receiving this.
|
|
322
264
|
this.clearNetworkCache();
|
|
323
265
|
switch (status) {
|
|
324
|
-
case
|
|
266
|
+
case enums_1.SLStatus.NETWORK_UP: {
|
|
325
267
|
this.oneWaitress.resolveEvent(oneWaitress_1.OneWaitressEvents.STACK_STATUS_NETWORK_UP);
|
|
326
268
|
logger_1.logger.info(`[STACK STATUS] Network up.`, NS);
|
|
327
269
|
break;
|
|
328
270
|
}
|
|
329
|
-
case
|
|
271
|
+
case enums_1.SLStatus.NETWORK_DOWN: {
|
|
330
272
|
this.oneWaitress.resolveEvent(oneWaitress_1.OneWaitressEvents.STACK_STATUS_NETWORK_DOWN);
|
|
331
273
|
logger_1.logger.info(`[STACK STATUS] Network down.`, NS);
|
|
332
274
|
break;
|
|
333
275
|
}
|
|
334
|
-
case
|
|
276
|
+
case enums_1.SLStatus.ZIGBEE_NETWORK_OPENED: {
|
|
335
277
|
this.oneWaitress.resolveEvent(oneWaitress_1.OneWaitressEvents.STACK_STATUS_NETWORK_OPENED);
|
|
336
278
|
logger_1.logger.info(`[STACK STATUS] Network opened.`, NS);
|
|
337
279
|
break;
|
|
338
280
|
}
|
|
339
|
-
case
|
|
281
|
+
case enums_1.SLStatus.ZIGBEE_NETWORK_CLOSED: {
|
|
340
282
|
this.oneWaitress.resolveEvent(oneWaitress_1.OneWaitressEvents.STACK_STATUS_NETWORK_CLOSED);
|
|
341
283
|
logger_1.logger.info(`[STACK STATUS] Network closed.`, NS);
|
|
342
284
|
break;
|
|
343
285
|
}
|
|
344
|
-
case
|
|
286
|
+
case enums_1.SLStatus.ZIGBEE_CHANNEL_CHANGED: {
|
|
345
287
|
this.oneWaitress.resolveEvent(oneWaitress_1.OneWaitressEvents.STACK_STATUS_CHANNEL_CHANGED);
|
|
346
288
|
// invalidate cache
|
|
347
|
-
this.networkCache.parameters.radioChannel =
|
|
289
|
+
this.networkCache.parameters.radioChannel = consts_1.INVALID_RADIO_CHANNEL;
|
|
348
290
|
logger_1.logger.info(`[STACK STATUS] Channel changed.`, NS);
|
|
349
291
|
break;
|
|
350
292
|
}
|
|
351
293
|
default: {
|
|
352
|
-
logger_1.logger.debug(`[STACK STATUS] ${
|
|
294
|
+
logger_1.logger.debug(`[STACK STATUS] ${enums_1.SLStatus[status]}.`, NS);
|
|
353
295
|
break;
|
|
354
296
|
}
|
|
355
297
|
}
|
|
@@ -364,17 +306,17 @@ class EmberAdapter extends __1.Adapter {
|
|
|
364
306
|
* @param messageTag
|
|
365
307
|
* @param status
|
|
366
308
|
*/
|
|
367
|
-
async onMessageSent(type, indexOrDestination, apsFrame, messageTag
|
|
368
|
-
if (status ===
|
|
309
|
+
async onMessageSent(status, type, indexOrDestination, apsFrame, messageTag) {
|
|
310
|
+
if (status === enums_1.SLStatus.ZIGBEE_DELIVERY_FAILED) {
|
|
369
311
|
// no ACK was received from the destination
|
|
370
312
|
switch (type) {
|
|
371
|
-
case
|
|
372
|
-
case
|
|
373
|
-
case
|
|
374
|
-
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: {
|
|
375
317
|
// BC/MC not checking for message sent, avoid unnecessary waitress lookups
|
|
376
|
-
logger_1.logger.error(`Delivery of ${
|
|
377
|
-
|
|
318
|
+
logger_1.logger.error(`Delivery of ${enums_1.EmberOutgoingMessageType[type]} failed for "${indexOrDestination}" ` +
|
|
319
|
+
`[apsFrame=${JSON.stringify(apsFrame)} messageTag=${messageTag}]`, NS);
|
|
378
320
|
break;
|
|
379
321
|
}
|
|
380
322
|
default: {
|
|
@@ -384,9 +326,11 @@ class EmberAdapter extends __1.Adapter {
|
|
|
384
326
|
}
|
|
385
327
|
}
|
|
386
328
|
}
|
|
387
|
-
else if (status ===
|
|
388
|
-
if (type ===
|
|
389
|
-
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)) {
|
|
390
334
|
// workaround for devices using multicast for state update (coordinator passthrough)
|
|
391
335
|
const tableIdx = this.multicastTable.length;
|
|
392
336
|
const multicastEntry = {
|
|
@@ -396,22 +340,20 @@ class EmberAdapter extends __1.Adapter {
|
|
|
396
340
|
};
|
|
397
341
|
// set immediately to avoid potential race
|
|
398
342
|
this.multicastTable.push(multicastEntry.multicastId);
|
|
399
|
-
|
|
400
|
-
this.
|
|
401
|
-
const status =
|
|
402
|
-
if (status !==
|
|
403
|
-
|
|
404
|
-
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]}.`);
|
|
405
348
|
}
|
|
406
349
|
logger_1.logger.debug(`Registered multicast table entry (${tableIdx}): ${JSON.stringify(multicastEntry)}.`, NS);
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
});
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
catch (error) {
|
|
353
|
+
// remove to allow retry on next occurrence
|
|
354
|
+
this.multicastTable.splice(tableIdx, 1);
|
|
355
|
+
throw error;
|
|
356
|
+
}
|
|
415
357
|
}
|
|
416
358
|
}
|
|
417
359
|
// shouldn't be any other status
|
|
@@ -419,26 +361,31 @@ class EmberAdapter extends __1.Adapter {
|
|
|
419
361
|
/**
|
|
420
362
|
* Emitted from @see Ezsp.ezspIncomingMessageHandler
|
|
421
363
|
*
|
|
422
|
-
* @param
|
|
364
|
+
* @param apsFrame The APS frame associated with the response.
|
|
423
365
|
* @param sender The sender of the response. Should match `payload.nodeId` in many responses.
|
|
424
|
-
* @param
|
|
366
|
+
* @param messageContents The content of the response.
|
|
425
367
|
*/
|
|
426
|
-
async onZDOResponse(
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
368
|
+
async onZDOResponse(apsFrame, sender, messageContents) {
|
|
369
|
+
try {
|
|
370
|
+
const payload = buffaloZdo_1.BuffaloZdo.readResponse(apsFrame.clusterId, messageContents);
|
|
371
|
+
logger_1.logger.debug(`<~~~ [ZDO ${Zdo.ClusterId[apsFrame.clusterId]} from=${sender} ${payload ? JSON.stringify(payload) : 'OK'}]`, NS);
|
|
372
|
+
this.oneWaitress.resolveZDO(sender, apsFrame, payload);
|
|
373
|
+
if (apsFrame.clusterId === Zdo.ClusterId.NETWORK_ADDRESS_RESPONSE) {
|
|
374
|
+
this.emit(events_1.Events.networkAddress, {
|
|
375
|
+
networkAddress: payload.nwkAddress,
|
|
376
|
+
ieeeAddr: payload.eui64,
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
else if (apsFrame.clusterId === Zdo.ClusterId.END_DEVICE_ANNOUNCE) {
|
|
380
|
+
this.emit(events_1.Events.deviceAnnounce, {
|
|
381
|
+
networkAddress: payload.nwkAddress,
|
|
382
|
+
ieeeAddr: payload.eui64,
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
catch (error) {
|
|
387
|
+
this.oneWaitress.resolveZDO(sender, apsFrame, error);
|
|
388
|
+
}
|
|
442
389
|
}
|
|
443
390
|
/**
|
|
444
391
|
* Emitted from @see Ezsp.ezspIncomingMessageHandler
|
|
@@ -458,7 +405,7 @@ class EmberAdapter extends __1.Adapter {
|
|
|
458
405
|
endpoint: apsFrame.sourceEndpoint,
|
|
459
406
|
linkquality: lastHopLqi,
|
|
460
407
|
groupID: apsFrame.groupId,
|
|
461
|
-
wasBroadcast:
|
|
408
|
+
wasBroadcast: type === enums_1.EmberIncomingMessageType.BROADCAST || type === enums_1.EmberIncomingMessageType.BROADCAST_LOOPBACK,
|
|
462
409
|
destinationEndpoint: apsFrame.destinationEndpoint,
|
|
463
410
|
};
|
|
464
411
|
this.oneWaitress.resolveZCL(payload);
|
|
@@ -543,7 +490,7 @@ class EmberAdapter extends __1.Adapter {
|
|
|
543
490
|
* @param parentOfNewNodeId
|
|
544
491
|
*/
|
|
545
492
|
async onTrustCenterJoin(newNodeId, newNodeEui64, status, policyDecision, parentOfNewNodeId) {
|
|
546
|
-
if (status ===
|
|
493
|
+
if (status === enums_1.EmberDeviceUpdate.DEVICE_LEFT) {
|
|
547
494
|
const payload = {
|
|
548
495
|
networkAddress: newNodeId,
|
|
549
496
|
ieeeAddr: newNodeEui64,
|
|
@@ -551,7 +498,7 @@ class EmberAdapter extends __1.Adapter {
|
|
|
551
498
|
this.emit(events_1.Events.deviceLeave, payload);
|
|
552
499
|
}
|
|
553
500
|
else {
|
|
554
|
-
if (policyDecision !==
|
|
501
|
+
if (policyDecision !== enums_1.EmberJoinDecision.DENY_JOIN) {
|
|
555
502
|
const payload = {
|
|
556
503
|
networkAddress: newNodeId,
|
|
557
504
|
ieeeAddr: newNodeEui64,
|
|
@@ -559,15 +506,11 @@ class EmberAdapter extends __1.Adapter {
|
|
|
559
506
|
// set workaround manuf code if necessary, or revert to default if previous joined device required workaround and new one does not
|
|
560
507
|
const joinManufCode = WORKAROUND_JOIN_MANUF_IEEE_PREFIX_TO_CODE[newNodeEui64.substring(0, 8)] ?? DEFAULT_MANUFACTURER_CODE;
|
|
561
508
|
if (this.manufacturerCode !== joinManufCode) {
|
|
562
|
-
await
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
this.emit(events_1.Events.deviceJoined, payload);
|
|
568
|
-
resolve();
|
|
569
|
-
return enums_3.EmberStatus.SUCCESS;
|
|
570
|
-
}, 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);
|
|
571
514
|
});
|
|
572
515
|
}
|
|
573
516
|
else {
|
|
@@ -580,22 +523,18 @@ class EmberAdapter extends __1.Adapter {
|
|
|
580
523
|
}
|
|
581
524
|
}
|
|
582
525
|
async watchdogCounters() {
|
|
583
|
-
await
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
logger_1.logger.info(`[ASH COUNTERS] ${ashCounters.join(',')}`, NS);
|
|
590
|
-
resolve();
|
|
591
|
-
return enums_3.EmberStatus.SUCCESS;
|
|
592
|
-
}, 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);
|
|
593
532
|
});
|
|
594
533
|
}
|
|
595
534
|
initVariables() {
|
|
596
535
|
this.ezsp.removeAllListeners(ezsp_1.EzspEvents.NCP_NEEDS_RESET_AND_INIT);
|
|
597
536
|
clearInterval(this.watchdogCountersHandle);
|
|
598
|
-
this.
|
|
537
|
+
this.queue.clear();
|
|
599
538
|
this.zdoRequestSequence = 0; // start at 1
|
|
600
539
|
this.zdoRequestRadius = 255;
|
|
601
540
|
this.interpanLock = false;
|
|
@@ -609,96 +548,49 @@ class EmberAdapter extends __1.Adapter {
|
|
|
609
548
|
* This is called by start and on internal reset.
|
|
610
549
|
*/
|
|
611
550
|
async initEzsp() {
|
|
612
|
-
let result =
|
|
551
|
+
let result = 'resumed';
|
|
613
552
|
// NOTE: something deep in this call can throw too
|
|
614
|
-
const startResult =
|
|
615
|
-
if (startResult !==
|
|
616
|
-
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]}.`);
|
|
617
556
|
}
|
|
618
557
|
// call before any other command, else fails
|
|
619
558
|
await this.emberVersion();
|
|
620
|
-
|
|
621
|
-
await this.initNCPAddressTable();
|
|
622
|
-
await this.initNCPConfiguration();
|
|
623
|
-
// WARNING: From here on EZSP commands that affect memory allocation on the NCP should no longer be called (like resizing tables)
|
|
624
|
-
await this.registerFixedEndpoints();
|
|
625
|
-
this.clearNetworkCache();
|
|
626
|
-
result = (await this.initTrustCenter());
|
|
627
|
-
// after network UP, as per SDK, ensures clean slate
|
|
628
|
-
await this.initNCPConcentrator();
|
|
629
|
-
// await (this.emberStartEnergyScan());// TODO: via config of some kind, better off waiting for UI supports though
|
|
630
|
-
// populate network cache info
|
|
631
|
-
const [status, , parameters] = (await this.ezsp.ezspGetNetworkParameters());
|
|
632
|
-
if (status !== enums_3.EmberStatus.SUCCESS) {
|
|
633
|
-
throw new Error(`Failed to get network parameters with status=${enums_3.EmberStatus[status]}.`);
|
|
634
|
-
}
|
|
635
|
-
this.networkCache.parameters = parameters;
|
|
636
|
-
this.networkCache.status = (await this.ezsp.ezspNetworkState());
|
|
637
|
-
this.networkCache.eui64 = (await this.ezsp.ezspGetEui64());
|
|
638
|
-
logger_1.logger.debug(`[INIT] Network Ready! ${JSON.stringify(this.networkCache)}`, NS);
|
|
639
|
-
this.watchdogCountersHandle = setInterval(this.watchdogCounters.bind(this), WATCHDOG_COUNTERS_FEED_INTERVAL);
|
|
640
|
-
this.requestQueue.startDispatching();
|
|
641
|
-
return result;
|
|
642
|
-
}
|
|
643
|
-
/**
|
|
644
|
-
* NCP Config init. Should always be called first in the init stack (after version cmd).
|
|
645
|
-
* @returns
|
|
646
|
-
*/
|
|
647
|
-
async initNCPPreConfiguration() {
|
|
648
|
-
// this can only decrease, not increase, NCP-side value
|
|
649
|
-
await this.emberSetEzspConfigValue(enums_2.EzspConfigId.ADDRESS_TABLE_SIZE, this.stackConfig.ADDRESS_TABLE_SIZE);
|
|
650
|
-
await this.emberSetEzspConfigValue(enums_2.EzspConfigId.TRUST_CENTER_ADDRESS_CACHE_SIZE, this.stackConfig.TRUST_CENTER_ADDRESS_CACHE_SIZE);
|
|
651
|
-
// BUG 14222: If stack profile is 2 (ZigBee Pro), we need to enforce
|
|
652
|
-
// the standard stack configuration values for that feature set.
|
|
653
|
-
/** MAC indirect timeout should be 7.68 secs */
|
|
559
|
+
/** MAC indirect timeout should be 7.68 secs (STACK_PROFILE_ZIGBEE_PRO) */
|
|
654
560
|
await this.emberSetEzspConfigValue(enums_2.EzspConfigId.INDIRECT_TRANSMISSION_TIMEOUT, 7680);
|
|
655
|
-
/** Max hops should be 2 * nwkMaxDepth, where nwkMaxDepth is 15 */
|
|
561
|
+
/** Max hops should be 2 * nwkMaxDepth, where nwkMaxDepth is 15 (STACK_PROFILE_ZIGBEE_PRO) */
|
|
656
562
|
await this.emberSetEzspConfigValue(enums_2.EzspConfigId.MAX_HOPS, 30);
|
|
657
|
-
await this.emberSetEzspConfigValue(enums_2.EzspConfigId.TX_POWER_MODE, enums_3.EmberTXPowerMode.USE_TOKEN);
|
|
658
563
|
await this.emberSetEzspConfigValue(enums_2.EzspConfigId.SUPPORTED_NETWORKS, 1);
|
|
659
|
-
await this.emberSetEzspValue(enums_2.EzspValueId.END_DEVICE_KEEP_ALIVE_SUPPORT_MODE, 1, [enums_3.EmberKeepAliveMode.KEEP_ALIVE_SUPPORT_ALL]);
|
|
660
564
|
// allow other devices to modify the binding table
|
|
661
565
|
await this.emberSetEzspPolicy(enums_2.EzspPolicyId.BINDING_MODIFICATION_POLICY, enums_2.EzspDecisionId.CHECK_BINDING_MODIFICATIONS_ARE_VALID_ENDPOINT_CLUSTERS);
|
|
662
|
-
// return message tag
|
|
663
|
-
await this.emberSetEzspPolicy(enums_2.EzspPolicyId.MESSAGE_CONTENTS_IN_CALLBACK_POLICY, enums_2.EzspDecisionId.
|
|
664
|
-
await this.emberSetEzspValue(enums_2.EzspValueId.MAXIMUM_INCOMING_TRANSFER_SIZE, 2, (0, math_1.lowHighBytes)(consts_2.MAXIMUM_APS_PAYLOAD_LENGTH));
|
|
665
|
-
await this.emberSetEzspValue(enums_2.EzspValueId.MAXIMUM_OUTGOING_TRANSFER_SIZE, 2, (0, math_1.lowHighBytes)(consts_2.MAXIMUM_APS_PAYLOAD_LENGTH));
|
|
566
|
+
// return message tag only in ezspMessageSentHandler()
|
|
567
|
+
await this.emberSetEzspPolicy(enums_2.EzspPolicyId.MESSAGE_CONTENTS_IN_CALLBACK_POLICY, enums_2.EzspDecisionId.MESSAGE_TAG_ONLY_IN_CALLBACK);
|
|
666
568
|
await this.emberSetEzspValue(enums_2.EzspValueId.TRANSIENT_DEVICE_TIMEOUT, 2, (0, math_1.lowHighBytes)(this.stackConfig.TRANSIENT_DEVICE_TIMEOUT));
|
|
667
569
|
await this.ezsp.ezspSetManufacturerCode(this.manufacturerCode);
|
|
668
570
|
// network security init
|
|
669
|
-
await this.emberSetEzspConfigValue(enums_2.EzspConfigId.STACK_PROFILE,
|
|
670
|
-
await this.emberSetEzspConfigValue(enums_2.EzspConfigId.SECURITY_LEVEL,
|
|
671
|
-
|
|
672
|
-
/**
|
|
673
|
-
* NCP Address table init.
|
|
674
|
-
* @returns
|
|
675
|
-
*/
|
|
676
|
-
async initNCPAddressTable() {
|
|
677
|
-
const desiredTableSize = this.stackConfig.ADDRESS_TABLE_SIZE;
|
|
678
|
-
// If the host and the ncp disagree on the address table size, explode.
|
|
679
|
-
const [status, addressTableSize] = (await this.ezsp.ezspGetConfigurationValue(enums_2.EzspConfigId.ADDRESS_TABLE_SIZE));
|
|
680
|
-
// After the change of ncp memory model in UC, we can not increase the default NCP table sizes anymore.
|
|
681
|
-
// Therefore, checking for desiredTableSize == (ncp)addressTableSize might not be always true anymore
|
|
682
|
-
// assert(desiredTableSize <= addressTableSize);
|
|
683
|
-
if ((status !== enums_3.EzspStatus.SUCCESS) || (addressTableSize > desiredTableSize)) {
|
|
684
|
-
throw new Error(`[INIT] NCP (${addressTableSize}) disagrees with Host (min ${desiredTableSize}) on table size. status=${enums_3.EzspStatus[status]}`);
|
|
685
|
-
}
|
|
686
|
-
}
|
|
687
|
-
/**
|
|
688
|
-
* NCP configuration init
|
|
689
|
-
*/
|
|
690
|
-
async initNCPConfiguration() {
|
|
691
|
-
await this.emberSetEzspConfigValue(enums_2.EzspConfigId.BINDING_TABLE_SIZE, this.stackConfig.BINDING_TABLE_SIZE);
|
|
692
|
-
await this.emberSetEzspConfigValue(enums_2.EzspConfigId.KEY_TABLE_SIZE, this.stackConfig.KEY_TABLE_SIZE);
|
|
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);
|
|
573
|
+
// common configs
|
|
693
574
|
await this.emberSetEzspConfigValue(enums_2.EzspConfigId.MAX_END_DEVICE_CHILDREN, this.stackConfig.MAX_END_DEVICE_CHILDREN);
|
|
694
|
-
await this.emberSetEzspConfigValue(enums_2.EzspConfigId.APS_UNICAST_MESSAGE_COUNT, this.stackConfig.APS_UNICAST_MESSAGE_COUNT);
|
|
695
|
-
await this.emberSetEzspConfigValue(enums_2.EzspConfigId.BROADCAST_TABLE_SIZE, this.stackConfig.BROADCAST_TABLE_SIZE);
|
|
696
|
-
await this.emberSetEzspConfigValue(enums_2.EzspConfigId.NEIGHBOR_TABLE_SIZE, this.stackConfig.NEIGHBOR_TABLE_SIZE);
|
|
697
575
|
await this.emberSetEzspConfigValue(enums_2.EzspConfigId.END_DEVICE_POLL_TIMEOUT, this.stackConfig.END_DEVICE_POLL_TIMEOUT);
|
|
698
576
|
await this.emberSetEzspConfigValue(enums_2.EzspConfigId.TRANSIENT_KEY_TIMEOUT_S, this.stackConfig.TRANSIENT_KEY_TIMEOUT_S);
|
|
699
|
-
|
|
700
|
-
await this.
|
|
701
|
-
|
|
577
|
+
// WARNING: From here on EZSP commands that affect memory allocation on the NCP should no longer be called (like resizing tables)
|
|
578
|
+
await this.registerFixedEndpoints();
|
|
579
|
+
this.clearNetworkCache();
|
|
580
|
+
result = await this.initTrustCenter();
|
|
581
|
+
// after network UP, as per SDK, ensures clean slate
|
|
582
|
+
await this.initNCPConcentrator();
|
|
583
|
+
// populate network cache info
|
|
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]}.`);
|
|
587
|
+
}
|
|
588
|
+
this.networkCache.parameters = parameters;
|
|
589
|
+
this.networkCache.status = await this.ezsp.ezspNetworkState();
|
|
590
|
+
this.networkCache.eui64 = await this.ezsp.ezspGetEui64();
|
|
591
|
+
logger_1.logger.debug(`[INIT] Network Ready! ${JSON.stringify(this.networkCache)}`, NS);
|
|
592
|
+
this.watchdogCountersHandle = setInterval(this.watchdogCounters.bind(this), WATCHDOG_COUNTERS_FEED_INTERVAL);
|
|
593
|
+
return result;
|
|
702
594
|
}
|
|
703
595
|
/**
|
|
704
596
|
* NCP concentrator init. Also enables source route discovery mode with RESCHEDULE.
|
|
@@ -715,11 +607,11 @@ class EmberAdapter extends __1.Adapter {
|
|
|
715
607
|
* (through a target node that is neither the trust center nor one of its neighboring routers.)
|
|
716
608
|
*/
|
|
717
609
|
async initNCPConcentrator() {
|
|
718
|
-
const status =
|
|
719
|
-
if (status !==
|
|
720
|
-
throw new Error(`[CONCENTRATOR] Failed to set concentrator with status=${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]}.`);
|
|
721
613
|
}
|
|
722
|
-
const remainTilMTORR =
|
|
614
|
+
const remainTilMTORR = await this.ezsp.ezspSetSourceRouteDiscoveryMode(enums_1.EmberSourceRouteDiscoveryMode.RESCHEDULE);
|
|
723
615
|
logger_1.logger.info(`[CONCENTRATOR] Started source route discovery. ${remainTilMTORR}ms until next broadcast.`, NS);
|
|
724
616
|
}
|
|
725
617
|
/**
|
|
@@ -731,18 +623,18 @@ class EmberAdapter extends __1.Adapter {
|
|
|
731
623
|
logger_1.logger.debug(`Multi-network not currently supported. Skipping endpoint ${JSON.stringify(ep)}.`, NS);
|
|
732
624
|
continue;
|
|
733
625
|
}
|
|
734
|
-
const [epStatus
|
|
626
|
+
const [epStatus] = await this.ezsp.ezspGetEndpointFlags(ep.endpoint);
|
|
735
627
|
// endpoint not already registered
|
|
736
|
-
if (epStatus !==
|
|
628
|
+
if (epStatus !== enums_1.SLStatus.OK) {
|
|
737
629
|
// check to see if ezspAddEndpoint needs to be called
|
|
738
630
|
// if ezspInit is called without NCP reset, ezspAddEndpoint is not necessary and will return an error
|
|
739
|
-
const status =
|
|
740
|
-
ep.outClusterList.slice())
|
|
741
|
-
if (status ===
|
|
742
|
-
logger_1.logger.debug(`Registered endpoint
|
|
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) {
|
|
634
|
+
logger_1.logger.debug(`Registered endpoint '${ep.endpoint}'.`, NS);
|
|
743
635
|
}
|
|
744
636
|
else {
|
|
745
|
-
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]}.`);
|
|
746
638
|
}
|
|
747
639
|
}
|
|
748
640
|
else {
|
|
@@ -754,9 +646,9 @@ class EmberAdapter extends __1.Adapter {
|
|
|
754
646
|
endpoint: ep.endpoint,
|
|
755
647
|
networkIndex: ep.networkIndex,
|
|
756
648
|
};
|
|
757
|
-
const status =
|
|
758
|
-
if (status !==
|
|
759
|
-
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]}.`);
|
|
760
652
|
}
|
|
761
653
|
logger_1.logger.debug(`Registered multicast table entry (${this.multicastTable.length}): ${JSON.stringify(multicastEntry)}.`, NS);
|
|
762
654
|
this.multicastTable.push(multicastEntry.multicastId);
|
|
@@ -770,49 +662,49 @@ class EmberAdapter extends __1.Adapter {
|
|
|
770
662
|
async initTrustCenter() {
|
|
771
663
|
// init TC policies
|
|
772
664
|
{
|
|
773
|
-
let status =
|
|
774
|
-
if (status !==
|
|
775
|
-
throw new Error(`[INIT TC] Failed to set EzspPolicyId TC_KEY_REQUEST_POLICY to ALLOW_TC_KEY_REQUESTS_AND_SEND_CURRENT_KEY `
|
|
776
|
-
|
|
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]}.`);
|
|
777
669
|
}
|
|
778
|
-
const
|
|
779
|
-
status =
|
|
780
|
-
if (status !==
|
|
781
|
-
throw new Error(`[INIT TC] Failed to set EzspPolicyId APP_KEY_REQUEST_POLICY to ${enums_2.EzspDecisionId[
|
|
782
|
-
|
|
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]}.`);
|
|
783
675
|
}
|
|
784
|
-
status =
|
|
785
|
-
if (status !==
|
|
786
|
-
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]}.`);
|
|
787
679
|
}
|
|
788
680
|
}
|
|
789
681
|
const configNetworkKey = Buffer.from(this.networkOptions.networkKey);
|
|
790
682
|
const networkInitStruct = {
|
|
791
|
-
bitmask:
|
|
683
|
+
bitmask: enums_1.EmberNetworkInitBitmask.PARENT_INFO_IN_TOKEN | enums_1.EmberNetworkInitBitmask.END_DEVICE_REJOIN_ON_REBOOT,
|
|
792
684
|
};
|
|
793
|
-
const initStatus =
|
|
794
|
-
logger_1.logger.debug(`[INIT TC] Network init status=${
|
|
795
|
-
if (
|
|
796
|
-
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]}.`);
|
|
797
689
|
}
|
|
798
690
|
let action = NetworkInitAction.DONE;
|
|
799
|
-
if (initStatus ===
|
|
691
|
+
if (initStatus === enums_1.SLStatus.OK) {
|
|
800
692
|
// network
|
|
801
693
|
await this.oneWaitress.startWaitingForEvent({ eventName: oneWaitress_1.OneWaitressEvents.STACK_STATUS_NETWORK_UP }, DEFAULT_NETWORK_REQUEST_TIMEOUT, '[INIT TC] Network init');
|
|
802
|
-
const [npStatus, nodeType, netParams] =
|
|
803
|
-
logger_1.logger.debug(`[INIT TC] Current network
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
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)) {
|
|
807
700
|
// config matches adapter so far, no error, we can check the network key
|
|
808
701
|
const context = (0, initters_1.initSecurityManagerContext)();
|
|
809
|
-
context.coreKeyType =
|
|
702
|
+
context.coreKeyType = enums_1.SecManKeyType.NETWORK;
|
|
810
703
|
context.keyIndex = 0;
|
|
811
|
-
const [
|
|
812
|
-
if (nkStatus !==
|
|
813
|
-
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]}.`);
|
|
814
707
|
}
|
|
815
|
-
logger_1.logger.debug(`[INIT TC] Current NCP network: networkKey=${networkKey.contents.toString('hex')}`, NS);
|
|
816
708
|
// config doesn't match adapter anymore
|
|
817
709
|
if (!networkKey.contents.equals(configNetworkKey)) {
|
|
818
710
|
action = NetworkInitAction.LEAVE;
|
|
@@ -823,10 +715,10 @@ class EmberAdapter extends __1.Adapter {
|
|
|
823
715
|
action = NetworkInitAction.LEAVE;
|
|
824
716
|
}
|
|
825
717
|
if (action === NetworkInitAction.LEAVE) {
|
|
826
|
-
logger_1.logger.info(`[INIT TC]
|
|
827
|
-
const leaveStatus =
|
|
828
|
-
if (leaveStatus !==
|
|
829
|
-
throw new Error(`[INIT TC] Failed leave network request with status=${
|
|
718
|
+
logger_1.logger.info(`[INIT TC] Adapter network does not match config. Leaving network...`, NS);
|
|
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]}.`);
|
|
830
722
|
}
|
|
831
723
|
await this.oneWaitress.startWaitingForEvent({ eventName: oneWaitress_1.OneWaitressEvents.STACK_STATUS_NETWORK_DOWN }, DEFAULT_NETWORK_REQUEST_TIMEOUT, '[INIT TC] Leave network');
|
|
832
724
|
await (0, utils_1.Wait)(200); // settle down
|
|
@@ -834,13 +726,13 @@ class EmberAdapter extends __1.Adapter {
|
|
|
834
726
|
}
|
|
835
727
|
}
|
|
836
728
|
const backup = this.getStoredBackup();
|
|
837
|
-
if (
|
|
729
|
+
if (initStatus === enums_1.SLStatus.NOT_JOINED || action === NetworkInitAction.LEFT) {
|
|
838
730
|
// no network
|
|
839
731
|
if (backup != null) {
|
|
840
|
-
if (
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
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)) {
|
|
844
736
|
// config matches backup
|
|
845
737
|
action = NetworkInitAction.FORM_BACKUP;
|
|
846
738
|
}
|
|
@@ -863,29 +755,27 @@ class EmberAdapter extends __1.Adapter {
|
|
|
863
755
|
logger_1.logger.info(`[INIT TC] Forming from backup.`, NS);
|
|
864
756
|
const keyList = backup.devices.map((device) => {
|
|
865
757
|
const octets = Array.from(device.ieeeAddress.reverse());
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
deviceEui64,
|
|
758
|
+
return {
|
|
759
|
+
deviceEui64: `0x${octets.map((octet) => octet.toString(16).padStart(2, '0')).join('')}`,
|
|
869
760
|
key: { contents: device.linkKey.key },
|
|
870
761
|
outgoingFrameCounter: device.linkKey.txCounter,
|
|
871
762
|
incomingFrameCounter: device.linkKey.rxCounter,
|
|
872
763
|
};
|
|
873
|
-
return key;
|
|
874
764
|
});
|
|
875
765
|
// before forming
|
|
876
766
|
await this.importLinkKeys(keyList);
|
|
877
|
-
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);
|
|
878
768
|
result = 'restored';
|
|
879
769
|
break;
|
|
880
770
|
}
|
|
881
771
|
case NetworkInitAction.FORM_CONFIG: {
|
|
882
772
|
logger_1.logger.info(`[INIT TC] Forming from config.`, NS);
|
|
883
|
-
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));
|
|
884
774
|
result = 'reset';
|
|
885
775
|
break;
|
|
886
776
|
}
|
|
887
777
|
case NetworkInitAction.DONE: {
|
|
888
|
-
logger_1.logger.info(`[INIT TC]
|
|
778
|
+
logger_1.logger.info(`[INIT TC] Adapter network matches config.`, NS);
|
|
889
779
|
break;
|
|
890
780
|
}
|
|
891
781
|
default: {
|
|
@@ -893,7 +783,7 @@ class EmberAdapter extends __1.Adapter {
|
|
|
893
783
|
}
|
|
894
784
|
}
|
|
895
785
|
// can't let frame counter wrap to zero (uint32_t), will force a broadcast after init if getting too close
|
|
896
|
-
if (backup != null &&
|
|
786
|
+
if (backup != null && backup.networkKeyInfo.frameCounter > 0xfeeeeeee) {
|
|
897
787
|
// XXX: while this remains a pretty low occurrence in most (small) networks,
|
|
898
788
|
// currently Z2M won't support the key update because of one-way config...
|
|
899
789
|
// need to investigate handling this properly
|
|
@@ -902,9 +792,9 @@ class EmberAdapter extends __1.Adapter {
|
|
|
902
792
|
// // XXX: no idea here on the proper timer value, but this will block the network for several seconds on exec
|
|
903
793
|
// // (probably have to take the behavior of sleepy-end devices into account to improve chances of reaching everyone right away?)
|
|
904
794
|
// setTimeout(async () => {
|
|
905
|
-
// this.requestQueue.enqueue(async (): Promise<
|
|
795
|
+
// this.requestQueue.enqueue(async (): Promise<SLStatus> => {
|
|
906
796
|
// await this.broadcastNetworkKeyUpdate();
|
|
907
|
-
// return
|
|
797
|
+
// return SLStatus.OK;
|
|
908
798
|
// }, logger.error, true);// no reject just log error if any, will retry next start, & prioritize so we know it'll run when expected
|
|
909
799
|
// }, 300000);
|
|
910
800
|
logger_1.logger.warning(`[INIT TC] Network key frame counter is reaching its limit. A new network key will have to be instaured soon.`, NS);
|
|
@@ -916,30 +806,32 @@ class EmberAdapter extends __1.Adapter {
|
|
|
916
806
|
*/
|
|
917
807
|
async formNetwork(fromBackup, networkKey, networkKeySequenceNumber, panId, extendedPanId, radioChannel, tcLinkKey) {
|
|
918
808
|
const state = {
|
|
919
|
-
bitmask:
|
|
920
|
-
|
|
921
|
-
|
|
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,
|
|
922
814
|
preconfiguredKey: { contents: tcLinkKey },
|
|
923
815
|
networkKey: { contents: networkKey },
|
|
924
816
|
networkKeySequenceNumber: networkKeySequenceNumber,
|
|
925
817
|
preconfiguredTrustCenterEui64: ZSpec.BLANK_EUI64,
|
|
926
818
|
};
|
|
927
819
|
if (fromBackup) {
|
|
928
|
-
state.bitmask |=
|
|
820
|
+
state.bitmask |= enums_1.EmberInitialSecurityBitmask.NO_FRAME_COUNTER_RESET;
|
|
929
821
|
}
|
|
930
|
-
let
|
|
931
|
-
if (
|
|
932
|
-
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]}.`);
|
|
933
825
|
}
|
|
934
|
-
const extended =
|
|
935
|
-
|
|
936
|
-
if (
|
|
937
|
-
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]}.`);
|
|
938
830
|
}
|
|
939
|
-
if (!fromBackup
|
|
940
|
-
|
|
941
|
-
if (
|
|
942
|
-
|
|
831
|
+
if (!fromBackup) {
|
|
832
|
+
status = await this.ezsp.ezspClearKeyTable();
|
|
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);
|
|
943
835
|
}
|
|
944
836
|
}
|
|
945
837
|
const netParams = {
|
|
@@ -947,19 +839,19 @@ class EmberAdapter extends __1.Adapter {
|
|
|
947
839
|
extendedPanId,
|
|
948
840
|
radioTxPower: 5,
|
|
949
841
|
radioChannel,
|
|
950
|
-
joinMethod:
|
|
842
|
+
joinMethod: enums_1.EmberJoinMethod.MAC_ASSOCIATION,
|
|
951
843
|
nwkManagerId: ZSpec.COORDINATOR_ADDRESS,
|
|
952
844
|
nwkUpdateId: 0,
|
|
953
|
-
channels:
|
|
845
|
+
channels: consts_1.EMBER_ALL_802_15_4_CHANNELS_MASK,
|
|
954
846
|
};
|
|
955
847
|
logger_1.logger.info(`[INIT FORM] Forming new network with: ${JSON.stringify(netParams)}`, NS);
|
|
956
|
-
|
|
957
|
-
if (
|
|
958
|
-
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]}.`);
|
|
959
851
|
}
|
|
960
852
|
await this.oneWaitress.startWaitingForEvent({ eventName: oneWaitress_1.OneWaitressEvents.STACK_STATUS_NETWORK_UP }, DEFAULT_NETWORK_REQUEST_TIMEOUT, '[INIT FORM] Form network');
|
|
961
|
-
|
|
962
|
-
logger_1.logger.debug(`[INIT FORM] Start writing stack tokens status=${
|
|
853
|
+
status = await this.ezsp.ezspStartWritingStackTokens();
|
|
854
|
+
logger_1.logger.debug(`[INIT FORM] Start writing stack tokens status=${enums_1.SLStatus[status]}.`, NS);
|
|
963
855
|
logger_1.logger.info(`[INIT FORM] New network formed!`, NS);
|
|
964
856
|
}
|
|
965
857
|
/**
|
|
@@ -971,12 +863,12 @@ class EmberAdapter extends __1.Adapter {
|
|
|
971
863
|
}
|
|
972
864
|
let data;
|
|
973
865
|
try {
|
|
974
|
-
data = JSON.parse((
|
|
866
|
+
data = JSON.parse((0, fs_1.readFileSync)(this.backupPath).toString());
|
|
975
867
|
}
|
|
976
868
|
catch (error) {
|
|
977
869
|
throw new Error(`[BACKUP] Coordinator backup is corrupted.`);
|
|
978
870
|
}
|
|
979
|
-
if (data.metadata?.format ===
|
|
871
|
+
if (data.metadata?.format === 'zigpy/open-coordinator-backup' && data.metadata?.version) {
|
|
980
872
|
if (data.metadata?.version !== 1) {
|
|
981
873
|
throw new Error(`[BACKUP] Unsupported open coordinator backup version (version=${data.metadata?.version}).`);
|
|
982
874
|
}
|
|
@@ -1000,27 +892,27 @@ class EmberAdapter extends __1.Adapter {
|
|
|
1000
892
|
* @return List of keys data with AES hashed keys
|
|
1001
893
|
*/
|
|
1002
894
|
async exportLinkKeys() {
|
|
1003
|
-
const [confStatus, keyTableSize] =
|
|
1004
|
-
if (confStatus !==
|
|
1005
|
-
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]}.`);
|
|
1006
898
|
}
|
|
1007
|
-
let
|
|
899
|
+
let context;
|
|
1008
900
|
let plaintextKey;
|
|
1009
901
|
let apsKeyMeta;
|
|
1010
902
|
let status;
|
|
1011
903
|
const keyList = [];
|
|
1012
904
|
for (let i = 0; i < keyTableSize; i++) {
|
|
1013
|
-
[
|
|
1014
|
-
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);
|
|
1015
907
|
// only include key if we could retrieve one at index and hash it properly
|
|
1016
|
-
if (status ===
|
|
908
|
+
if (status === enums_1.SLStatus.OK) {
|
|
1017
909
|
// Rather than give the real link key, the backup contains a hashed version of the key.
|
|
1018
910
|
// This is done to prevent a compromise of the backup data from compromising the current link keys.
|
|
1019
911
|
// This is per the Smart Energy spec.
|
|
1020
|
-
const [hashStatus, hashedKey] =
|
|
1021
|
-
if (hashStatus ===
|
|
912
|
+
const [hashStatus, hashedKey] = await this.emberAesHashSimple(plaintextKey.contents);
|
|
913
|
+
if (hashStatus === enums_1.SLStatus.OK) {
|
|
1022
914
|
keyList.push({
|
|
1023
|
-
deviceEui64,
|
|
915
|
+
deviceEui64: context.eui64,
|
|
1024
916
|
key: { contents: hashedKey },
|
|
1025
917
|
outgoingFrameCounter: apsKeyMeta.outgoingFrameCounter,
|
|
1026
918
|
incomingFrameCounter: apsKeyMeta.incomingFrameCounter,
|
|
@@ -1028,7 +920,7 @@ class EmberAdapter extends __1.Adapter {
|
|
|
1028
920
|
}
|
|
1029
921
|
else {
|
|
1030
922
|
// this should never happen?
|
|
1031
|
-
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);
|
|
1032
924
|
}
|
|
1033
925
|
}
|
|
1034
926
|
}
|
|
@@ -1044,30 +936,27 @@ class EmberAdapter extends __1.Adapter {
|
|
|
1044
936
|
if (!backupData?.length) {
|
|
1045
937
|
return;
|
|
1046
938
|
}
|
|
1047
|
-
const [confStatus, keyTableSize] =
|
|
1048
|
-
if (confStatus !==
|
|
1049
|
-
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]}.`);
|
|
1050
942
|
}
|
|
1051
943
|
if (backupData.length > keyTableSize) {
|
|
1052
944
|
throw new Error(`[BACKUP] Current key table of ${keyTableSize} is too small to import backup of ${backupData.length}!`);
|
|
1053
945
|
}
|
|
1054
|
-
const networkStatus =
|
|
1055
|
-
if (networkStatus !==
|
|
1056
|
-
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]}.`);
|
|
1057
949
|
}
|
|
1058
950
|
let status;
|
|
1059
951
|
for (let i = 0; i < keyTableSize; i++) {
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
if (status !== enums_3.EmberStatus.SUCCESS) {
|
|
1069
|
-
throw new Error(`[BACKUP] Failed to ${((i >= backupData.length) ? "erase" : "set")} key table entry at index ${i} `
|
|
1070
|
-
+ `with status=${enums_3.EmberStatus[status]}`);
|
|
952
|
+
// erase any key index not present in backup but available on the NCP
|
|
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]}`);
|
|
1071
960
|
}
|
|
1072
961
|
}
|
|
1073
962
|
logger_1.logger.info(`[BACKUP] Imported ${backupData.length} keys.`, NS);
|
|
@@ -1079,27 +968,21 @@ class EmberAdapter extends __1.Adapter {
|
|
|
1079
968
|
* On the other hand, the more often this runs, the more secure the network is...
|
|
1080
969
|
*/
|
|
1081
970
|
async broadcastNetworkKeyUpdate() {
|
|
1082
|
-
return
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
logger_1.logger.error(`[TRUST CENTER] Failed to broadcast network key switch with status=${enums_3.EmberStatus[status]}.`, NS);
|
|
1098
|
-
return status;
|
|
1099
|
-
}
|
|
1100
|
-
resolve();
|
|
1101
|
-
return status;
|
|
1102
|
-
}, 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
|
+
}
|
|
1103
986
|
});
|
|
1104
987
|
}
|
|
1105
988
|
/**
|
|
@@ -1107,16 +990,23 @@ class EmberAdapter extends __1.Adapter {
|
|
|
1107
990
|
* @param status
|
|
1108
991
|
*/
|
|
1109
992
|
async onNcpNeedsResetAndInit(status) {
|
|
1110
|
-
logger_1.logger.error(`!!!
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
await (0, utils_1.Wait)(500); // just because
|
|
1114
|
-
await this.start();
|
|
1115
|
-
}
|
|
1116
|
-
catch (err) {
|
|
1117
|
-
logger_1.logger.error(`Failed to reset and init NCP. ${err}`, NS);
|
|
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);
|
|
1118
996
|
this.emit(events_1.Events.disconnected);
|
|
1119
997
|
}
|
|
998
|
+
else {
|
|
999
|
+
logger_1.logger.info(`Attempting adapter reset...`, NS);
|
|
1000
|
+
try {
|
|
1001
|
+
await this.stop();
|
|
1002
|
+
await (0, utils_1.Wait)(500); // just because
|
|
1003
|
+
await this.start();
|
|
1004
|
+
}
|
|
1005
|
+
catch (err) {
|
|
1006
|
+
logger_1.logger.error(`Failed to reset and init adapter. ${err}`, NS);
|
|
1007
|
+
this.emit(events_1.Events.disconnected);
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1120
1010
|
}
|
|
1121
1011
|
//---- START Events
|
|
1122
1012
|
//---- END Events
|
|
@@ -1133,8 +1023,8 @@ class EmberAdapter extends __1.Adapter {
|
|
|
1133
1023
|
* Check against UNKNOWN_NETWORK_STATE for validity.
|
|
1134
1024
|
*/
|
|
1135
1025
|
async emberNetworkState() {
|
|
1136
|
-
if (this.networkCache.status ===
|
|
1137
|
-
const networkStatus =
|
|
1026
|
+
if (this.networkCache.status === consts_1.UNKNOWN_NETWORK_STATE) {
|
|
1027
|
+
const networkStatus = await this.ezsp.ezspNetworkState();
|
|
1138
1028
|
this.networkCache.status = networkStatus;
|
|
1139
1029
|
}
|
|
1140
1030
|
return this.networkCache.status;
|
|
@@ -1146,7 +1036,7 @@ class EmberAdapter extends __1.Adapter {
|
|
|
1146
1036
|
*/
|
|
1147
1037
|
async emberGetEui64() {
|
|
1148
1038
|
if (this.networkCache.eui64 === ZSpec.BLANK_EUI64) {
|
|
1149
|
-
this.networkCache.eui64 =
|
|
1039
|
+
this.networkCache.eui64 = await this.ezsp.ezspGetEui64();
|
|
1150
1040
|
}
|
|
1151
1041
|
return this.networkCache.eui64;
|
|
1152
1042
|
}
|
|
@@ -1157,12 +1047,12 @@ class EmberAdapter extends __1.Adapter {
|
|
|
1157
1047
|
*/
|
|
1158
1048
|
async emberGetPanId() {
|
|
1159
1049
|
if (this.networkCache.parameters.panId === ZSpec.INVALID_PAN_ID) {
|
|
1160
|
-
const [status, , parameters] =
|
|
1161
|
-
if (status ===
|
|
1050
|
+
const [status, , parameters] = await this.ezsp.ezspGetNetworkParameters();
|
|
1051
|
+
if (status === enums_1.SLStatus.OK) {
|
|
1162
1052
|
this.networkCache.parameters = parameters;
|
|
1163
1053
|
}
|
|
1164
1054
|
else {
|
|
1165
|
-
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);
|
|
1166
1056
|
}
|
|
1167
1057
|
}
|
|
1168
1058
|
return this.networkCache.parameters.panId;
|
|
@@ -1174,12 +1064,12 @@ class EmberAdapter extends __1.Adapter {
|
|
|
1174
1064
|
*/
|
|
1175
1065
|
async emberGetExtendedPanId() {
|
|
1176
1066
|
if ((0, es6_1.default)(this.networkCache.parameters.extendedPanId, ZSpec.BLANK_EXTENDED_PAN_ID)) {
|
|
1177
|
-
const [status, , parameters] =
|
|
1178
|
-
if (status ===
|
|
1067
|
+
const [status, , parameters] = await this.ezsp.ezspGetNetworkParameters();
|
|
1068
|
+
if (status === enums_1.SLStatus.OK) {
|
|
1179
1069
|
this.networkCache.parameters = parameters;
|
|
1180
1070
|
}
|
|
1181
1071
|
else {
|
|
1182
|
-
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);
|
|
1183
1073
|
}
|
|
1184
1074
|
}
|
|
1185
1075
|
return this.networkCache.parameters.extendedPanId;
|
|
@@ -1190,30 +1080,25 @@ class EmberAdapter extends __1.Adapter {
|
|
|
1190
1080
|
* Check against INVALID_RADIO_CHANNEL for validity.
|
|
1191
1081
|
*/
|
|
1192
1082
|
async emberGetRadioChannel() {
|
|
1193
|
-
if (this.networkCache.parameters.radioChannel ===
|
|
1194
|
-
const [status, , parameters] =
|
|
1195
|
-
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) {
|
|
1196
1086
|
this.networkCache.parameters = parameters;
|
|
1197
1087
|
}
|
|
1198
1088
|
else {
|
|
1199
|
-
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);
|
|
1200
1090
|
}
|
|
1201
1091
|
}
|
|
1202
1092
|
return this.networkCache.parameters.radioChannel;
|
|
1203
1093
|
}
|
|
1204
1094
|
// queued
|
|
1205
1095
|
async emberStartEnergyScan() {
|
|
1206
|
-
return
|
|
1207
|
-
this.
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
}
|
|
1213
|
-
// TODO: result in logs only atm, since UI doesn't support it
|
|
1214
|
-
resolve();
|
|
1215
|
-
return enums_3.EmberStatus.SUCCESS;
|
|
1216
|
-
}, 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
|
|
1217
1102
|
});
|
|
1218
1103
|
}
|
|
1219
1104
|
//---- END Cache-enabled EZSP wrappers
|
|
@@ -1227,35 +1112,40 @@ class EmberAdapter extends __1.Adapter {
|
|
|
1227
1112
|
* Does nothing if ncpNeedsResetAndInit == true.
|
|
1228
1113
|
*/
|
|
1229
1114
|
async emberVersion() {
|
|
1230
|
-
// Note that NCP == Network Co-Processor
|
|
1231
|
-
// the EZSP protocol version that the Host is running, we are the host so we set this value
|
|
1232
|
-
const hostEzspProtocolVer = consts_1.EZSP_PROTOCOL_VERSION;
|
|
1233
1115
|
// send the Host version number to the NCP.
|
|
1234
1116
|
// The NCP returns the EZSP version that the NCP is running along with the stackType and stackVersion
|
|
1235
|
-
|
|
1117
|
+
let [ncpEzspProtocolVer, ncpStackType, ncpStackVer] = await this.ezsp.ezspVersion(consts_2.EZSP_PROTOCOL_VERSION);
|
|
1236
1118
|
// verify that the stack type is what is expected
|
|
1237
|
-
if (ncpStackType !==
|
|
1119
|
+
if (ncpStackType !== consts_2.EZSP_STACK_TYPE_MESH) {
|
|
1238
1120
|
throw new Error(`Stack type ${ncpStackType} is not expected!`);
|
|
1239
1121
|
}
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1122
|
+
if (ncpEzspProtocolVer === consts_2.EZSP_PROTOCOL_VERSION) {
|
|
1123
|
+
logger_1.logger.debug(`Adapter EZSP protocol version (${ncpEzspProtocolVer}) matches Host.`, NS);
|
|
1124
|
+
}
|
|
1125
|
+
else if (ncpEzspProtocolVer < consts_2.EZSP_PROTOCOL_VERSION && ncpEzspProtocolVer >= consts_2.EZSP_MIN_PROTOCOL_VERSION) {
|
|
1126
|
+
[ncpEzspProtocolVer, ncpStackType, ncpStackVer] = await this.ezsp.ezspVersion(ncpEzspProtocolVer);
|
|
1127
|
+
logger_1.logger.info(`Adapter EZSP protocol version (${ncpEzspProtocolVer}) lower than Host. Switched.`, NS);
|
|
1128
|
+
}
|
|
1129
|
+
else {
|
|
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}].`);
|
|
1243
1132
|
}
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1133
|
+
this.ezsp.setProtocolVersion(ncpEzspProtocolVer);
|
|
1134
|
+
logger_1.logger.debug(`Adapter info: EZSPVersion=${ncpEzspProtocolVer} StackType=${ncpStackType} StackVersion=${ncpStackVer}`, NS);
|
|
1135
|
+
const [status, versionStruct] = await this.ezsp.ezspGetVersionStruct();
|
|
1136
|
+
if (status !== enums_1.SLStatus.OK) {
|
|
1247
1137
|
// Should never happen with support of only EZSP v13+
|
|
1248
1138
|
throw new Error(`NCP has old-style version number. Not supported.`);
|
|
1249
1139
|
}
|
|
1250
1140
|
this.version = {
|
|
1251
1141
|
ezsp: ncpEzspProtocolVer,
|
|
1252
|
-
revision: `${versionStruct.major}.${versionStruct.minor}.${versionStruct.patch} [${
|
|
1142
|
+
revision: `${versionStruct.major}.${versionStruct.minor}.${versionStruct.patch} [${enums_1.EmberVersionType[versionStruct.type]}]`,
|
|
1253
1143
|
...versionStruct,
|
|
1254
1144
|
};
|
|
1255
|
-
if (versionStruct.type !==
|
|
1256
|
-
logger_1.logger.warning(`
|
|
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);
|
|
1257
1147
|
}
|
|
1258
|
-
logger_1.logger.
|
|
1148
|
+
logger_1.logger.info(`Adapter version info: ${JSON.stringify(this.version)}`, NS);
|
|
1259
1149
|
}
|
|
1260
1150
|
/**
|
|
1261
1151
|
* This function sets an EZSP config value.
|
|
@@ -1266,15 +1156,11 @@ class EmberAdapter extends __1.Adapter {
|
|
|
1266
1156
|
* @returns
|
|
1267
1157
|
*/
|
|
1268
1158
|
async emberSetEzspConfigValue(configId, value) {
|
|
1269
|
-
const status =
|
|
1270
|
-
logger_1.logger.debug(`[EzspConfigId] SET "${enums_2.EzspConfigId[configId]}" TO "${value}" with status=${
|
|
1271
|
-
if (status
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
}
|
|
1275
|
-
else if (status !== enums_3.EzspStatus.SUCCESS) {
|
|
1276
|
-
logger_1.logger.warning(`[EzspConfigId] Failed to SET "${enums_2.EzspConfigId[configId]}" TO "${value}" with status=${enums_3.EzspStatus[status]}. `
|
|
1277
|
-
+ `Firmware value will be used instead.`, NS);
|
|
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);
|
|
1278
1164
|
}
|
|
1279
1165
|
return status;
|
|
1280
1166
|
}
|
|
@@ -1286,8 +1172,8 @@ class EmberAdapter extends __1.Adapter {
|
|
|
1286
1172
|
* @returns
|
|
1287
1173
|
*/
|
|
1288
1174
|
async emberSetEzspValue(valueId, valueLength, value) {
|
|
1289
|
-
const status =
|
|
1290
|
-
logger_1.logger.debug(`[EzspValueId] SET "${enums_2.EzspValueId[valueId]}" TO "${value}" with status=${
|
|
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);
|
|
1291
1177
|
return status;
|
|
1292
1178
|
}
|
|
1293
1179
|
/**
|
|
@@ -1297,8 +1183,8 @@ class EmberAdapter extends __1.Adapter {
|
|
|
1297
1183
|
* @returns
|
|
1298
1184
|
*/
|
|
1299
1185
|
async emberSetEzspPolicy(policyId, decisionId) {
|
|
1300
|
-
const status =
|
|
1301
|
-
logger_1.logger.debug(`[EzspPolicyId] SET "${enums_2.EzspPolicyId[policyId]}" TO "${decisionId}" with status=${
|
|
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);
|
|
1302
1188
|
return status;
|
|
1303
1189
|
}
|
|
1304
1190
|
/**
|
|
@@ -1314,9 +1200,10 @@ class EmberAdapter extends __1.Adapter {
|
|
|
1314
1200
|
*/
|
|
1315
1201
|
async aesMmoHash(context, finalize, data) {
|
|
1316
1202
|
if (data.length > 255) {
|
|
1317
|
-
|
|
1203
|
+
// will be caught by request queue and rejected internally.
|
|
1204
|
+
throw new ezspError_1.EzspError(enums_1.EzspStatus.ERROR_INVALID_CALL);
|
|
1318
1205
|
}
|
|
1319
|
-
const [status, reContext] =
|
|
1206
|
+
const [status, reContext] = await this.ezsp.ezspAesMmoHash(context, finalize, data);
|
|
1320
1207
|
return [status, reContext];
|
|
1321
1208
|
}
|
|
1322
1209
|
/**
|
|
@@ -1327,7 +1214,7 @@ class EmberAdapter extends __1.Adapter {
|
|
|
1327
1214
|
* @param context EmberAesMmoHashContext* A pointer to the location of the hash context to update.
|
|
1328
1215
|
* @param data const uint8_t* A pointer to the location of the data to hash.
|
|
1329
1216
|
*
|
|
1330
|
-
* @returns An ::
|
|
1217
|
+
* @returns An ::SLStatus value indicating EMBER_SUCCESS if the hash was
|
|
1331
1218
|
* calculated successfully. EMBER_INVALID_CALL if the block size is not a
|
|
1332
1219
|
* multiple of 16 bytes, and EMBER_INDEX_OUT_OF_RANGE is returned when the
|
|
1333
1220
|
* data exceeds the maximum limits of the hash function.
|
|
@@ -1347,7 +1234,7 @@ class EmberAdapter extends __1.Adapter {
|
|
|
1347
1234
|
* @param context EmberAesMmoHashContext * A pointer to the location of the hash context to finalize.
|
|
1348
1235
|
* @param data uint8_t * A pointer to the location of data to hash. May be NULL.
|
|
1349
1236
|
*
|
|
1350
|
-
* @returns An ::
|
|
1237
|
+
* @returns An ::SLStatus value indicating EMBER_SUCCESS if the hash was
|
|
1351
1238
|
* calculated successfully. EMBER_INVALID_CALL if the block size is not a
|
|
1352
1239
|
* multiple of 16 bytes, and EMBER_INDEX_OUT_OF_RANGE is returned when the
|
|
1353
1240
|
* data exceeds the maximum limits of the hash function.
|
|
@@ -1362,7 +1249,7 @@ class EmberAdapter extends __1.Adapter {
|
|
|
1362
1249
|
*
|
|
1363
1250
|
* @param data const uint8_t* The data to hash. Expected of valid length (as in, not larger alloc)
|
|
1364
1251
|
*
|
|
1365
|
-
* @returns An ::
|
|
1252
|
+
* @returns An ::SLStatus value indicating EMBER_SUCCESS if the hash was
|
|
1366
1253
|
* calculated successfully. EMBER_INVALID_CALL if the block size is not a
|
|
1367
1254
|
* multiple of 16 bytes, and EMBER_INDEX_OUT_OF_RANGE is returned when the
|
|
1368
1255
|
* data exceeds the maximum limits of the hash function.
|
|
@@ -1370,7 +1257,7 @@ class EmberAdapter extends __1.Adapter {
|
|
|
1370
1257
|
*/
|
|
1371
1258
|
async emberAesHashSimple(data) {
|
|
1372
1259
|
const context = (0, initters_1.aesMmoHashInit)();
|
|
1373
|
-
const [status, reContext] =
|
|
1260
|
+
const [status, reContext] = await this.emberAesMmoHashFinal(context, data);
|
|
1374
1261
|
return [status, reContext?.result];
|
|
1375
1262
|
}
|
|
1376
1263
|
/**
|
|
@@ -1387,13 +1274,14 @@ class EmberAdapter extends __1.Adapter {
|
|
|
1387
1274
|
* @returns messageTag The tag passed to ezspSend${x} function.
|
|
1388
1275
|
*/
|
|
1389
1276
|
async emberPermitJoining(duration, broadcastMgmtPermitJoin) {
|
|
1390
|
-
let status =
|
|
1277
|
+
let status = await this.ezsp.ezspPermitJoining(duration);
|
|
1391
1278
|
let apsFrame = null;
|
|
1392
1279
|
let messageTag = null;
|
|
1393
1280
|
logger_1.logger.debug(`Permit joining for ${duration} sec. status=${[status]}`, NS);
|
|
1394
1281
|
if (broadcastMgmtPermitJoin) {
|
|
1395
1282
|
// `authentication`: TC significance always 1 (zb specs)
|
|
1396
|
-
|
|
1283
|
+
const zdoPayload = buffaloZdo_1.BuffaloZdo.buildPermitJoining(duration, 1, []);
|
|
1284
|
+
[status, apsFrame, messageTag] = await this.sendZDORequest(ZSpec.BroadcastAddress.DEFAULT, Zdo.ClusterId.PERMIT_JOINING_REQUEST, zdoPayload, DEFAULT_APS_OPTIONS);
|
|
1397
1285
|
}
|
|
1398
1286
|
return [status, apsFrame, messageTag];
|
|
1399
1287
|
}
|
|
@@ -1404,92 +1292,17 @@ class EmberAdapter extends __1.Adapter {
|
|
|
1404
1292
|
*/
|
|
1405
1293
|
async emberSetJoinPolicy(decision) {
|
|
1406
1294
|
let policy = enums_2.EzspDecisionBitmask.DEFAULT_CONFIGURATION;
|
|
1407
|
-
if (decision ==
|
|
1408
|
-
policy =
|
|
1295
|
+
if (decision == enums_1.EmberJoinDecision.USE_PRECONFIGURED_KEY) {
|
|
1296
|
+
policy = enums_2.EzspDecisionBitmask.ALLOW_JOINS | enums_2.EzspDecisionBitmask.ALLOW_UNSECURED_REJOINS;
|
|
1409
1297
|
}
|
|
1410
|
-
else if (decision ==
|
|
1411
|
-
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;
|
|
1412
1300
|
}
|
|
1413
|
-
else if (decision ==
|
|
1301
|
+
else if (decision == enums_1.EmberJoinDecision.ALLOW_REJOINS_ONLY) {
|
|
1414
1302
|
policy = enums_2.EzspDecisionBitmask.ALLOW_UNSECURED_REJOINS;
|
|
1415
1303
|
}
|
|
1416
1304
|
return this.emberSetEzspPolicy(enums_2.EzspPolicyId.TRUST_CENTER_POLICY, policy);
|
|
1417
1305
|
}
|
|
1418
|
-
/**
|
|
1419
|
-
* Get Source Route Overhead
|
|
1420
|
-
*
|
|
1421
|
-
* Returns the number of bytes needed in a packet for source routing.
|
|
1422
|
-
* Since each hop consumes 2 bytes in the packet, this routine calculates the
|
|
1423
|
-
* total number of bytes needed based on number of hops to reach the destination.
|
|
1424
|
-
*
|
|
1425
|
-
* This function is called by the framework to determine the overhead required
|
|
1426
|
-
* in the network frame for source routing to a particular destination.
|
|
1427
|
-
*
|
|
1428
|
-
* @param destination The node id of the destination Ver.: always
|
|
1429
|
-
* @returns int8u The number of bytes needed for source routing in a packet.
|
|
1430
|
-
*/
|
|
1431
|
-
async emberGetSourceRouteOverhead(destination) {
|
|
1432
|
-
const [status, value] = (await this.ezsp.ezspGetSourceRouteOverhead(destination));
|
|
1433
|
-
if (status === enums_3.EzspStatus.SUCCESS) {
|
|
1434
|
-
return value;
|
|
1435
|
-
}
|
|
1436
|
-
else {
|
|
1437
|
-
logger_1.logger.debug(`Failed to get source route overhead (via extended value), status=${enums_3.EzspStatus[status]}.`, NS);
|
|
1438
|
-
}
|
|
1439
|
-
return 0;
|
|
1440
|
-
}
|
|
1441
|
-
/**
|
|
1442
|
-
* Return the maximum size of the payload that the Application Support sub-layer will accept for
|
|
1443
|
-
* the given message type, destination, and APS frame.
|
|
1444
|
-
*
|
|
1445
|
-
* The size depends on multiple factors, including the security level in use and additional information
|
|
1446
|
-
* added to the message to support the various options.
|
|
1447
|
-
*
|
|
1448
|
-
* @param type The outgoing message type.
|
|
1449
|
-
* @param indexOrDestination uint16_t Depending on the message type, this is either the
|
|
1450
|
-
* EmberNodeId of the destination, an index into the address table, an index
|
|
1451
|
-
* into the binding table, the multicast identifier, or a broadcast address.
|
|
1452
|
-
* @param apsFrame EmberApsFrame *The APS frame for the message.
|
|
1453
|
-
* @return uint8_t The maximum APS payload length for the given message.
|
|
1454
|
-
*/
|
|
1455
|
-
async maximumApsPayloadLength(type, indexOrDestination, apsFrame) {
|
|
1456
|
-
let destination = consts_2.EMBER_UNKNOWN_NODE_ID;
|
|
1457
|
-
let max = consts_2.MAXIMUM_APS_PAYLOAD_LENGTH; // uint8_t
|
|
1458
|
-
if ((apsFrame.options & enums_3.EmberApsOption.ENCRYPTION) !== 0) {
|
|
1459
|
-
max -= consts_2.APS_ENCRYPTION_OVERHEAD;
|
|
1460
|
-
}
|
|
1461
|
-
if ((apsFrame.options & enums_3.EmberApsOption.SOURCE_EUI64) !== 0) {
|
|
1462
|
-
max -= consts_1.EUI64_SIZE;
|
|
1463
|
-
}
|
|
1464
|
-
if ((apsFrame.options & enums_3.EmberApsOption.DESTINATION_EUI64) !== 0) {
|
|
1465
|
-
max -= consts_1.EUI64_SIZE;
|
|
1466
|
-
}
|
|
1467
|
-
if ((apsFrame.options & enums_3.EmberApsOption.FRAGMENT) !== 0) {
|
|
1468
|
-
max -= consts_2.APS_FRAGMENTATION_OVERHEAD;
|
|
1469
|
-
}
|
|
1470
|
-
switch (type) {
|
|
1471
|
-
case enums_3.EmberOutgoingMessageType.DIRECT:
|
|
1472
|
-
destination = indexOrDestination;
|
|
1473
|
-
break;
|
|
1474
|
-
case enums_3.EmberOutgoingMessageType.VIA_ADDRESS_TABLE:
|
|
1475
|
-
destination = (await this.ezsp.ezspGetAddressTableRemoteNodeId(indexOrDestination));
|
|
1476
|
-
break;
|
|
1477
|
-
case enums_3.EmberOutgoingMessageType.VIA_BINDING:
|
|
1478
|
-
destination = (await this.ezsp.ezspGetBindingRemoteNodeId(indexOrDestination));
|
|
1479
|
-
break;
|
|
1480
|
-
case enums_3.EmberOutgoingMessageType.MULTICAST:
|
|
1481
|
-
// APS multicast messages include the two-byte group id and exclude the one-byte destination endpoint,
|
|
1482
|
-
// for a net loss of an extra byte.
|
|
1483
|
-
max--;
|
|
1484
|
-
break;
|
|
1485
|
-
case enums_3.EmberOutgoingMessageType.BROADCAST:
|
|
1486
|
-
break;
|
|
1487
|
-
default:
|
|
1488
|
-
break;
|
|
1489
|
-
}
|
|
1490
|
-
max -= (await this.emberGetSourceRouteOverhead(destination));
|
|
1491
|
-
return max;
|
|
1492
|
-
}
|
|
1493
1306
|
//---- END EZSP wrappers
|
|
1494
1307
|
//---- START Ember ZDO
|
|
1495
1308
|
/**
|
|
@@ -1521,525 +1334,55 @@ class EmberAdapter extends __1.Adapter {
|
|
|
1521
1334
|
* @return uint8_t The next device request sequence number
|
|
1522
1335
|
*/
|
|
1523
1336
|
nextZDORequestSequence() {
|
|
1524
|
-
return (this.zdoRequestSequence =
|
|
1337
|
+
return (this.zdoRequestSequence = ++this.zdoRequestSequence & APPLICATION_ZDO_SEQUENCE_MASK);
|
|
1525
1338
|
}
|
|
1526
1339
|
/**
|
|
1527
1340
|
* ZDO
|
|
1528
1341
|
*
|
|
1529
1342
|
* @param destination
|
|
1530
1343
|
* @param clusterId uint16_t
|
|
1344
|
+
* @param messageContents Content of the ZDO request (sequence to be assigned at index zero)
|
|
1531
1345
|
* @param options
|
|
1532
|
-
* @param length uint8_t
|
|
1533
1346
|
* @returns status Indicates success or failure (with reason) of send
|
|
1534
1347
|
* @returns apsFrame The APS Frame resulting of the request being built and sent (`sequence` set from stack-given value).
|
|
1535
1348
|
* @returns messageTag The tag passed to ezspSend${x} function.
|
|
1536
1349
|
*/
|
|
1537
|
-
async
|
|
1538
|
-
if (
|
|
1539
|
-
return [
|
|
1350
|
+
async sendZDORequest(destination, clusterId, messageContents, options) {
|
|
1351
|
+
if (messageContents.length > consts_2.EZSP_MAX_FRAME_LENGTH) {
|
|
1352
|
+
return [enums_1.SLStatus.MESSAGE_TOO_LONG, null, null];
|
|
1540
1353
|
}
|
|
1541
1354
|
const messageTag = this.nextZDORequestSequence();
|
|
1542
|
-
|
|
1355
|
+
messageContents[0] = messageTag;
|
|
1543
1356
|
const apsFrame = {
|
|
1544
|
-
profileId:
|
|
1545
|
-
clusterId
|
|
1546
|
-
sourceEndpoint:
|
|
1547
|
-
destinationEndpoint:
|
|
1548
|
-
options
|
|
1357
|
+
profileId: Zdo.ZDO_PROFILE_ID,
|
|
1358
|
+
clusterId,
|
|
1359
|
+
sourceEndpoint: Zdo.ZDO_ENDPOINT,
|
|
1360
|
+
destinationEndpoint: Zdo.ZDO_ENDPOINT,
|
|
1361
|
+
options,
|
|
1549
1362
|
groupId: 0,
|
|
1550
1363
|
sequence: 0, // set by stack
|
|
1551
1364
|
};
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
logger_1.logger.debug(`~~~> [ZDO BROADCAST
|
|
1556
|
-
|
|
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);
|
|
1370
|
+
const [status, apsSequence] = await this.ezsp.ezspSendBroadcast(ZSpec.NULL_NODE_ID, // alias
|
|
1371
|
+
destination, 0, // nwkSequence
|
|
1372
|
+
apsFrame, this.getZDORequestRadius(), messageTag, messageContents);
|
|
1557
1373
|
apsFrame.sequence = apsSequence;
|
|
1558
|
-
logger_1.logger.debug(`~~~> [SENT ZDO type=BROADCAST
|
|
1374
|
+
logger_1.logger.debug(`~~~> [SENT ZDO type=BROADCAST apsSequence=${apsSequence} messageTag=${messageTag} status=${enums_1.SLStatus[status]}`, NS);
|
|
1559
1375
|
return [status, apsFrame, messageTag];
|
|
1560
1376
|
}
|
|
1561
1377
|
else {
|
|
1562
|
-
logger_1.logger.debug(`~~~> [ZDO UNICAST
|
|
1563
|
-
|
|
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);
|
|
1564
1381
|
apsFrame.sequence = apsSequence;
|
|
1565
|
-
logger_1.logger.debug(`~~~> [SENT ZDO type=DIRECT
|
|
1382
|
+
logger_1.logger.debug(`~~~> [SENT ZDO type=DIRECT apsSequence=${apsSequence} messageTag=${messageTag} status=${enums_1.SLStatus[status]}`, NS);
|
|
1566
1383
|
return [status, apsFrame, messageTag];
|
|
1567
1384
|
}
|
|
1568
1385
|
}
|
|
1569
|
-
/**
|
|
1570
|
-
* ZDO
|
|
1571
|
-
* Service Discovery Functions
|
|
1572
|
-
* Request the specified node to send a list of its endpoints that
|
|
1573
|
-
* match the specified application profile and, optionally, lists of input
|
|
1574
|
-
* and/or output clusters.
|
|
1575
|
-
* @param target The node whose matching endpoints are desired. The request can
|
|
1576
|
-
* be sent unicast or broadcast ONLY to the "RX-on-when-idle-address" (0xFFFD)
|
|
1577
|
-
* If sent as a broadcast, any node that has matching endpoints will send a
|
|
1578
|
-
* response.
|
|
1579
|
-
* @param profile uint16_t The application profile to match.
|
|
1580
|
-
* @param inCount uint8_t The number of input clusters. To not match any input
|
|
1581
|
-
* clusters, set this value to 0.
|
|
1582
|
-
* @param outCount uint8_t The number of output clusters. To not match any output
|
|
1583
|
-
* clusters, set this value to 0.
|
|
1584
|
-
* @param inClusters uint16_t * The list of input clusters.
|
|
1585
|
-
* @param outClusters uint16_t * The list of output clusters.
|
|
1586
|
-
* @param options The options to use when sending the unicast request. See
|
|
1587
|
-
* emberSendUnicast() for a description. This parameter is ignored if the target
|
|
1588
|
-
* is a broadcast address.
|
|
1589
|
-
* @returns An EmberStatus value. EMBER_SUCCESS, MESSAGE_TOO_LONG,
|
|
1590
|
-
* EMBER_NETWORK_DOWN or EMBER_NETWORK_BUSY.
|
|
1591
|
-
*/
|
|
1592
|
-
async emberMatchDescriptorsRequest(target, profile, inClusters, outClusters, options) {
|
|
1593
|
-
// 2 bytes for NWK Address + 2 bytes for Profile Id + 1 byte for in Cluster Count
|
|
1594
|
-
// + in times 2 for 2 byte Clusters + out Cluster Count + out times 2 for 2 byte Clusters
|
|
1595
|
-
const length = (zdo_1.ZDO_MESSAGE_OVERHEAD + 2 + 2 + 1 + (inClusters.length * 2) + 1 + (outClusters.length * 2));
|
|
1596
|
-
// sanity check
|
|
1597
|
-
if (length > consts_1.EZSP_MAX_FRAME_LENGTH) {
|
|
1598
|
-
return [enums_3.EmberStatus.MESSAGE_TOO_LONG, null, null];
|
|
1599
|
-
}
|
|
1600
|
-
this.zdoRequestBuffalo.setPosition(zdo_1.ZDO_MESSAGE_OVERHEAD);
|
|
1601
|
-
this.zdoRequestBuffalo.writeUInt16(target);
|
|
1602
|
-
this.zdoRequestBuffalo.writeUInt16(profile);
|
|
1603
|
-
this.zdoRequestBuffalo.writeUInt8(inClusters.length);
|
|
1604
|
-
this.zdoRequestBuffalo.writeListUInt16(inClusters);
|
|
1605
|
-
this.zdoRequestBuffalo.writeUInt8(outClusters.length);
|
|
1606
|
-
this.zdoRequestBuffalo.writeListUInt16(outClusters);
|
|
1607
|
-
logger_1.logger.debug(`~~~> [ZDO MATCH_DESCRIPTORS_REQUEST target=${target} profile=${profile} inClusters=${inClusters} outClusters=${outClusters}]`, NS);
|
|
1608
|
-
return this.sendZDORequestBuffer(target, zdo_1.MATCH_DESCRIPTORS_REQUEST, options);
|
|
1609
|
-
}
|
|
1610
|
-
/**
|
|
1611
|
-
* ZDO
|
|
1612
|
-
* Device Discovery Functions
|
|
1613
|
-
* Request the 16 bit network address of a node whose EUI64 is known.
|
|
1614
|
-
*
|
|
1615
|
-
* @param target The EUI64 of the node.
|
|
1616
|
-
* @param reportKids true to request that the target list their children
|
|
1617
|
-
* in the response.
|
|
1618
|
-
* @param childStartIndex uint8_t The index of the first child to list in the response.
|
|
1619
|
-
* Ignored if @c reportKids is false.
|
|
1620
|
-
*
|
|
1621
|
-
* @return An ::EmberStatus value.
|
|
1622
|
-
* - ::EMBER_SUCCESS - The request was transmitted successfully.
|
|
1623
|
-
* - ::EMBER_NO_BUFFERS - Insufficient message buffers were available to construct the request.
|
|
1624
|
-
* - ::EMBER_NETWORK_DOWN - The node is not part of a network.
|
|
1625
|
-
* - ::EMBER_NETWORK_BUSY - Transmission of the request failed.
|
|
1626
|
-
*/
|
|
1627
|
-
async emberNetworkAddressRequest(target, reportKids, childStartIndex) {
|
|
1628
|
-
this.zdoRequestBuffalo.setPosition(zdo_1.ZDO_MESSAGE_OVERHEAD);
|
|
1629
|
-
this.zdoRequestBuffalo.writeIeeeAddr(target);
|
|
1630
|
-
this.zdoRequestBuffalo.writeUInt8(reportKids ? 1 : 0);
|
|
1631
|
-
this.zdoRequestBuffalo.writeUInt8(childStartIndex);
|
|
1632
|
-
logger_1.logger.debug(`~~~> [ZDO NETWORK_ADDRESS_REQUEST target=${target} reportKids=${reportKids} childStartIndex=${childStartIndex}]`, NS);
|
|
1633
|
-
return this.sendZDORequestBuffer(enums_1.BroadcastAddress.RX_ON_WHEN_IDLE, zdo_1.NETWORK_ADDRESS_REQUEST, enums_3.EmberApsOption.SOURCE_EUI64);
|
|
1634
|
-
}
|
|
1635
|
-
/**
|
|
1636
|
-
* ZDO
|
|
1637
|
-
* Device Discovery Functions
|
|
1638
|
-
* @brief Request the EUI64 of a node whose 16 bit network address is known.
|
|
1639
|
-
*
|
|
1640
|
-
* @param target uint16_t The network address of the node.
|
|
1641
|
-
* @param reportKids uint8_t true to request that the target list their children
|
|
1642
|
-
* in the response.
|
|
1643
|
-
* @param childStartIndex uint8_t The index of the first child to list in the response.
|
|
1644
|
-
* Ignored if reportKids is false.
|
|
1645
|
-
* @param options The options to use when sending the request. See ::emberSendUnicast() for a description.
|
|
1646
|
-
*
|
|
1647
|
-
* @return An ::EmberStatus value.
|
|
1648
|
-
* - ::EMBER_SUCCESS
|
|
1649
|
-
* - ::EMBER_NO_BUFFERS
|
|
1650
|
-
* - ::EMBER_NETWORK_DOWN
|
|
1651
|
-
* - ::EMBER_NETWORK_BUSY
|
|
1652
|
-
*/
|
|
1653
|
-
async emberIeeeAddressRequest(target, reportKids, childStartIndex, options) {
|
|
1654
|
-
this.zdoRequestBuffalo.setPosition(zdo_1.ZDO_MESSAGE_OVERHEAD);
|
|
1655
|
-
this.zdoRequestBuffalo.writeUInt16(target);
|
|
1656
|
-
this.zdoRequestBuffalo.writeUInt8(reportKids ? 1 : 0);
|
|
1657
|
-
this.zdoRequestBuffalo.writeUInt8(childStartIndex);
|
|
1658
|
-
logger_1.logger.debug(`~~~> [ZDO IEEE_ADDRESS_REQUEST target=${target} reportKids=${reportKids} childStartIndex=${childStartIndex}]`, NS);
|
|
1659
|
-
return this.sendZDORequestBuffer(target, zdo_1.IEEE_ADDRESS_REQUEST, options);
|
|
1660
|
-
}
|
|
1661
|
-
/**
|
|
1662
|
-
* ZDO
|
|
1663
|
-
* @param discoveryNodeId uint16_t
|
|
1664
|
-
* @param reportKids uint8_t
|
|
1665
|
-
* @param childStartIndex uint8_t
|
|
1666
|
-
* @param options
|
|
1667
|
-
* @param targetNodeIdOfRequest
|
|
1668
|
-
*/
|
|
1669
|
-
async emberIeeeAddressRequestToTarget(discoveryNodeId, reportKids, childStartIndex, options, targetNodeIdOfRequest) {
|
|
1670
|
-
this.zdoRequestBuffalo.setPosition(zdo_1.ZDO_MESSAGE_OVERHEAD);
|
|
1671
|
-
this.zdoRequestBuffalo.writeUInt16(discoveryNodeId);
|
|
1672
|
-
this.zdoRequestBuffalo.writeUInt8(reportKids ? 1 : 0);
|
|
1673
|
-
this.zdoRequestBuffalo.writeUInt8(childStartIndex);
|
|
1674
|
-
logger_1.logger.debug(`~~~> [ZDO IEEE_ADDRESS_REQUEST targetNodeIdOfRequest=${targetNodeIdOfRequest} discoveryNodeId=${discoveryNodeId} `
|
|
1675
|
-
+ `reportKids=${reportKids} childStartIndex=${childStartIndex}]`, NS);
|
|
1676
|
-
return this.sendZDORequestBuffer(targetNodeIdOfRequest, zdo_1.IEEE_ADDRESS_REQUEST, options);
|
|
1677
|
-
}
|
|
1678
|
-
/**
|
|
1679
|
-
* ZDO
|
|
1680
|
-
*
|
|
1681
|
-
* @param target uint16_t
|
|
1682
|
-
* @param clusterId uint16_t
|
|
1683
|
-
* @param options
|
|
1684
|
-
* @returns
|
|
1685
|
-
*/
|
|
1686
|
-
async emberSendZigDevRequestTarget(target, clusterId, options) {
|
|
1687
|
-
this.zdoRequestBuffalo.setPosition(zdo_1.ZDO_MESSAGE_OVERHEAD);
|
|
1688
|
-
this.zdoRequestBuffalo.writeUInt16(target);
|
|
1689
|
-
return this.sendZDORequestBuffer(target, clusterId, options);
|
|
1690
|
-
}
|
|
1691
|
-
/**
|
|
1692
|
-
* ZDO
|
|
1693
|
-
* @brief Request the specified node to send the simple descriptor for
|
|
1694
|
-
* the specified endpoint.
|
|
1695
|
-
* The simple descriptor contains information specific
|
|
1696
|
-
* to a single endpoint. It describes the application profile identifier,
|
|
1697
|
-
* application device identifier, application device version, application flags,
|
|
1698
|
-
* application input clusters and application output clusters. It is defined in
|
|
1699
|
-
* the ZigBee Application Framework Specification.
|
|
1700
|
-
*
|
|
1701
|
-
* @param target uint16_t The node of interest.
|
|
1702
|
-
* @param targetEndpoint uint8_t The endpoint on the target node whose simple
|
|
1703
|
-
* descriptor is desired.
|
|
1704
|
-
* @param options The options to use when sending the request. See
|
|
1705
|
-
* emberSendUnicast() for a description.
|
|
1706
|
-
*
|
|
1707
|
-
* @return An EmberStatus value. ::EMBER_SUCCESS, ::EMBER_NO_BUFFERS,
|
|
1708
|
-
* ::EMBER_NETWORK_DOWN or ::EMBER_NETWORK_BUSY.
|
|
1709
|
-
*/
|
|
1710
|
-
async emberSimpleDescriptorRequest(target, targetEndpoint, options) {
|
|
1711
|
-
this.zdoRequestBuffalo.setPosition(zdo_1.ZDO_MESSAGE_OVERHEAD);
|
|
1712
|
-
this.zdoRequestBuffalo.writeUInt16(target);
|
|
1713
|
-
this.zdoRequestBuffalo.writeUInt8(targetEndpoint);
|
|
1714
|
-
logger_1.logger.debug(`~~~> [ZDO SIMPLE_DESCRIPTOR_REQUEST target=${target} targetEndpoint=${targetEndpoint}]`, NS);
|
|
1715
|
-
return this.sendZDORequestBuffer(target, zdo_1.SIMPLE_DESCRIPTOR_REQUEST, options);
|
|
1716
|
-
}
|
|
1717
|
-
/**
|
|
1718
|
-
* ZDO
|
|
1719
|
-
* Common logic used by `emberBindRequest` & `emberUnbindRequest`.
|
|
1720
|
-
*
|
|
1721
|
-
* @param target
|
|
1722
|
-
* @param bindClusterId
|
|
1723
|
-
* @param source
|
|
1724
|
-
* @param sourceEndpoint
|
|
1725
|
-
* @param clusterId
|
|
1726
|
-
* @param type
|
|
1727
|
-
* @param destination
|
|
1728
|
-
* @param groupAddress
|
|
1729
|
-
* @param destinationEndpoint
|
|
1730
|
-
* @param options
|
|
1731
|
-
*
|
|
1732
|
-
* @returns An ::EmberStatus value.
|
|
1733
|
-
* - ::EMBER_SUCCESS
|
|
1734
|
-
* - ::EMBER_NO_BUFFERS
|
|
1735
|
-
* - ::EMBER_NETWORK_DOWN
|
|
1736
|
-
* - ::EMBER_NETWORK_BUSY
|
|
1737
|
-
* @returns APS frame created for the request
|
|
1738
|
-
* @returns The tag used on the message.
|
|
1739
|
-
*/
|
|
1740
|
-
async emberSendZigDevBindRequest(target, bindClusterId, source, sourceEndpoint, clusterId, type, destination, groupAddress, destinationEndpoint, options) {
|
|
1741
|
-
this.zdoRequestBuffalo.setPosition(zdo_1.ZDO_MESSAGE_OVERHEAD);
|
|
1742
|
-
this.zdoRequestBuffalo.writeIeeeAddr(source);
|
|
1743
|
-
this.zdoRequestBuffalo.writeUInt8(sourceEndpoint);
|
|
1744
|
-
this.zdoRequestBuffalo.writeUInt16(clusterId);
|
|
1745
|
-
this.zdoRequestBuffalo.writeUInt8(type);
|
|
1746
|
-
switch (type) {
|
|
1747
|
-
case zdo_1.UNICAST_BINDING:
|
|
1748
|
-
this.zdoRequestBuffalo.writeIeeeAddr(destination);
|
|
1749
|
-
this.zdoRequestBuffalo.writeUInt8(destinationEndpoint);
|
|
1750
|
-
break;
|
|
1751
|
-
case zdo_1.MULTICAST_BINDING:
|
|
1752
|
-
this.zdoRequestBuffalo.writeUInt16(groupAddress);
|
|
1753
|
-
break;
|
|
1754
|
-
default:
|
|
1755
|
-
return [enums_3.EmberStatus.ERR_FATAL, null, null];
|
|
1756
|
-
}
|
|
1757
|
-
return this.sendZDORequestBuffer(target, bindClusterId, options);
|
|
1758
|
-
}
|
|
1759
|
-
/**
|
|
1760
|
-
* ZDO
|
|
1761
|
-
* Send a request to create a binding entry with the specified
|
|
1762
|
-
* contents on the specified node.
|
|
1763
|
-
*
|
|
1764
|
-
* @param target The node on which the binding will be created.
|
|
1765
|
-
* @param source The source EUI64 in the binding entry.
|
|
1766
|
-
* @param sourceEndpoint The source endpoint in the binding entry.
|
|
1767
|
-
* @param clusterId The cluster ID in the binding entry.
|
|
1768
|
-
* @param type The type of binding, either ::UNICAST_BINDING,
|
|
1769
|
-
* ::MULTICAST_BINDING, or ::UNICAST_MANY_TO_ONE_BINDING.
|
|
1770
|
-
* ::UNICAST_MANY_TO_ONE_BINDING is an Ember-specific extension
|
|
1771
|
-
* and should be used only when the target is an Ember device.
|
|
1772
|
-
* @param destination The destination EUI64 in the binding entry for
|
|
1773
|
-
* ::UNICAST_BINDING or ::UNICAST_MANY_TO_ONE_BINDING.
|
|
1774
|
-
* @param groupAddress The group address for the ::MULTICAST_BINDING.
|
|
1775
|
-
* @param destinationEndpoint The destination endpoint in the binding entry for
|
|
1776
|
-
* the ::UNICAST_BINDING or ::UNICAST_MANY_TO_ONE_BINDING.
|
|
1777
|
-
* @param options The options to use when sending the request. See
|
|
1778
|
-
* emberSendUnicast() for a description.
|
|
1779
|
-
*
|
|
1780
|
-
* @returns An ::EmberStatus value.
|
|
1781
|
-
* - ::EMBER_SUCCESS
|
|
1782
|
-
* - ::EMBER_NO_BUFFERS
|
|
1783
|
-
* - ::EMBER_NETWORK_DOWN
|
|
1784
|
-
* - ::EMBER_NETWORK_BUSY
|
|
1785
|
-
* @returns APS frame created for the request
|
|
1786
|
-
* @returns The tag used on the message.
|
|
1787
|
-
*/
|
|
1788
|
-
async emberBindRequest(target, source, sourceEndpoint, clusterId, type, destination, groupAddress, destinationEndpoint, options) {
|
|
1789
|
-
logger_1.logger.debug(`~~~> [ZDO BIND_REQUEST target=${target} source=${source} sourceEndpoint=${sourceEndpoint} clusterId=${clusterId} type=${type} `
|
|
1790
|
-
+ `destination=${destination} groupAddress=${groupAddress} destinationEndpoint=${destinationEndpoint}]`, NS);
|
|
1791
|
-
return this.emberSendZigDevBindRequest(target, zdo_1.BIND_REQUEST, source, sourceEndpoint, clusterId, type, destination, groupAddress, destinationEndpoint, options);
|
|
1792
|
-
}
|
|
1793
|
-
/**
|
|
1794
|
-
* ZDO
|
|
1795
|
-
* Send a request to remove a binding entry with the specified
|
|
1796
|
-
* contents from the specified node.
|
|
1797
|
-
*
|
|
1798
|
-
* @param target The node on which the binding will be removed.
|
|
1799
|
-
* @param source The source EUI64 in the binding entry.
|
|
1800
|
-
* @param sourceEndpoint uint8_t The source endpoint in the binding entry.
|
|
1801
|
-
* @param clusterId uint16_t The cluster ID in the binding entry.
|
|
1802
|
-
* @param type uint8_t The type of binding, either ::UNICAST_BINDING,
|
|
1803
|
-
* ::MULTICAST_BINDING, or ::UNICAST_MANY_TO_ONE_BINDING.
|
|
1804
|
-
* ::UNICAST_MANY_TO_ONE_BINDING is an Ember-specific extension
|
|
1805
|
-
* and should be used only when the target is an Ember device.
|
|
1806
|
-
* @param destination The destination EUI64 in the binding entry for the
|
|
1807
|
-
* ::UNICAST_BINDING or ::UNICAST_MANY_TO_ONE_BINDING.
|
|
1808
|
-
* @param groupAddress The group address for the ::MULTICAST_BINDING.
|
|
1809
|
-
* @param destinationEndpoint uint8_t The destination endpoint in the binding entry for
|
|
1810
|
-
* the ::UNICAST_BINDING or ::UNICAST_MANY_TO_ONE_BINDING.
|
|
1811
|
-
* @param options The options to use when sending the request. See
|
|
1812
|
-
* emberSendUnicast() for a description.
|
|
1813
|
-
*
|
|
1814
|
-
* @returns An ::EmberStatus value.
|
|
1815
|
-
* - ::EMBER_SUCCESS
|
|
1816
|
-
* - ::EMBER_NO_BUFFERS
|
|
1817
|
-
* - ::EMBER_NETWORK_DOWN
|
|
1818
|
-
* - ::EMBER_NETWORK_BUSY
|
|
1819
|
-
* @returns APS frame created for the request
|
|
1820
|
-
* @returns The tag used on the message.
|
|
1821
|
-
*/
|
|
1822
|
-
async emberUnbindRequest(target, source, sourceEndpoint, clusterId, type, destination, groupAddress, destinationEndpoint, options) {
|
|
1823
|
-
logger_1.logger.debug(`~~~> [ZDO UNBIND_REQUEST target=${target} source=${source} sourceEndpoint=${sourceEndpoint} clusterId=${clusterId} type=${type} `
|
|
1824
|
-
+ `destination=${destination} groupAddress=${groupAddress} destinationEndpoint=${destinationEndpoint}]`, NS);
|
|
1825
|
-
return this.emberSendZigDevBindRequest(target, zdo_1.UNBIND_REQUEST, source, sourceEndpoint, clusterId, type, destination, groupAddress, destinationEndpoint, options);
|
|
1826
|
-
}
|
|
1827
|
-
/**
|
|
1828
|
-
* ZDO
|
|
1829
|
-
* Request the specified node to send a list of its active
|
|
1830
|
-
* endpoints. An active endpoint is one for which a simple descriptor is
|
|
1831
|
-
* available.
|
|
1832
|
-
*
|
|
1833
|
-
* @param target The node whose active endpoints are desired.
|
|
1834
|
-
* @param options The options to use when sending the request. See
|
|
1835
|
-
* emberSendUnicast() for a description.
|
|
1836
|
-
*
|
|
1837
|
-
* @return An EmberStatus value. ::EMBER_SUCCESS, ::EMBER_NO_BUFFERS,
|
|
1838
|
-
* ::EMBER_NETWORK_DOWN or ::EMBER_NETWORK_BUSY.
|
|
1839
|
-
*/
|
|
1840
|
-
async emberActiveEndpointsRequest(target, options) {
|
|
1841
|
-
logger_1.logger.debug(`~~~> [ZDO ACTIVE_ENDPOINTS_REQUEST target=${target}]`, NS);
|
|
1842
|
-
return this.emberSendZigDevRequestTarget(target, zdo_1.ACTIVE_ENDPOINTS_REQUEST, options);
|
|
1843
|
-
}
|
|
1844
|
-
/**
|
|
1845
|
-
* ZDO
|
|
1846
|
-
* Request the specified node to send its power descriptor.
|
|
1847
|
-
* The power descriptor gives a dynamic indication of the power
|
|
1848
|
-
* status of the node. It describes current power mode,
|
|
1849
|
-
* available power sources, current power source and
|
|
1850
|
-
* current power source level. It is defined in the ZigBee
|
|
1851
|
-
* Application Framework Specification.
|
|
1852
|
-
*
|
|
1853
|
-
* @param target The node whose power descriptor is desired.
|
|
1854
|
-
* @param options The options to use when sending the request. See
|
|
1855
|
-
* emberSendUnicast() for a description.
|
|
1856
|
-
*
|
|
1857
|
-
* @return An EmberStatus value. ::EMBER_SUCCESS, ::EMBER_NO_BUFFERS,
|
|
1858
|
-
* ::EMBER_NETWORK_DOWN or ::EMBER_NETWORK_BUSY.
|
|
1859
|
-
*/
|
|
1860
|
-
async emberPowerDescriptorRequest(target, options) {
|
|
1861
|
-
logger_1.logger.debug(`~~~> [ZDO POWER_DESCRIPTOR_REQUEST target=${target}]`, NS);
|
|
1862
|
-
return this.emberSendZigDevRequestTarget(target, zdo_1.POWER_DESCRIPTOR_REQUEST, options);
|
|
1863
|
-
}
|
|
1864
|
-
/**
|
|
1865
|
-
* ZDO
|
|
1866
|
-
* Request the specified node to send its node descriptor.
|
|
1867
|
-
* The node descriptor contains information about the capabilities of the ZigBee
|
|
1868
|
-
* node. It describes logical type, APS flags, frequency band, MAC capabilities
|
|
1869
|
-
* flags, manufacturer code and maximum buffer size. It is defined in the ZigBee
|
|
1870
|
-
* Application Framework Specification.
|
|
1871
|
-
*
|
|
1872
|
-
* @param target The node whose node descriptor is desired.
|
|
1873
|
-
* @param options The options to use when sending the request. See
|
|
1874
|
-
* emberSendUnicast() for a description.
|
|
1875
|
-
*
|
|
1876
|
-
* @return An ::EmberStatus value. ::EMBER_SUCCESS, ::EMBER_NO_BUFFERS,
|
|
1877
|
-
* ::EMBER_NETWORK_DOWN or ::EMBER_NETWORK_BUSY.
|
|
1878
|
-
*/
|
|
1879
|
-
async emberNodeDescriptorRequest(target, options) {
|
|
1880
|
-
logger_1.logger.debug(`~~~> [ZDO NODE_DESCRIPTOR_REQUEST target=${target}]`, NS);
|
|
1881
|
-
return this.emberSendZigDevRequestTarget(target, zdo_1.NODE_DESCRIPTOR_REQUEST, options);
|
|
1882
|
-
}
|
|
1883
|
-
/**
|
|
1884
|
-
* ZDO
|
|
1885
|
-
* Request the specified node to send its LQI (neighbor) table.
|
|
1886
|
-
* The response gives PAN ID, EUI64, node ID and cost for each neighbor. The
|
|
1887
|
-
* EUI64 is only available if security is enabled. The other fields in the
|
|
1888
|
-
* response are set to zero. The response format is defined in the ZigBee Device
|
|
1889
|
-
* Profile Specification.
|
|
1890
|
-
*
|
|
1891
|
-
* @param target The node whose LQI table is desired.
|
|
1892
|
-
* @param startIndex uint8_t The index of the first neighbor to include in the
|
|
1893
|
-
* response.
|
|
1894
|
-
* @param options The options to use when sending the request. See
|
|
1895
|
-
* emberSendUnicast() for a description.
|
|
1896
|
-
*
|
|
1897
|
-
* @return An EmberStatus value. ::EMBER_SUCCESS, ::EMBER_NO_BUFFERS,
|
|
1898
|
-
* ::EMBER_NETWORK_DOWN or ::EMBER_NETWORK_BUSY.
|
|
1899
|
-
*/
|
|
1900
|
-
async emberLqiTableRequest(target, startIndex, options) {
|
|
1901
|
-
logger_1.logger.debug(`~~~> [ZDO LQI_TABLE_REQUEST target=${target} startIndex=${startIndex}]`, NS);
|
|
1902
|
-
return this.emberTableRequest(zdo_1.LQI_TABLE_REQUEST, target, startIndex, options);
|
|
1903
|
-
}
|
|
1904
|
-
/**
|
|
1905
|
-
* ZDO
|
|
1906
|
-
* Request the specified node to send its routing table.
|
|
1907
|
-
* The response gives destination node ID, status and many-to-one flags,
|
|
1908
|
-
* and the next hop node ID.
|
|
1909
|
-
* The response format is defined in the ZigBee Device
|
|
1910
|
-
* Profile Specification.
|
|
1911
|
-
*
|
|
1912
|
-
* @param target The node whose routing table is desired.
|
|
1913
|
-
* @param startIndex uint8_t The index of the first route entry to include in the
|
|
1914
|
-
* response.
|
|
1915
|
-
* @param options The options to use when sending the request. See
|
|
1916
|
-
* emberSendUnicast() for a description.
|
|
1917
|
-
*
|
|
1918
|
-
* @return An EmberStatus value. ::EMBER_SUCCESS, ::EMBER_NO_BUFFERS,
|
|
1919
|
-
* ::EMBER_NETWORK_DOWN or ::EMBER_NETWORK_BUSY.
|
|
1920
|
-
*/
|
|
1921
|
-
async emberRoutingTableRequest(target, startIndex, options) {
|
|
1922
|
-
logger_1.logger.debug(`~~~> [ZDO ROUTING_TABLE_REQUEST target=${target} startIndex=${startIndex}]`, NS);
|
|
1923
|
-
return this.emberTableRequest(zdo_1.ROUTING_TABLE_REQUEST, target, startIndex, options);
|
|
1924
|
-
}
|
|
1925
|
-
/**
|
|
1926
|
-
* ZDO
|
|
1927
|
-
* Request the specified node to send its nonvolatile bindings.
|
|
1928
|
-
* The response gives source address, source endpoint, cluster ID, destination
|
|
1929
|
-
* address and destination endpoint for each binding entry. The response format
|
|
1930
|
-
* is defined in the ZigBee Device Profile Specification.
|
|
1931
|
-
* Note that bindings that have the Ember-specific ::UNICAST_MANY_TO_ONE_BINDING
|
|
1932
|
-
* type are reported as having the standard ::UNICAST_BINDING type.
|
|
1933
|
-
*
|
|
1934
|
-
* @param target The node whose binding table is desired.
|
|
1935
|
-
* @param startIndex uint8_t The index of the first binding entry to include in the
|
|
1936
|
-
* response.
|
|
1937
|
-
* @param options The options to use when sending the request. See
|
|
1938
|
-
* emberSendUnicast() for a description.
|
|
1939
|
-
*
|
|
1940
|
-
* @return An EmberStatus value. ::EMBER_SUCCESS, ::EMBER_NO_BUFFERS,
|
|
1941
|
-
* ::EMBER_NETWORK_DOWN or ::EMBER_NETWORK_BUSY.
|
|
1942
|
-
*/
|
|
1943
|
-
async emberBindingTableRequest(target, startIndex, options) {
|
|
1944
|
-
logger_1.logger.debug(`~~~> [ZDO BINDING_TABLE_REQUEST target=${target} startIndex=${startIndex}]`, NS);
|
|
1945
|
-
return this.emberTableRequest(zdo_1.BINDING_TABLE_REQUEST, target, startIndex, options);
|
|
1946
|
-
}
|
|
1947
|
-
/**
|
|
1948
|
-
* ZDO
|
|
1949
|
-
*
|
|
1950
|
-
* @param clusterId uint16_t
|
|
1951
|
-
* @param target
|
|
1952
|
-
* @param startIndex uint8_t
|
|
1953
|
-
* @param options
|
|
1954
|
-
* @returns
|
|
1955
|
-
*/
|
|
1956
|
-
async emberTableRequest(clusterId, target, startIndex, options) {
|
|
1957
|
-
this.zdoRequestBuffalo.setPosition(zdo_1.ZDO_MESSAGE_OVERHEAD);
|
|
1958
|
-
this.zdoRequestBuffalo.writeUInt8(startIndex);
|
|
1959
|
-
return this.sendZDORequestBuffer(target, clusterId, options);
|
|
1960
|
-
}
|
|
1961
|
-
/**
|
|
1962
|
-
* ZDO
|
|
1963
|
-
* Request the specified node to remove the specified device from
|
|
1964
|
-
* the network. The device to be removed must be the node to which the request
|
|
1965
|
-
* is sent or one of its children.
|
|
1966
|
-
*
|
|
1967
|
-
* @param target The node which will remove the device.
|
|
1968
|
-
* @param deviceAddress All zeros if the target is to remove itself from
|
|
1969
|
-
* the network or the EUI64 of a child of the target device to remove
|
|
1970
|
-
* that child.
|
|
1971
|
-
* @param leaveRequestFlags uint8_t A bitmask of leave options.
|
|
1972
|
-
* Include ::AND_REJOIN if the target is to rejoin the network immediately after leaving.
|
|
1973
|
-
* @param options The options to use when sending the request. See
|
|
1974
|
-
* emberSendUnicast() for a description.
|
|
1975
|
-
*
|
|
1976
|
-
* @return An EmberStatus value. ::EMBER_SUCCESS, ::EMBER_NO_BUFFERS,
|
|
1977
|
-
* ::EMBER_NETWORK_DOWN or ::EMBER_NETWORK_BUSY.
|
|
1978
|
-
*/
|
|
1979
|
-
async emberLeaveRequest(target, deviceAddress, leaveRequestFlags, options) {
|
|
1980
|
-
this.zdoRequestBuffalo.setPosition(zdo_1.ZDO_MESSAGE_OVERHEAD);
|
|
1981
|
-
this.zdoRequestBuffalo.writeIeeeAddr(deviceAddress);
|
|
1982
|
-
this.zdoRequestBuffalo.writeUInt8(leaveRequestFlags);
|
|
1983
|
-
logger_1.logger.debug(`~~~> [ZDO LEAVE_REQUEST target=${target} deviceAddress=${deviceAddress} leaveRequestFlags=${leaveRequestFlags}]`, NS);
|
|
1984
|
-
return this.sendZDORequestBuffer(target, zdo_1.LEAVE_REQUEST, options);
|
|
1985
|
-
}
|
|
1986
|
-
/**
|
|
1987
|
-
* ZDO
|
|
1988
|
-
* Request the specified node to allow or disallow association.
|
|
1989
|
-
*
|
|
1990
|
-
* @param target The node which will allow or disallow association. The request
|
|
1991
|
-
* can be broadcast by using a broadcast address (0xFFFC/0xFFFD/0xFFFF). No
|
|
1992
|
-
* response is sent if the request is broadcast.
|
|
1993
|
-
* @param duration uint8_t A value of 0x00 disables joining. A value of 0xFF enables
|
|
1994
|
-
* joining. Any other value enables joining for that number of seconds.
|
|
1995
|
-
* @param authentication uint8_t Controls Trust Center authentication behavior.
|
|
1996
|
-
* @param options The options to use when sending the request. See
|
|
1997
|
-
* emberSendUnicast() for a description. This parameter is ignored if the target
|
|
1998
|
-
* is a broadcast address.
|
|
1999
|
-
*
|
|
2000
|
-
* @return An EmberStatus value. ::EMBER_SUCCESS, ::EMBER_NO_BUFFERS,
|
|
2001
|
-
* ::EMBER_NETWORK_DOWN or ::EMBER_NETWORK_BUSY.
|
|
2002
|
-
*/
|
|
2003
|
-
async emberPermitJoiningRequest(target, duration, authentication, options) {
|
|
2004
|
-
this.zdoRequestBuffalo.setPosition(zdo_1.ZDO_MESSAGE_OVERHEAD);
|
|
2005
|
-
this.zdoRequestBuffalo.writeUInt8(duration);
|
|
2006
|
-
this.zdoRequestBuffalo.writeUInt8(authentication);
|
|
2007
|
-
logger_1.logger.debug(`~~~> [ZDO PERMIT_JOINING_REQUEST target=${target} duration=${duration} authentication=${authentication}]`, NS);
|
|
2008
|
-
return this.sendZDORequestBuffer(target, zdo_1.PERMIT_JOINING_REQUEST, options);
|
|
2009
|
-
}
|
|
2010
|
-
/**
|
|
2011
|
-
* ZDO
|
|
2012
|
-
*
|
|
2013
|
-
* @see NWK_UPDATE_REQUEST
|
|
2014
|
-
*
|
|
2015
|
-
* @param target
|
|
2016
|
-
* @param scanChannels uint8_t[]
|
|
2017
|
-
* @param duration uint8_t
|
|
2018
|
-
* @param count uint8_t
|
|
2019
|
-
* @param manager
|
|
2020
|
-
*/
|
|
2021
|
-
async emberNetworkUpdateRequest(target, scanChannels, duration, count, manager, options) {
|
|
2022
|
-
this.zdoRequestBuffalo.setPosition(zdo_1.ZDO_MESSAGE_OVERHEAD);
|
|
2023
|
-
this.zdoRequestBuffalo.writeUInt32(scanChannels.reduce((a, c) => a + (1 << c), 0)); // to uint32_t
|
|
2024
|
-
this.zdoRequestBuffalo.writeUInt8(duration);
|
|
2025
|
-
if (count != null) {
|
|
2026
|
-
this.zdoRequestBuffalo.writeUInt8(count);
|
|
2027
|
-
}
|
|
2028
|
-
if (manager != null) {
|
|
2029
|
-
this.zdoRequestBuffalo.writeUInt16(manager);
|
|
2030
|
-
}
|
|
2031
|
-
logger_1.logger.debug(`~~~> [ZDO NWK_UPDATE_REQUEST target=${target} scanChannels=${scanChannels} duration=${duration} count=${count} manager=${manager}]`, NS);
|
|
2032
|
-
return this.sendZDORequestBuffer(target, zdo_1.NWK_UPDATE_REQUEST, options);
|
|
2033
|
-
}
|
|
2034
|
-
async emberScanChannelsRequest(target, scanChannels, duration, count, options) {
|
|
2035
|
-
return this.emberNetworkUpdateRequest(target, scanChannels, duration, count, null, options);
|
|
2036
|
-
}
|
|
2037
|
-
async emberChannelChangeRequest(target, channel, options) {
|
|
2038
|
-
return this.emberNetworkUpdateRequest(target, [channel], 0xFE, null, null, options);
|
|
2039
|
-
}
|
|
2040
|
-
async emberSetActiveChannelsAndNwkManagerIdRequest(target, scanChannels, manager, options) {
|
|
2041
|
-
return this.emberNetworkUpdateRequest(target, scanChannels, 0xFF, null, manager, options);
|
|
2042
|
-
}
|
|
2043
1386
|
//---- END Ember ZDO
|
|
2044
1387
|
//-- START Adapter implementation
|
|
2045
1388
|
static async isValidPath(path) {
|
|
@@ -2057,7 +1400,7 @@ class EmberAdapter extends __1.Adapter {
|
|
|
2057
1400
|
}
|
|
2058
1401
|
static async autoDetectPath() {
|
|
2059
1402
|
const paths = await serialPortUtils_1.default.find(autoDetectDefinitions);
|
|
2060
|
-
paths.sort((a, b) => (a < b
|
|
1403
|
+
paths.sort((a, b) => (a < b ? -1 : 1));
|
|
2061
1404
|
return paths.length > 0 ? paths[0] : null;
|
|
2062
1405
|
}
|
|
2063
1406
|
async start() {
|
|
@@ -2067,34 +1410,30 @@ class EmberAdapter extends __1.Adapter {
|
|
|
2067
1410
|
return result;
|
|
2068
1411
|
}
|
|
2069
1412
|
async stop() {
|
|
2070
|
-
this.requestQueue.stopDispatching();
|
|
2071
1413
|
await this.ezsp.stop();
|
|
2072
1414
|
this.initVariables();
|
|
2073
1415
|
logger_1.logger.info(`======== Ember Adapter Stopped ========`, NS);
|
|
2074
1416
|
}
|
|
2075
1417
|
// queued, non-InterPAN
|
|
2076
1418
|
async getCoordinator() {
|
|
2077
|
-
return
|
|
2078
|
-
this.
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
});
|
|
2096
|
-
return enums_3.EmberStatus.SUCCESS;
|
|
2097
|
-
}, 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
|
+
};
|
|
2098
1437
|
});
|
|
2099
1438
|
}
|
|
2100
1439
|
async getCoordinatorVersion() {
|
|
@@ -2103,7 +1442,7 @@ class EmberAdapter extends __1.Adapter {
|
|
|
2103
1442
|
// queued
|
|
2104
1443
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
2105
1444
|
async reset(type) {
|
|
2106
|
-
return Promise.reject(new Error(
|
|
1445
|
+
return Promise.reject(new Error('Not supported'));
|
|
2107
1446
|
// NOTE: although this function is legacy atm, a couple of new untested EZSP functions that could also prove useful:
|
|
2108
1447
|
// this.ezsp.ezspTokenFactoryReset(true/*excludeOutgoingFC*/, true/*excludeBootCounter*/);
|
|
2109
1448
|
// this.ezsp.ezspResetNode()
|
|
@@ -2114,103 +1453,86 @@ class EmberAdapter extends __1.Adapter {
|
|
|
2114
1453
|
// queued
|
|
2115
1454
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
2116
1455
|
async backup(ieeeAddressesInDatabase) {
|
|
2117
|
-
return
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
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,
|
|
2172
1511
|
},
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
key: key.key.contents,
|
|
2182
|
-
rxCounter: key.incomingFrameCounter,
|
|
2183
|
-
txCounter: key.outgoingFrameCounter,
|
|
2184
|
-
},
|
|
2185
|
-
})),
|
|
2186
|
-
ezsp: {
|
|
2187
|
-
version: this.version.ezsp,
|
|
2188
|
-
hashed_tclk: tcLinkKey.contents,
|
|
2189
|
-
// tokens: tokensBuf.toString('hex'),
|
|
2190
|
-
// altNetworkKey: altNetworkKey.contents,
|
|
2191
|
-
}
|
|
2192
|
-
});
|
|
2193
|
-
return enums_3.EmberStatus.SUCCESS;
|
|
2194
|
-
}, 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
|
+
};
|
|
2195
1520
|
});
|
|
2196
1521
|
}
|
|
2197
1522
|
// queued, non-InterPAN
|
|
2198
1523
|
async getNetworkParameters() {
|
|
2199
|
-
return
|
|
2200
|
-
this.
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
});
|
|
2212
|
-
return enums_3.EmberStatus.SUCCESS;
|
|
2213
|
-
}, 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
|
+
};
|
|
2214
1536
|
});
|
|
2215
1537
|
}
|
|
2216
1538
|
async supportsChangeChannel() {
|
|
@@ -2218,38 +1540,44 @@ class EmberAdapter extends __1.Adapter {
|
|
|
2218
1540
|
}
|
|
2219
1541
|
// queued
|
|
2220
1542
|
async changeChannel(newChannel) {
|
|
2221
|
-
return
|
|
2222
|
-
this.
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
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');
|
|
1552
|
+
});
|
|
1553
|
+
}
|
|
1554
|
+
// queued
|
|
1555
|
+
async scanChannels(networkAddress, channels, duration, count) {
|
|
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;
|
|
2235
1569
|
});
|
|
2236
1570
|
}
|
|
2237
1571
|
// queued
|
|
2238
1572
|
async setTransmitPower(value) {
|
|
2239
1573
|
if (typeof value !== 'number') {
|
|
2240
|
-
|
|
2241
|
-
return;
|
|
1574
|
+
throw new Error(`Tried to set transmit power to non-number. Value ${value} of type ${typeof value}.`);
|
|
2242
1575
|
}
|
|
2243
|
-
return
|
|
2244
|
-
this.
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
return status;
|
|
2249
|
-
}
|
|
2250
|
-
resolve();
|
|
2251
|
-
return enums_3.EmberStatus.SUCCESS;
|
|
2252
|
-
}, 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
|
+
}
|
|
2253
1581
|
});
|
|
2254
1582
|
}
|
|
2255
1583
|
// queued
|
|
@@ -2258,47 +1586,41 @@ class EmberAdapter extends __1.Adapter {
|
|
|
2258
1586
|
throw new Error(`[ADD INSTALL CODE] Failed for '${ieeeAddress}'; no code given.`);
|
|
2259
1587
|
}
|
|
2260
1588
|
// codes with CRC, check CRC before sending to NCP, otherwise let NCP handle
|
|
2261
|
-
if (
|
|
1589
|
+
if (consts_1.EMBER_INSTALL_CODE_SIZES.indexOf(key.length) !== -1) {
|
|
2262
1590
|
// Reverse the bits in a byte (uint8_t)
|
|
2263
1591
|
const reverse = (b) => {
|
|
2264
|
-
return (((b * 0x0802 & 0x22110) | (b * 0x8020 & 0x88440)) * 0x10101 >> 16) &
|
|
1592
|
+
return (((((b * 0x0802) & 0x22110) | ((b * 0x8020) & 0x88440)) * 0x10101) >> 16) & 0xff;
|
|
2265
1593
|
};
|
|
2266
|
-
let crc =
|
|
1594
|
+
let crc = 0xffff; // uint16_t
|
|
2267
1595
|
// Compute the CRC and verify that it matches.
|
|
2268
1596
|
// The bit reversals, byte swap, and ones' complement are due to differences between halCommonCrc16 and the Smart Energy version.
|
|
2269
|
-
for (let index = 0; index <
|
|
1597
|
+
for (let index = 0; index < key.length - consts_1.EMBER_INSTALL_CODE_CRC_SIZE; index++) {
|
|
2270
1598
|
crc = (0, math_1.halCommonCrc16)(reverse(key[index]), crc);
|
|
2271
1599
|
}
|
|
2272
|
-
crc =
|
|
2273
|
-
if (key[key.length -
|
|
2274
|
-
|
|
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)) {
|
|
2275
1603
|
throw new Error(`[ADD INSTALL CODE] Failed for '${ieeeAddress}'; invalid code CRC.`);
|
|
2276
1604
|
}
|
|
2277
1605
|
else {
|
|
2278
1606
|
logger_1.logger.debug(`[ADD INSTALL CODE] CRC validated for '${ieeeAddress}'.`, NS);
|
|
2279
1607
|
}
|
|
2280
1608
|
}
|
|
2281
|
-
return
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
}
|
|
2295
|
-
|
|
2296
|
-
logger_1.logger.error(`[ADD INSTALL CODE] Failed for '${ieeeAddress}' with status=${enums_3.SLStatus[impStatus]}.`, NS);
|
|
2297
|
-
return enums_3.EmberStatus.ERR_FATAL;
|
|
2298
|
-
}
|
|
2299
|
-
resolve();
|
|
2300
|
-
return enums_3.EmberStatus.SUCCESS;
|
|
2301
|
-
}, 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
|
+
}
|
|
2302
1624
|
});
|
|
2303
1625
|
}
|
|
2304
1626
|
/** WARNING: Adapter impl. Starts timer immediately upon returning */
|
|
@@ -2313,7 +1635,7 @@ class EmberAdapter extends __1.Adapter {
|
|
|
2313
1635
|
sourceEndpoint: sourceEndpointInfo.endpoint,
|
|
2314
1636
|
destinationEndpoint: endpoint,
|
|
2315
1637
|
groupId: 0,
|
|
2316
|
-
options:
|
|
1638
|
+
options: enums_1.EmberApsOption.NONE,
|
|
2317
1639
|
},
|
|
2318
1640
|
zclSequence: transactionSequenceNumber,
|
|
2319
1641
|
commandIdentifier,
|
|
@@ -2328,18 +1650,15 @@ class EmberAdapter extends __1.Adapter {
|
|
|
2328
1650
|
async permitJoin(seconds, networkAddress) {
|
|
2329
1651
|
const preJoining = async () => {
|
|
2330
1652
|
if (seconds) {
|
|
2331
|
-
const plaintextKey = { contents: Buffer.from(
|
|
2332
|
-
const impKeyStatus =
|
|
2333
|
-
if (impKeyStatus !==
|
|
2334
|
-
|
|
2335
|
-
return enums_3.EmberStatus.ERR_FATAL;
|
|
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]}.`);
|
|
2336
1657
|
}
|
|
2337
|
-
const setJPstatus =
|
|
2338
|
-
if (setJPstatus !==
|
|
2339
|
-
|
|
2340
|
-
return enums_3.EmberStatus.ERR_FATAL;
|
|
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]}.`);
|
|
2341
1661
|
}
|
|
2342
|
-
return enums_3.EmberStatus.SUCCESS;
|
|
2343
1662
|
}
|
|
2344
1663
|
else {
|
|
2345
1664
|
if (this.manufacturerCode !== DEFAULT_MANUFACTURER_CODE) {
|
|
@@ -2348,308 +1667,243 @@ class EmberAdapter extends __1.Adapter {
|
|
|
2348
1667
|
this.manufacturerCode = DEFAULT_MANUFACTURER_CODE;
|
|
2349
1668
|
}
|
|
2350
1669
|
await this.ezsp.ezspClearTransientLinkKeys();
|
|
2351
|
-
const setJPstatus =
|
|
2352
|
-
if (setJPstatus !==
|
|
2353
|
-
|
|
2354
|
-
return enums_3.EmberStatus.ERR_FATAL;
|
|
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]}.`);
|
|
2355
1673
|
}
|
|
2356
|
-
return enums_3.EmberStatus.SUCCESS;
|
|
2357
1674
|
}
|
|
2358
1675
|
};
|
|
2359
1676
|
if (networkAddress) {
|
|
2360
1677
|
// specific device that is not `Coordinator`
|
|
2361
|
-
return
|
|
2362
|
-
this.
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
}
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
}
|
|
2376
|
-
(await this.oneWaitress.startWaitingFor({
|
|
2377
|
-
target: networkAddress,
|
|
2378
|
-
apsFrame,
|
|
2379
|
-
responseClusterId: zdo_1.PERMIT_JOINING_RESPONSE,
|
|
2380
|
-
}, DEFAULT_ZDO_REQUEST_TIMEOUT));
|
|
2381
|
-
resolve();
|
|
2382
|
-
return enums_3.EmberStatus.SUCCESS;
|
|
2383
|
-
}, 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);
|
|
2384
1692
|
});
|
|
2385
1693
|
}
|
|
2386
1694
|
else {
|
|
2387
1695
|
// coordinator-only, or all
|
|
2388
|
-
return
|
|
2389
|
-
this.
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
// DEFAULT_ZCL_REQUEST_TIMEOUT,
|
|
2414
|
-
// '[ZDO] Permit Joining',
|
|
2415
|
-
// );
|
|
2416
|
-
// } else {
|
|
2417
|
-
// // NOTE: CLOSED stack status is not triggered if the network was not OPENED in the first place, so don't wait for it
|
|
2418
|
-
// // same kind of problem as described above (upstream always tries to close after start, but EZSP already is)
|
|
2419
|
-
// }
|
|
2420
|
-
resolve();
|
|
2421
|
-
return enums_3.EmberStatus.SUCCESS;
|
|
2422
|
-
}, 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
|
+
// }
|
|
2423
1721
|
});
|
|
2424
1722
|
}
|
|
2425
1723
|
}
|
|
2426
1724
|
// queued, non-InterPAN
|
|
2427
1725
|
async lqi(networkAddress) {
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
const
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
const result = (await this.oneWaitress.startWaitingFor({
|
|
2437
|
-
target: networkAddress,
|
|
2438
|
-
apsFrame,
|
|
2439
|
-
responseClusterId: zdo_1.LQI_TABLE_RESPONSE,
|
|
2440
|
-
}, DEFAULT_ZDO_REQUEST_TIMEOUT));
|
|
2441
|
-
for (const entry of result.entryList) {
|
|
2442
|
-
neighbors.push({
|
|
2443
|
-
ieeeAddr: entry.eui64,
|
|
2444
|
-
networkAddress: entry.nodeId,
|
|
2445
|
-
linkquality: entry.lqi,
|
|
2446
|
-
relationship: entry.relationship,
|
|
2447
|
-
depth: entry.depth,
|
|
2448
|
-
});
|
|
2449
|
-
}
|
|
2450
|
-
return [enums_3.EmberStatus.SUCCESS, result.neighborTableEntries, result.entryList.length];
|
|
2451
|
-
};
|
|
2452
|
-
return new Promise((resolve, reject) => {
|
|
2453
|
-
this.requestQueue.enqueue(async () => {
|
|
2454
|
-
this.checkInterpanLock();
|
|
2455
|
-
let [status, tableEntries, entryCount] = (await request(0));
|
|
2456
|
-
if (status !== enums_3.EmberStatus.SUCCESS) {
|
|
2457
|
-
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]}.`);
|
|
2458
1734
|
}
|
|
2459
|
-
const
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
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
|
+
});
|
|
2467
1748
|
}
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
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 };
|
|
2471
1759
|
});
|
|
2472
1760
|
}
|
|
2473
1761
|
// queued, non-InterPAN
|
|
2474
1762
|
async routingTable(networkAddress) {
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
const
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
const result = (await this.oneWaitress.startWaitingFor({
|
|
2484
|
-
target: networkAddress,
|
|
2485
|
-
apsFrame,
|
|
2486
|
-
responseClusterId: zdo_1.ROUTING_TABLE_RESPONSE,
|
|
2487
|
-
}, DEFAULT_ZDO_REQUEST_TIMEOUT));
|
|
2488
|
-
for (const entry of result.entryList) {
|
|
2489
|
-
table.push({
|
|
2490
|
-
destinationAddress: entry.destinationAddress,
|
|
2491
|
-
status: RoutingTableStatus[entry.status], // get str value from enum to satisfy upstream's needs
|
|
2492
|
-
nextHop: entry.nextHopAddress,
|
|
2493
|
-
});
|
|
2494
|
-
}
|
|
2495
|
-
return [enums_3.EmberStatus.SUCCESS, result.routingTableEntries, result.entryList.length];
|
|
2496
|
-
};
|
|
2497
|
-
return new Promise((resolve, reject) => {
|
|
2498
|
-
this.requestQueue.enqueue(async () => {
|
|
2499
|
-
this.checkInterpanLock();
|
|
2500
|
-
let [status, tableEntries, entryCount] = (await request(0));
|
|
2501
|
-
if (status !== enums_3.EmberStatus.SUCCESS) {
|
|
2502
|
-
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]}.`);
|
|
2503
1771
|
}
|
|
2504
|
-
const
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
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
|
+
});
|
|
2512
1783
|
}
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
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 };
|
|
2516
1794
|
});
|
|
2517
1795
|
}
|
|
2518
1796
|
// queued, non-InterPAN
|
|
2519
1797
|
async nodeDescriptor(networkAddress) {
|
|
2520
|
-
return
|
|
2521
|
-
this.
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
}
|
|
2552
|
-
resolve({ type, manufacturerCode: result.manufacturerCode });
|
|
2553
|
-
return enums_3.EmberStatus.SUCCESS;
|
|
2554
|
-
}, 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 };
|
|
2555
1829
|
});
|
|
2556
1830
|
}
|
|
2557
1831
|
// queued, non-InterPAN
|
|
2558
1832
|
async activeEndpoints(networkAddress) {
|
|
2559
|
-
return
|
|
2560
|
-
this.
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
}, DEFAULT_ZDO_REQUEST_TIMEOUT));
|
|
2573
|
-
resolve({ endpoints: result.endpointList });
|
|
2574
|
-
return enums_3.EmberStatus.SUCCESS;
|
|
2575
|
-
}, 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 };
|
|
2576
1846
|
});
|
|
2577
1847
|
}
|
|
2578
1848
|
// queued, non-InterPAN
|
|
2579
1849
|
async simpleDescriptor(networkAddress, endpointID) {
|
|
2580
|
-
return
|
|
2581
|
-
this.
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
inputClusters: result.inClusterList,
|
|
2600
|
-
outputClusters: result.outClusterList,
|
|
2601
|
-
});
|
|
2602
|
-
return enums_3.EmberStatus.SUCCESS;
|
|
2603
|
-
}, 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
|
+
};
|
|
2604
1869
|
});
|
|
2605
1870
|
}
|
|
2606
1871
|
// queued, non-InterPAN
|
|
2607
1872
|
async bind(destinationNetworkAddress, sourceIeeeAddress, sourceEndpoint, clusterID, destinationAddressOrGroup, type, destinationEndpoint) {
|
|
2608
1873
|
if (typeof destinationAddressOrGroup === 'string' && type === 'endpoint') {
|
|
2609
1874
|
// dest address is EUI64 (str), so type should always be endpoint (unicast)
|
|
2610
|
-
return
|
|
2611
|
-
this.
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
responseClusterId: zdo_1.BIND_RESPONSE,
|
|
2625
|
-
}, DEFAULT_ZDO_REQUEST_TIMEOUT);
|
|
2626
|
-
resolve();
|
|
2627
|
-
return enums_3.EmberStatus.SUCCESS;
|
|
2628
|
-
}, 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);
|
|
2629
1889
|
});
|
|
2630
1890
|
}
|
|
2631
1891
|
else if (typeof destinationAddressOrGroup === 'number' && type === 'group') {
|
|
2632
1892
|
// dest is group num, so type should always be group (multicast)
|
|
2633
|
-
return
|
|
2634
|
-
this.
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
apsFrame,
|
|
2648
|
-
responseClusterId: zdo_1.BIND_RESPONSE,
|
|
2649
|
-
}, DEFAULT_ZDO_REQUEST_TIMEOUT);
|
|
2650
|
-
resolve();
|
|
2651
|
-
return enums_3.EmberStatus.SUCCESS;
|
|
2652
|
-
}, 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);
|
|
2653
1907
|
});
|
|
2654
1908
|
}
|
|
2655
1909
|
}
|
|
@@ -2657,79 +1911,61 @@ class EmberAdapter extends __1.Adapter {
|
|
|
2657
1911
|
async unbind(destinationNetworkAddress, sourceIeeeAddress, sourceEndpoint, clusterID, destinationAddressOrGroup, type, destinationEndpoint) {
|
|
2658
1912
|
if (typeof destinationAddressOrGroup === 'string' && type === 'endpoint') {
|
|
2659
1913
|
// dest address is EUI64 (str), so type should always be endpoint (unicast)
|
|
2660
|
-
return
|
|
2661
|
-
this.
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
responseClusterId: zdo_1.UNBIND_RESPONSE,
|
|
2675
|
-
}, DEFAULT_ZDO_REQUEST_TIMEOUT);
|
|
2676
|
-
resolve();
|
|
2677
|
-
return enums_3.EmberStatus.SUCCESS;
|
|
2678
|
-
}, 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);
|
|
2679
1928
|
});
|
|
2680
1929
|
}
|
|
2681
1930
|
else if (typeof destinationAddressOrGroup === 'number' && type === 'group') {
|
|
2682
1931
|
// dest is group num, so type should always be group (multicast)
|
|
2683
|
-
return new Promise((
|
|
2684
|
-
this.requestQueue.enqueue(async () => {
|
|
2685
|
-
this.checkInterpanLock();
|
|
2686
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
2687
|
-
const [status, apsFrame, messageTag] = (await this.emberUnbindRequest(destinationNetworkAddress, sourceIeeeAddress, sourceEndpoint, clusterID, zdo_1.MULTICAST_BINDING, null, // doesn't matter
|
|
2688
|
-
destinationAddressOrGroup, destinationEndpoint, // doesn't matter
|
|
2689
|
-
DEFAULT_APS_OPTIONS));
|
|
2690
|
-
if (status !== enums_3.EmberStatus.SUCCESS) {
|
|
2691
|
-
logger_1.logger.error(`[ZDO] Failed unbind request for "${destinationNetworkAddress}" group "${destinationAddressOrGroup}" `
|
|
2692
|
-
+ `with status=${enums_3.EmberStatus[status]}.`, NS);
|
|
2693
|
-
return status;
|
|
2694
|
-
}
|
|
2695
|
-
await this.oneWaitress.startWaitingFor({
|
|
2696
|
-
target: destinationNetworkAddress,
|
|
2697
|
-
apsFrame,
|
|
2698
|
-
responseClusterId: zdo_1.UNBIND_RESPONSE,
|
|
2699
|
-
}, DEFAULT_ZDO_REQUEST_TIMEOUT);
|
|
2700
|
-
resolve();
|
|
2701
|
-
return enums_3.EmberStatus.SUCCESS;
|
|
2702
|
-
}, reject);
|
|
2703
|
-
});
|
|
2704
|
-
}
|
|
2705
|
-
}
|
|
2706
|
-
// queued, non-InterPAN
|
|
2707
|
-
async removeDevice(networkAddress, ieeeAddr) {
|
|
2708
|
-
return new Promise((resolve, reject) => {
|
|
2709
|
-
this.requestQueue.enqueue(async () => {
|
|
1932
|
+
return new Promise(async () => {
|
|
2710
1933
|
this.checkInterpanLock();
|
|
2711
|
-
//
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
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]}.`);
|
|
2717
1940
|
}
|
|
2718
1941
|
await this.oneWaitress.startWaitingFor({
|
|
2719
|
-
target:
|
|
1942
|
+
target: destinationNetworkAddress,
|
|
2720
1943
|
apsFrame,
|
|
2721
|
-
responseClusterId:
|
|
1944
|
+
responseClusterId: Zdo.ClusterId.UNBIND_RESPONSE,
|
|
2722
1945
|
}, DEFAULT_ZDO_REQUEST_TIMEOUT);
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
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);
|
|
2726
1963
|
});
|
|
2727
1964
|
}
|
|
2728
1965
|
//---- ZCL
|
|
2729
1966
|
// queued, non-InterPAN
|
|
2730
1967
|
async sendZclFrameToEndpoint(ieeeAddr, networkAddress, endpoint, zclFrame, timeout, disableResponse, disableRecovery, sourceEndpoint) {
|
|
2731
|
-
const sourceEndpointInfo = typeof sourceEndpoint === 'number' ?
|
|
2732
|
-
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];
|
|
2733
1969
|
const command = zclFrame.command;
|
|
2734
1970
|
let commandResponseId = null;
|
|
2735
1971
|
if (command.hasOwnProperty('response') && disableResponse === false) {
|
|
@@ -2742,54 +1978,65 @@ class EmberAdapter extends __1.Adapter {
|
|
|
2742
1978
|
profileId: sourceEndpointInfo.profileId,
|
|
2743
1979
|
clusterId: zclFrame.cluster.ID,
|
|
2744
1980
|
sourceEndpoint: sourceEndpointInfo.endpoint,
|
|
2745
|
-
destinationEndpoint:
|
|
1981
|
+
destinationEndpoint: typeof endpoint === 'number' ? endpoint : endpoints_1.FIXED_ENDPOINTS[0].endpoint,
|
|
2746
1982
|
options: DEFAULT_APS_OPTIONS,
|
|
2747
1983
|
groupId: 0,
|
|
2748
1984
|
sequence: 0, // set by stack
|
|
2749
1985
|
};
|
|
2750
1986
|
// don't RETRY if no response expected
|
|
2751
1987
|
if (commandResponseId == null) {
|
|
2752
|
-
apsFrame.options &= ~
|
|
1988
|
+
apsFrame.options &= ~enums_1.EmberApsOption.RETRY;
|
|
2753
1989
|
}
|
|
2754
1990
|
const data = zclFrame.toBuffer();
|
|
2755
|
-
return
|
|
2756
|
-
this.
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
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);
|
|
1999
|
+
}
|
|
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
|
+
}
|
|
2762
2008
|
}
|
|
2763
2009
|
}
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
0));
|
|
2768
|
-
if (status !== enums_3.EmberStatus.SUCCESS) {
|
|
2769
|
-
logger_1.logger.error(`~x~> [ZCL to=${networkAddress}] Failed to send request with status=${enums_3.EmberStatus[status]}.`, NS);
|
|
2770
|
-
return status; // let queue handle retry based on status
|
|
2010
|
+
// `else if` order matters
|
|
2011
|
+
if (status === enums_1.SLStatus.OK) {
|
|
2012
|
+
break;
|
|
2771
2013
|
}
|
|
2772
|
-
if (
|
|
2773
|
-
|
|
2774
|
-
const result = (await this.oneWaitress.startWaitingFor({
|
|
2775
|
-
target: networkAddress,
|
|
2776
|
-
apsFrame,
|
|
2777
|
-
zclSequence: zclFrame.header.transactionSequenceNumber,
|
|
2778
|
-
commandIdentifier: commandResponseId,
|
|
2779
|
-
}, timeout || DEFAULT_ZCL_REQUEST_TIMEOUT));
|
|
2780
|
-
resolve(result);
|
|
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]}.`);
|
|
2781
2016
|
}
|
|
2782
|
-
else {
|
|
2783
|
-
|
|
2784
|
-
return enums_3.EmberStatus.SUCCESS;
|
|
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);
|
|
2785
2019
|
}
|
|
2786
|
-
|
|
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;
|
|
2787
2035
|
});
|
|
2788
2036
|
}
|
|
2789
2037
|
// queued, non-InterPAN
|
|
2790
2038
|
async sendZclFrameToGroup(groupID, zclFrame, sourceEndpoint) {
|
|
2791
|
-
const sourceEndpointInfo = typeof sourceEndpoint === 'number' ?
|
|
2792
|
-
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];
|
|
2793
2040
|
const apsFrame = {
|
|
2794
2041
|
profileId: sourceEndpointInfo.profileId,
|
|
2795
2042
|
clusterId: zclFrame.cluster.ID,
|
|
@@ -2800,65 +2047,44 @@ class EmberAdapter extends __1.Adapter {
|
|
|
2800
2047
|
sequence: 0, // set by stack
|
|
2801
2048
|
};
|
|
2802
2049
|
const data = zclFrame.toBuffer();
|
|
2803
|
-
return
|
|
2804
|
-
this.
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
}
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
apsFrame, data, 0, // alias
|
|
2816
|
-
0));
|
|
2817
|
-
if (status !== enums_3.EmberStatus.SUCCESS) {
|
|
2818
|
-
logger_1.logger.error(`~x~> [ZCL GROUP] Failed to send with status=${enums_3.EmberStatus[status]}.`, NS);
|
|
2819
|
-
return status; // let queue handle retry based on status
|
|
2820
|
-
}
|
|
2821
|
-
// NOTE: since ezspMessageSentHandler could take a while here, we don't block, it'll just be logged if the delivery failed
|
|
2822
|
-
resolve();
|
|
2823
|
-
return enums_3.EmberStatus.SUCCESS;
|
|
2824
|
-
}, 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);
|
|
2825
2062
|
});
|
|
2826
2063
|
}
|
|
2827
2064
|
// queued, non-InterPAN
|
|
2828
2065
|
async sendZclFrameToAll(endpoint, zclFrame, sourceEndpoint, destination) {
|
|
2829
|
-
const sourceEndpointInfo = typeof sourceEndpoint === 'number' ?
|
|
2830
|
-
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];
|
|
2831
2067
|
const apsFrame = {
|
|
2832
2068
|
profileId: sourceEndpointInfo.profileId,
|
|
2833
2069
|
clusterId: zclFrame.cluster.ID,
|
|
2834
2070
|
sourceEndpoint: sourceEndpointInfo.endpoint,
|
|
2835
|
-
destinationEndpoint:
|
|
2071
|
+
destinationEndpoint: typeof endpoint === 'number' ? endpoint : endpoints_1.FIXED_ENDPOINTS[0].endpoint,
|
|
2836
2072
|
options: DEFAULT_APS_OPTIONS,
|
|
2837
2073
|
groupId: destination,
|
|
2838
2074
|
sequence: 0, // set by stack
|
|
2839
2075
|
};
|
|
2840
2076
|
const data = zclFrame.toBuffer();
|
|
2841
|
-
return
|
|
2842
|
-
this.
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
const [status, messageTag] = (await this.ezsp.send(enums_3.EmberOutgoingMessageType.BROADCAST, destination, apsFrame, data, 0, // alias
|
|
2853
|
-
0));
|
|
2854
|
-
if (status !== enums_3.EmberStatus.SUCCESS) {
|
|
2855
|
-
logger_1.logger.error(`~x~> [ZCL BROADCAST] Failed to send with status=${enums_3.EmberStatus[status]}.`, NS);
|
|
2856
|
-
return status; // let queue handle retry based on status
|
|
2857
|
-
}
|
|
2858
|
-
// NOTE: since ezspMessageSentHandler could take a while here, we don't block, it'll just be logged if the delivery failed
|
|
2859
|
-
resolve();
|
|
2860
|
-
return enums_3.EmberStatus.SUCCESS;
|
|
2861
|
-
}, 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);
|
|
2862
2088
|
});
|
|
2863
2089
|
}
|
|
2864
2090
|
//---- InterPAN for Touchlink
|
|
@@ -2870,48 +2096,38 @@ class EmberAdapter extends __1.Adapter {
|
|
|
2870
2096
|
logger_1.logger.error(`Tried to set channel InterPAN to non-number. Channel ${channel} of type ${typeof channel}.`, NS);
|
|
2871
2097
|
return;
|
|
2872
2098
|
}
|
|
2873
|
-
return
|
|
2874
|
-
this.
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
return status;
|
|
2881
|
-
}
|
|
2882
|
-
resolve();
|
|
2883
|
-
return status;
|
|
2884
|
-
}, 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
|
+
}
|
|
2885
2106
|
});
|
|
2886
2107
|
}
|
|
2887
2108
|
// queued
|
|
2888
2109
|
async sendZclFrameInterPANToIeeeAddr(zclFrame, ieeeAddress) {
|
|
2889
|
-
return
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
}
|
|
2911
|
-
// NOTE: can use ezspRawTransmitCompleteHandler if needed here
|
|
2912
|
-
resolve();
|
|
2913
|
-
return status;
|
|
2914
|
-
}, 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
|
|
2915
2131
|
});
|
|
2916
2132
|
}
|
|
2917
2133
|
// queued
|
|
@@ -2926,60 +2142,51 @@ class EmberAdapter extends __1.Adapter {
|
|
|
2926
2142
|
clusterId: zclFrame.cluster.ID,
|
|
2927
2143
|
sourceEndpoint: 0,
|
|
2928
2144
|
destinationEndpoint: 0,
|
|
2929
|
-
options:
|
|
2930
|
-
groupId:
|
|
2145
|
+
options: enums_1.EmberApsOption.NONE,
|
|
2146
|
+
groupId: ZSpec.BroadcastAddress.SLEEPY,
|
|
2931
2147
|
sequence: 0, // set by stack
|
|
2932
2148
|
};
|
|
2933
|
-
return
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
}, timeout || DEFAULT_ZCL_REQUEST_TIMEOUT * 2)); // XXX: touchlink timeout?
|
|
2963
|
-
resolve(result);
|
|
2964
|
-
return enums_3.EmberStatus.SUCCESS;
|
|
2965
|
-
}, 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;
|
|
2966
2178
|
});
|
|
2967
2179
|
}
|
|
2968
2180
|
// queued
|
|
2969
2181
|
async restoreChannelInterPAN() {
|
|
2970
|
-
return
|
|
2971
|
-
this.
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
await (0, utils_1.Wait)(3000);
|
|
2979
|
-
this.interpanLock = false;
|
|
2980
|
-
resolve();
|
|
2981
|
-
return status;
|
|
2982
|
-
}, 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;
|
|
2983
2190
|
});
|
|
2984
2191
|
}
|
|
2985
2192
|
//-- END Adapter implementation
|
|
@@ -2987,7 +2194,7 @@ class EmberAdapter extends __1.Adapter {
|
|
|
2987
2194
|
if (this.interpanLock) {
|
|
2988
2195
|
logger_1.logger.error(`[INTERPAN MODE] Cannot execute non-InterPAN commands.`, NS);
|
|
2989
2196
|
// will be caught by request queue and rejected internally.
|
|
2990
|
-
throw new
|
|
2197
|
+
throw new ezspError_1.EzspError(enums_1.EzspStatus.ERROR_INVALID_CALL);
|
|
2991
2198
|
}
|
|
2992
2199
|
}
|
|
2993
2200
|
}
|