From 7da1ae081c500b2501461cd39db64a9e41779e90 Mon Sep 17 00:00:00 2001 From: MyHomeMyData Date: Sun, 17 Dec 2023 23:33:41 +0100 Subject: [PATCH] More improvemets for Collecting. Introduced comm. statistics. --- .gitignore | 1 + lib/callback.js | 6 +- lib/canCollect.js | 201 +++++++++++++++++++++++++++++++++++----------- lib/canUds.js | 86 ++++++++++++-------- lib/storage.js | 53 +++++++++--- main.js | 50 ++++++------ 6 files changed, 281 insertions(+), 116 deletions(-) diff --git a/.gitignore b/.gitignore index bc63cc6..6695f30 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ admin/i18n/*/flat.txt admin/jsonConfigDemo.json5 admin/jsonConfig.testTab.json README.org.md +todo.md diff --git a/lib/callback.js b/lib/callback.js index 760d7e9..36eded2 100644 --- a/lib/callback.js +++ b/lib/callback.js @@ -62,7 +62,7 @@ class udsCallback { } break; case 'timeout': - if (ctxAgent.cntCommTimeout < ctx.udsMaxTrialsDevScan) { + if (ctxAgent.stat.cntCommTimeout < ctx.udsMaxTrialsDevScan) { await ctxAgent.pushCmnd(ctx, 'read', [ctx.udsDidForScan]); ctx.udsScanDidsCntRetries += 1; } @@ -98,8 +98,8 @@ class udsCallback { case 'did mismatch MF': case 'bad frame': if (response == 'timeout') { - //ctx.log.debug('UDS did scan: Timeout on '+String(ctxAgent.canIDhex)+'.'+String(ctxAgent.data.did)+' cnt: '+String(ctxAgent.cntCommTimeoutPerDid[ctxAgent.data.did])); - if (ctxAgent.cntCommTimeoutPerDid[ctxAgent.data.did] < ctx.udsMaxTrialsDidScan) { + //ctx.log.debug('UDS did scan: Timeout on '+String(ctxAgent.canIDhex)+'.'+String(ctxAgent.data.did)+' cnt: '+String(ctxAgent.stat.cntCommTimeoutPerDid[ctxAgent.data.did])); + if (ctxAgent.stat.cntCommTimeoutPerDid[ctxAgent.data.did] < ctx.udsMaxTrialsDidScan) { ctxAgent.pushCmnd(ctx, 'read', [ctxAgent.data.did]); ctx.udsScanDidsCntRetries += 1; } diff --git a/lib/canCollect.js b/lib/canCollect.js index 8e775c7..237c48d 100644 --- a/lib/canCollect.js +++ b/lib/canCollect.js @@ -1,88 +1,195 @@ - -const storageCol = require('./storage'); +const storage = require('./storage'); class collect { constructor(config) { this.config = config; - this.storage = new storageCol.storage(this.config); + this.config.statName = 'statCollect'; + this.storage = new storage.storage(this.config); this.ts = {}; - this.didwatch = 7777; + this.msDelay = config.delay*1000; + this.timeoutHandle = null; + this.maxDid = 3500; + this.commBusy = false; // Communication routine running this.data = { 'len' : 0, 'timestamp' : 0, 'databytes' : [], 'did' : 0, 'collecting': false, - 'D0' : 0x21 + 'D0expected': 0x21 + }; + this.stat = { + cntCommTotal : 0, // Number collected dids + cntCommOk : 0, // Number of ok + cntCommStored : 0, // Number of dids stored + cntCommTimeout : 0, // Number of timeouts + cntCommBadProt : 0, // Number of bad communications + cntTooBusy : 0, // Number of conflicting calls of msgCollect() }; } async initStates(ctx) { await this.storage.initStates(ctx); + await this.storage.storeStatistics(ctx, this); + } + + async onTimeout(ctxGlobal, ctxLocal) { + ctxGlobal.log.error('Collect timeout on 0x'+Number(ctxLocal.config.canID[0]).toString(16)+'.'+String(ctxLocal.data.did)); + ctxLocal.stat.cntCommTimeout += 1; + ctxLocal.data.collecting = false; + } + + async startup(ctx) { + await this.storage.storeStatistics(ctx, this); + this.data.collecting = false; await this.storage.setOpMode('normal'); + await ctx.log.debug('Collect agent started on '+this.config.stateBase); + } + + async stop(ctx) { + // Stop Timeout: + if (this.timeoutHandle) await clearTimeout(this.timeoutHandle); + this.timeoutHandle = null; + + // Wait till possibly running communication has finished: + const tsAbort = await new Date().getTime() + this.config.timeout; + while ( (this.commBusy) && (new Date().getTime() < tsAbort) ) { + await this.sleep(50); + } + + await this.storage.storeStatistics(ctx, this); + + // Stop agent: + this.data.collecting = false; + await this.storage.setOpMode('standby'); + await ctx.log.debug('Collect agent stopped on '+this.config.stateBase); + } + + sleep(milliseconds) { + return new Promise(resolve => setTimeout(resolve, milliseconds)); } async msgCollect(ctx, msg) { + + if (this.commBusy) { + this.stat.cntTooBusy += 1; + if (this.stat.cntTooBusy == 1) ctx.log.warn('Collect: Evaluation of messages overloaded on '+String(this.config.stateBase)); + return; + } + + this.commBusy = true; const candata = msg.data.toJSON().data; + const canid = msg.id; + const msgDlc = candata.length; const tsNow = new Date().getTime(); - if (this.config.device == 'e380') { - if (!(canid in this.ts)) { this.ts[canid] = 0; } - if ( (this.config.delay > 0) && ((tsNow-this.ts[canid]) < this.config.delay*1000) ) { return; } - this.storage.decodeDataCAN(ctx,msg.id,candata); - this.ts[canid] = tsNow; + // Energy meter + this.stat.cntCommTotal += 1; + this.stat.cntCommOk += 1; + if (!(canid in this.ts)) { this.ts[canid] = tsNow; } + if ( (this.config.delay == 0) || ((tsNow >= this.ts[canid])) ) { + this.stat.cntCommStored += 1; + this.storage.decodeDataCAN(ctx,this,msg.id,candata); + this.ts[canid] = tsNow+this.msDelay; + } } else { - //ctx.log.debug(JSON.stringify(candata)); + // E3 device + //await ctx.log.debug(this.storage.arr2Hex(candata)); if (this.data.collecting) { - this.data.D0 += 1; - if (this.data.D0 > 0x2f) { - this.data.D0 = 0x20; - } - if (candata[0] == this.data.D0) { + if (candata[0] == this.data.D0expected) { // append next part of data this.data.databytes = this.data.databytes.concat(candata.slice(1)); - if (this.data.did == this.didwatch) { ctx.log.debug('D0='+String(this.data.D0)+'; candata='+JSON.stringify(this.data.databytes)); } - } else { - // no more data - if ((this.config.dids == null) || (this.data.did in this.config.dids) ) { - if (this.data.did == this.didwatch) { - ctx.log.debug(JSON.stringify(this.data)); + if (this.data.databytes.length >= this.data.len) { + // All data received + if (this.timeoutHandle) await clearTimeout(this.timeoutHandle); + //await ctx.log.debug('Done did MF '+String(this.data.did)); + this.stat.cntCommOk += 1; + if (!(this.data.did in this.ts)) { this.ts[this.data.did] = tsNow; } + if ( (this.config.delay == 0) || ((tsNow >= this.ts[this.data.did])) ) { + this.stat.cntCommStored += 1; + this.storage.decodeDataCAN(ctx, this, this.data.did, this.data.databytes.slice(0,this.data.len)); + this.ts[this.data.did] = tsNow+this.msDelay; } this.data.collecting = false; - await this.storage.decodeDataCAN(ctx, this.data.did, this.data.databytes.slice(0,this.data.len)); - this.ts[this.data.did] = tsNow; + } else { + // More data to come + //await ctx.log.debug('Ongoing did MF '+String(this.data.did)+' len '+String(this.data.databytes.length)); + this.data.D0expected += 1; + if (this.data.D0expected > 0x2f) { + this.data.D0expected = 0x20; + } } } } - if ( (!this.data.collecting) && (candata.length > 4) && (candata[0] == 0x21) && (candata[3] >= 0xb0) && (candata[3] < 0xc0)) { - this.data.D0 = candata[0]; - const D3 = candata[3]; - if (D3 == 0xb0) { - this.data.len = candata[4]; - if (candata[5]==0xb5) { - this.data.databytes = candata.slice(6); - } else { - this.data.databytes = candata.slice(5); - } - } else { - this.data.len = D3-0xb0; - this.data.databytes = candata.slice(4); - } + const D3 = candata[3]; + if ( (!this.data.collecting) && (msgDlc > 4) && (candata[0] == 0x21) && (D3 >= 0xb0) && (D3 < 0xc0)) { + this.data.D0expected = candata[0]; this.data.did = candata[1]+256*candata[2]; - if (this.data.did == this.didwatch) { - ctx.log.debug('Start did '+String(this.didwatch)); - ctx.log.debug(JSON.stringify(this.data)); - } - if ( (this.data.did > 0) && (this.data.did < 10000) ) { - if (!(this.data.did in this.ts)) { this.ts[this.data.did] = 0; } - if ( (this.config.delay > 0) && ((tsNow-this.ts[this.data.did]) < this.config.delay*1000) ) { return; } - this.data.timestamp = msg.ts_sec*1000+Math.round(msg.ts_usec/1000); - this.data.collecting = true; + this.data.timestamp = msg.ts_sec*1000+Math.round(msg.ts_usec/1000); + if ( (this.data.did > 0) && (this.data.did < this.maxDid) ) { + switch (D3) { + case 0xb1: + case 0xb2: + case 0xb3: + case 0xb4: + // Single Frame B1,B2,B3,B4 + this.data.len = D3-0xb0; + //await ctx.log.debug('Start did B1..B4 '+String(this.data.did)+String(this.data.len)); + this.data.databytes = candata.slice(4); + this.stat.cntCommTotal += 1; + this.stat.cntCommOk += 1; + if (!(this.data.did in this.ts)) { this.ts[this.data.did] = tsNow; } + if ( (this.config.delay == 0) || ((tsNow >= this.ts[this.data.did])) ) { + this.stat.cntCommStored += 1; + this.storage.decodeDataCAN(ctx, this, this.data.did, this.data.databytes.slice(0,this.data.len)); + this.ts[this.data.did] = tsNow+this.msDelay; + } + //await ctx.log.debug('Done did B1..B4 '+String(this.data.did)); + break; + case 0xb0: + // Multi Frame B0 + this.data.D0expected = candata[0]+1; + this.stat.cntCommTotal += 1; + if (candata[4]==0xc1) { + this.data.databytes = candata.slice(6); + this.data.len = candata[5]; + //await ctx.log.debug('Start did B0..B5 '+String(this.data.did)+' len '+String(this.data.len)); + } else { + this.data.databytes = candata.slice(5); + this.data.len = candata[4]; + //await ctx.log.debug('Start did B0 '+String(this.data.did)+String(this.data.len)); + } + this.timeoutHandle = setTimeout(this.onTimeout, this.config.timeout, ctx, this); + this.data.collecting = true; + break; + case 0xb6: + case 0xb7: + case 0xb8: + case 0xb9: + case 0xba: + case 0xbb: + case 0xbc: + case 0xbd: + case 0xbe: + case 0xbf: + // Multi Frame B6 .. BF + this.stat.cntCommTotal += 1; + this.data.D0expected = candata[0]+1; + this.data.databytes = candata.slice(4); + this.data.len = D3-0xb0; + this.timeoutHandle = setTimeout(this.onTimeout, this.config.timeout, ctx, this); + //await ctx.log.debug('Start did B6B7 '+String(this.data.did)+String(this.data.len)); + this.data.collecting = true; + break; + default: + ctx.log.debug('Collect: D3=0x'+Number(D3).toString(16)); + } } } } + this.commBusy = false; } } diff --git a/lib/canUds.js b/lib/canUds.js index cba1049..9e81f7c 100644 --- a/lib/canUds.js +++ b/lib/canUds.js @@ -1,4 +1,4 @@ -const storageCol = require('./storage'); +const storage = require('./storage'); class scheduleLoop { constructor(ctxGlobal, ctxLocal, schedule, dids) { @@ -35,7 +35,8 @@ class scheduleLoop { class uds { constructor(config) { this.config = config; - this.storage = new storageCol.storage(this.config); + this.config.statName = 'statUDS'; + this.storage = new storage.storage(this.config); this.states = ['standby','waitForFF','waitForCF']; this.frameFC = [0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00]; this.readByDidProt = { @@ -60,17 +61,21 @@ class uds { this.cmndsHandle = null; this.cmndsUpdateTime = 50; // Check for new commands (ms) this.busy = false; // Agent is busy + this.commBusy = false; // Communication routine running this.schedules = {}; this.userDidsToReadId = this.config.stateBase+'.udsDidsToRead'; this.timeoutHandle = null; this.callback = null; this.coolDownTs = 0; // Earliest time for next communication - this.cntCommTotal = 0; // Number of startes communications - this.cntCommOk = 0; // Number of succesfull communications - this.cntCommNR = 0; // Number of communications ending in negative response - this.cntCommTimeout = 0; // Number of communications ending in timeout - this.cntCommTimeoutPerDid = {}; // Number of communications ending in timeout for specific did - this.cntCommBad = 0; // Number of bad communications, e.g. bad frame + this.stat = { + cntCommTotal : 0, // Number of startes communications + cntCommOk : 0, // Number of succesfull communications + cntCommNR : 0, // Number of communications ending in negative response + cntCommTimeout : 0, // Number of communications ending in timeout + cntCommTimeoutPerDid: {}, // Number of communications ending in timeout for specific did + cntCommBadProtocol : 0, // Number of bad communications, e.g. bad frame + cntTooBusy : 0 // Number of conflicting calls of msgUds() + }; } async initStates(ctx) { @@ -87,6 +92,7 @@ class uds { native: {}, }); await ctx.setStateAsync(this.userDidsToReadId, { val: JSON.stringify([]), ack: true }); + await this.storage.storeStatistics(ctx, this); } async setAgentOpMode(opMode) { @@ -124,6 +130,7 @@ class uds { async startup(ctx, opMode) { await this.setComState(0); + await this.storage.storeStatistics(ctx, this); this.cmndsHandle = setInterval(async () => { await this.cmndsLoop(ctx); }, this.cmndsUpdateTime); @@ -150,12 +157,18 @@ class uds { } if (this.cmndsHandle) await clearInterval(this.cmndsHandle); + // Stop Timeout: + if (this.timeoutHandle) await clearTimeout(this.timeoutHandle); + this.timeoutHandle = null; + // Wait till possibly running communication has finished: const tsAbort = await new Date().getTime() + this.config.timeout; while ( (this.busy) && (new Date().getTime() < tsAbort) ) { await this.sleep(50); } + await this.storage.storeStatistics(ctx, this); + // Stop agent: const opMode = await this.storage.getOpMode(); this.callback = null; @@ -224,15 +237,14 @@ class uds { if ( (opMode != 'udsDevScan') && ((opMode != 'udsDidScan')) ) { await ctxGlobal.log.error('UDS timeout on '+ctxLocal.canIDhex+'.'+String(ctxLocal.data.did)); } - ctxLocal.cntCommTimeout += 1; + ctxLocal.stat.cntCommTimeout += 1; const did = await Number(ctxLocal.data.did); - if (did in ctxLocal.cntCommTimeoutPerDid) { - ctxLocal.cntCommTimeoutPerDid[did] += 1; + if (did in ctxLocal.stat.cntCommTimeoutPerDid) { + ctxLocal.stat.cntCommTimeoutPerDid[did] += 1; } else { - ctxLocal.cntCommTimeoutPerDid[did] = 1; + ctxLocal.stat.cntCommTimeoutPerDid[did] = 1; } if (ctxLocal.callback) await ctxLocal.callback(ctxGlobal, ctxLocal, ['timeout', ctxLocal.storage.udsScanResult]); - //ctxGlobal.log.debug('Timeout: '+String(ctxLocal.canIDhex)+'.'+String(ctxLocal.data.did)); await ctxLocal.setDidDone(0); } @@ -269,7 +281,7 @@ class uds { await this.pushCmnd(ctx, 'read', [did]); return; } - this.cntCommTotal += 1; + this.stat.cntCommTotal += 1; await this.setDidStart(ctx, did); await this.sendFrame(ctx, await this.initialRequestSF(did)); await ctx.log.silly('ReadByDid(): '+String(this.canIDhex)+'.'+String(did)); @@ -280,21 +292,30 @@ class uds { } async msgUds(ctx, msg) { + if (await this.storage.getOpMode() == 'standby') return; // No communication in mode 'standby' + if (this.commBusy) { + this.stat.cntTooBusy += 1; + if (this.stat.cntTooBusy == 1) ctx.log.warn('UDS: Evaluation of messages overloaded on '+String(this.canIDhex)); + return; + } + + this.commBusy = true; + const candata = msg.data.toJSON().data; switch (await this.getComState()) { case 0: // standby - return; + break; case 1: // waitForFF if ( (candata[0] == 0x03) && (candata[1] == 0x7F) && (candata[2] == this.readByDidProt.SIDtx) ) { // Negative response - this.cntCommNR += 1; + this.stat.cntCommNR += 1; if (this.callback) { await this.callback(ctx, this, ['negative response', this.storage.udsScanResult]); } else { - await ctx.log.error('msgUds(): Negative response on device '+this.canIDhex+'. Code=0x'+Number(candata[3]).toString(16)); + ctx.log.error('msgUds(): Negative response on device '+this.canIDhex+'. Code=0x'+Number(candata[3]).toString(16)); } await this.setDidDone(100); break; @@ -304,21 +325,21 @@ class uds { const didRx = candata[3]+256*candata[2]; if (didRx == this.data.did) { // Did does match - this.cntCommOk += 1; - await ctx.log.silly('msgUds SF: '+this.canIDhex+' '+JSON.stringify(candata)); + this.stat.cntCommOk += 1; + ctx.log.silly('msgUds SF: '+this.canIDhex+' '+JSON.stringify(candata)); this.data.len = candata[0]-3; this.data.databytes = candata.slice(4,4+this.data.len); - await this.storage.decodeDataCAN(ctx, this.data.did, this.data.databytes.slice(0,this.data.len)); + this.storage.decodeDataCAN(ctx, this, this.data.did, this.data.databytes.slice(0,this.data.len)); if (this.callback) await this.callback(ctx, this, ['ok', this.storage.udsScanResult]); await this.setDidDone(0); break; } else { // Did does not match - this.cntCommBad += 1; + this.stat.cntCommBad += 1; if (this.callback) { await this.callback(ctx, this, ['did mismatch SF', this.storage.udsScanResult]); } else { - await ctx.log.error('msgUds(): Did mismatch SF on device '+this.canIDhex); + ctx.log.error('msgUds(): Did mismatch SF on device '+this.canIDhex); } await this.setDidDone(1000); break; @@ -330,19 +351,19 @@ class uds { if (didRx == this.data.did) { // Did does match this.data.len = (candata[0] & 0x0F)*256 + candata[1] - 3; - await ctx.log.silly('msgUds FF: data.len='+String(this.data.len)); + ctx.log.silly('msgUds FF: data.len='+String(this.data.len)); this.data.databytes = candata.slice(5); this.data.D0 = 0x21; - await this.sendFrame(ctx, this.frameFC); // Send request for Consecutive Frames + this.sendFrame(ctx, this.frameFC); // Send request for Consecutive Frames await this.setComState(2); // 'waitForCF' break; } else { // Did does not match - this.cntCommBad += 1; + this.stat.cntCommBad += 1; if (this.callback) { await this.callback(ctx, this, ['did mismatch MF', this.storage.udsScanResult]); } else { - await ctx.log.error('msgUds(): Did mismatch MF on device '+this.canIDhex+'. Expected='+String(this.data.did)+'; Received='+String(didRx)); + ctx.log.error('msgUds(): Did mismatch MF on device '+this.canIDhex+'. Expected='+String(this.data.did)+'; Received='+String(didRx)); } await this.setDidDone(1000); break; @@ -351,9 +372,9 @@ class uds { if (this.callback) { await this.callback(ctx, this, ['bad frame', this.storage.udsScanResult]); } else { - await ctx.log.error('msgUds(): Bad frame on device '+this.canIDhex+': '+JSON.stringify(candata)); + ctx.log.error('msgUds(): Bad frame on device '+this.canIDhex+': '+JSON.stringify(candata)); } - this.cntCommBad += 1; + this.stat.cntCommBad += 1; await this.setDidDone(2500); break; @@ -364,9 +385,9 @@ class uds { this.data.databytes = this.data.databytes.concat(candata.slice(1)); if (this.data.databytes.length >= this.data.len) { // All data received - this.cntCommOk += 1; - await ctx.log.silly('msgUds multi frame completed: '+this.canIDhex+' '+JSON.stringify(this.data)); - await this.storage.decodeDataCAN(ctx, this.data.did, this.data.databytes.slice(0,this.data.len)); + this.stat.cntCommOk += 1; + ctx.log.silly('msgUds multi frame completed: '+this.canIDhex+' '+JSON.stringify(this.data)); + this.storage.decodeDataCAN(ctx, this, this.data.did, this.data.databytes.slice(0,this.data.len)); if (this.callback) await this.callback(ctx, this, ['ok', this.storage.udsScanResult]); await this.setDidDone(0); } else { @@ -380,7 +401,7 @@ class uds { break; default: - this.cntCommBad += 1; + this.stat.cntCommBad += 1; if (this.callback) { this.callback(ctx, this, ['bad state value', this.storage.udsScanResult]); } else { @@ -388,6 +409,7 @@ class uds { } await this.setDidDone(2500); } + this.commBusy = false; } } diff --git a/lib/storage.js b/lib/storage.js index b502f54..74e18f1 100644 --- a/lib/storage.js +++ b/lib/storage.js @@ -9,6 +9,28 @@ class storage { this.udsScanResult = null; } async initStates(ctx) { + await ctx.setObjectNotExistsAsync(this.config.stateBase+'.info', { + type: 'channel', + common: { + name: this.config.stateBase+' informations', + role: 'device' + }, + native: {}, + }); + + await ctx.setObjectNotExistsAsync(this.config.stateBase+'.info.'+this.config.statName, { + type: 'state', + common: { + name: this.config.stateBase+' statistics about communication', + role: 'state', + type: 'json', + read: true, + write: true, + def: JSON.stringify({}) + }, + native: {}, + }); + await ctx.setObjectNotExistsAsync(this.config.stateBase+'.json', { type: 'channel', common: { @@ -59,6 +81,10 @@ class storage { return hs; } + async storeStatistics(ctx, ctxAgent) { + if (ctxAgent.stat) await ctx.setStateAsync(ctxAgent.config.stateBase+'.info.'+this.config.statName, JSON.stringify(ctxAgent.stat), true); + } + async storeKnownDids(ctx, dids) { const stateId = this.config.stateBase+'.dids'; await ctx.setObjectNotExistsAsync(stateId, { @@ -75,7 +101,7 @@ class storage { await ctx.setStateAsync(stateId, JSON.stringify(dids), true); } - async decodeDataCAN(ctx, did, data) { + async decodeDataCAN(ctx, ctxAgent, did, data) { async function storeObjectJson(ctx, stateId, obj) { try { await ctx.setObjectNotExistsAsync(stateId, { @@ -93,22 +119,28 @@ class storage { await ctx.setStateAsync(stateId, JSON.stringify(obj), true); } catch(e) { - ctx.log.error('UDS storage of did @'+stateId+'.'+String(did)+' failed: '+JSON.stringify(e)); + ctx.log.error('Storage of did '+stateId+'.'+String(did)+' failed: '+JSON.stringify(e)); } } async function storeObjectTree(ctx, stateId, obj) { - if (typeof(obj) == 'object') { - if (Object.keys(obj).length <= 100) { - for (const [key, itm] of Object.entries(obj)) { - await storeObjectTree(ctx, String(stateId)+'.'+String(key),itm); + try { + if (typeof(obj) == 'object') { + if (Object.keys(obj).length <= 100) { + for (const [key, itm] of Object.entries(obj)) { + await storeObjectTree(ctx, String(stateId)+'.'+String(key),itm); + } + } else { + ctx.log.error('Did valuation aborted. Too many members ('+String(Object.keys(obj).length)+') '+stateId+'.'+String(did)); } } else { - ctx.log.error('UDS did valuation aborted. Too many members ('+String(Object.keys(obj).length)+') '+stateId+'.'+String(did)); + await storeObjectJson(ctx, stateId, obj); } - } else { - await storeObjectJson(ctx, stateId, obj); + } + catch(e) { + ctx.log.error('Storage of did '+stateId+'.'+String(did)+' failed: '+JSON.stringify(e)); } } + if (this.opMode == this.opModes[0]) { return; } const raw = this.arr2Hex(data); let idStr, val; @@ -119,7 +151,7 @@ class storage { } catch(e) { val = raw; - ctx.log.warn('UDS codec failed: '+this.config.canIDhex+'.'+String(did)); + ctx.log.warn('Codec failed: '+this.config.canIDhex+'.'+String(did)); } } else { @@ -161,6 +193,7 @@ class storage { await storeObjectTree(ctx, stateIdTree, val); await storeObjectJson(ctx, stateIdJson, val); await storeObjectJson(ctx, stateIdRaw, raw); + if (ctxAgent.stat) await ctx.setStateAsync(ctxAgent.config.stateBase+'.info.'+this.config.statName, JSON.stringify(ctxAgent.stat), true); break; default: ctx.log.error('Invalid opMode at class storage. Change to "standby"'); diff --git a/main.js b/main.js index c292f85..0705f60 100644 --- a/main.js +++ b/main.js @@ -30,11 +30,12 @@ class E3oncan extends utils.Adapter { this.udsScanTEST = true; - this.e380Collect = null; // E380 alway is assigned to external bus - this.E3CollectInt = {}; // Dict of collect devices on internal bus - this.E3CollectExt = {}; // Dict of collect devices on external bus - this.E3UdsAgents = {}; // Dict of uds devices on external bus - this.udsScanAgents = {}; // Dict for uds scan agents + this.e380Collect = null; // E380 alway is assigned to external bus + this.E3CollectInt = {}; // Dict of collect devices on internal bus + this.E3CollectExt = {}; // Dict of collect devices on external bus + this.collectTimeout = 1500; // Timeout (ms) for collecting data + this.E3UdsAgents = {}; // Dict of uds devices on external bus + this.udsScanAgents = {}; // Dict for uds scan agents this.udsCntNewDevs = 0; // New devices found during scan this.channelExt = null; @@ -233,37 +234,37 @@ class E3oncan extends utils.Adapter { e380Agent = new collect.collect( { 'canID': [0x250,0x252,0x254,0x256,0x258,0x25A,0x25C], 'stateBase': conf.e380Name, - 'device': conf.e380Name, + 'device': 'e380', 'delay': conf.e380Delay, 'active': conf.e380Active}); await e380Agent.initStates(this); } + if (e380Agent) await e380Agent.startup(this); return e380Agent; } // Setup E3 collect agents: - async setupE3CollectAgents(conf, agents, channel) { + async setupE3CollectAgents(conf, agents) { if ( (conf) && (conf.length > 0) ) { - for (const agent of Object.values(conf)) { - if (agent.collectActive) { - const devInfo = this.config.tableUdsDevices.filter(item => item.collectCanId == agent.collectCanId); + for (const agentConf of Object.values(conf)) { + if (agentConf.collectActive) { + const devInfo = this.config.tableUdsDevices.filter(item => item.collectCanId == agentConf.collectCanId); if (devInfo.length > 0) { - const Collect = new collect.collect( - { 'canID' : [Number(agent.collectCanId)], + const agent = new collect.collect( + { 'canID' : [Number(agentConf.collectCanId)], 'stateBase': devInfo[0].devStateName, 'device' : 'common', - 'delay' : agent.collectDelayTime, - 'active' : agent.collectActive, - 'channel' : channel + 'timeout' : this.collectTimeout, + 'delay' : agentConf.collectDelayTime }); - agents[Number(agent.collectCanId)] = Collect; - await Collect.initStates(this); + await agent.initStates(this); + if (agent) await agent.startup(this); + agents[Number(agentConf.collectCanId)] = agent; } } } } - } async registerUdsOnStateChange(ctx, id, onChange) { @@ -654,12 +655,13 @@ class E3oncan extends utils.Adapter { onUnload(callback) { try { // Stop UDS agents: - for (const agent of Object.values(this.E3UdsAgents)) { - agent.stop(this); - } - for (const agent of Object.values(this.udsScanAgents)) { - agent.stop(this); - } + for (const agent of Object.values(this.E3UdsAgents)) agent.stop(this); + for (const agent of Object.values(this.udsScanAgents)) agent.stop(this); + + // Stop Collect agents: + if (this.e380Collect) this.e380Collect.stop(this); + for (const agent of Object.values(this.E3CollectExt)) agent.stop(this); + for (const agent of Object.values(this.E3CollectInt)) agent.stop(this); // Stop CAN communication: this.disconnectFromCan(this.channelExt,this.config.canExtName);