diff --git a/lib/Af.js b/lib/Af.js index 527e8a8..2bc3d11 100644 --- a/lib/Af.js +++ b/lib/Af.js @@ -51,7 +51,10 @@ class Af extends EventEmitter { - _indirect_send */ this._controller = controller - this._seq = 0 + + // 0..250 random number to start seq with + this._seq = Math.floor(Math.random() * 250) + this.indirectTimeout = 70000 this.resendTimeout = 8100 this.maxTransactions = 250 @@ -64,7 +67,7 @@ class Af extends EventEmitter { } nextZclSeqNum() { - seqNumber += 1; // seqNumber is a private var on the top of this module + seqNumber ++; // seqNumber is a private var on the top of this module if (seqNumber >= 253 || seqNumber < 0) seqNumber = 0; @@ -112,11 +115,12 @@ class Af extends EventEmitter { if(msg.zclMsg.frameCntl.direction === 1) { // for broadcast responses only - this.emit('ZCL:incomingMsg:' + msg.dstendpoint + ':' + msg.zclMsg.seqNum, msg); + const prefix = 'ZCL:'+(frameType ? 'functional' : 'foundation')+':' + this.emit(prefix + msg.dstendpoint + ':' + msg.zclMsg.seqNum, msg); // { groupid, clusterid, srcaddr, srcendpoint, dstendpoint, wasbroadcast, linkquality, securityuse, timestamp, transseqnumber, zclMsg } - this.emit('ZCL:incomingMsg:' + msg.srcaddr.toString(16) + ':' + msg.srcendpoint + ':' + msg.dstendpoint + ':' + msg.zclMsg.seqNum, msg); - this.emit('ZCL:incomingMsg:' + msg.srcaddr.toString(16) + ':' + msg.srcendpoint + ':' + msg.zclMsg.seqNum, msg); + this.emit(prefix + msg.srcaddr.toString(16) + ':' + msg.srcendpoint + ':' + msg.dstendpoint + ':' + msg.zclMsg.seqNum, msg); + this.emit(prefix + msg.srcaddr.toString(16) + ':' + msg.srcendpoint + ':' + msg.zclMsg.seqNum, msg); } // Necessary, some IAS devices don't respect endpoints @@ -137,7 +141,7 @@ class Af extends EventEmitter { } } - if (typeof dispatchTo == "function") { + if (dispatchTo) { dispatchTo.call(targetEp, msg, remoteEp); } @@ -281,7 +285,7 @@ class Af extends EventEmitter { try { let areqCancelable = areqC() - const startAreq = async () => { + const startAreq = async (attempt) => { let cnf do { @@ -292,6 +296,13 @@ class Af extends EventEmitter { if (cnf.status === 0 || cnf.status === 'SUCCESS') { // success this.emit('ind:dataConfirm', { dstEp, afParams }); return cnf + } else if(cnf.status == 205) { // ZNwkNoRoute + await controller.request('NWK', 'rtg', { nwkaddr: dstAddr }) + await Q.delay(((Math.random()/4) + 0.75) * 16000) + await controller.request('NWK', 'rtg', { nwkaddr: dstAddr }) + if(attempt > 1) { + shouldResend = false + } } if (shouldResend) { @@ -367,9 +378,8 @@ class Af extends EventEmitter { areqCancelable._cancels.delete(wf) await Q.delay((Math.random() + 0.5) * 16000) continue - } else { - throw ex } + throw ex } wf.then(areqCancelable.resolve, areqCancelable.reject) break @@ -379,10 +389,10 @@ class Af extends EventEmitter { isResend = true } - const indirectSendFn = async () => { + const indirectSendFn = async (attempt) => { try { await afSend() - return await startAreq() + return await startAreq(attempt) } catch (ex) { areqCancelable.cancel() throw ex @@ -436,6 +446,8 @@ class Af extends EventEmitter { // .frame(frameCntl, manufCode, seqNum, cmd, zclPayload[, clusterId]) seqNum = cfg.seqNum !== undefined ? cfg.seqNum : this.nextZclSeqNum(); + + if(dstEp._logger) dstEp._logger(`zclFoundation(${cmd}:${seqNum}) ${JSON.stringify(zclData)}`) zclBuffer = zcl.frame(frameCntl, manufCode, seqNum, cmd, zclData); @@ -444,9 +456,9 @@ class Af extends EventEmitter { const nwkAddr = dstEp.nwkAddr assert(typeof nwkAddr === 'number') if (srcEp === dstEp) // from remote to remote itself - mandatoryEvent = 'ZCL:incomingMsg:' + nwkAddr.toString(16) + ':' + dstEp.getEpId() + ':' + seqNum; + mandatoryEvent = 'ZCL:foundation:' + nwkAddr.toString(16) + ':' + dstEp.getEpId() + ':' + seqNum; else // from local ep to remote ep - mandatoryEvent = 'ZCL:incomingMsg:' + nwkAddr.toString(16) + ':' + dstEp.getEpId() + ':' + srcEp.getEpId() + ':' + seqNum; + mandatoryEvent = 'ZCL:foundation:' + nwkAddr.toString(16) + ':' + dstEp.getEpId() + ':' + srcEp.getEpId() + ':' + seqNum; areq = this.waitFor(mandatoryEvent, AreqTimeout) } @@ -526,15 +538,17 @@ class Af extends EventEmitter { // .frame(frameCntl, manufCode, seqNum, cmd, zclPayload[, clusterId]) seqNum = cfg.seqNum !== undefined ? cfg.seqNum : this.nextZclSeqNum(); + + if(dstEp._logger) dstEp._logger(`zclFunctional(${cmd}:${seqNum}) ${JSON.stringify(zclData)}`) zclBuffer = zcl.frame(frameCntl, manufCode, seqNum, cmd, zclData, cId); if (frameCntl.direction === 0 && !cfg.response) { // client-to-server, thus require getting the feedback response if (srcEp === dstEp) // from remote to remote itself - mandatoryEvent = 'ZCL:incomingMsg:' + dstEp.nwkAddr.toString(16) + ':' + dstEp.getEpId() + ':' + seqNum; + mandatoryEvent = 'ZCL:functional:' + dstEp.nwkAddr.toString(16) + ':' + dstEp.getEpId() + ':' + seqNum; else // from local ep to remote ep - mandatoryEvent = 'ZCL:incomingMsg:' + dstEp.nwkAddr.toString(16) + ':' + dstEp.getEpId() + ':' + srcEp.getEpId() + ':' + seqNum; + mandatoryEvent = 'ZCL:functional:' + dstEp.nwkAddr.toString(16) + ':' + dstEp.getEpId() + ':' + srcEp.getEpId() + ':' + seqNum; areq = this.waitFor(mandatoryEvent, AreqTimeout) diff --git a/lib/AfController.js b/lib/AfController.js index 1d41d4c..27c42a5 100644 --- a/lib/AfController.js +++ b/lib/AfController.js @@ -81,7 +81,7 @@ class AfController extends EventEmitter { debug(`Doing indirect send attempt ${i}/${retries}`) } - workPromise = sendFn() + workPromise = sendFn(i) // It's a race for who can return first const promises = [Q.delay(cfg.indirectTimeout), workPromise] @@ -100,6 +100,7 @@ class AfController extends EventEmitter { await Q.cancelledRace([Q.delay(5000), workPromise]) // Wait at-least 5 seconds after a module error } else if(typeof result === 'number') { + // network status code if(result != 6 && i != retries) { const waitTime = 3500 - (Date.now() - attemptStart) if(waitTime > 0) await await Q.cancelledRace([Q.delay(waitTime), workPromise])