From 3961c71b39b76fbf091cc4b32558f9ffe1ba400e Mon Sep 17 00:00:00 2001 From: Stephan Mante Date: Wed, 17 Jan 2024 02:48:01 +0100 Subject: [PATCH 1/4] changed handling of timeout --- README.md | 1 + lib/modbus_connect.js | 6 +++--- main.js | 39 ++++++++++++++++++++------------------- 3 files changed, 24 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 232b486..d51a071 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,7 @@ If you use two inverters, then connect to the second inverter and read the commu ### **WORK IN PROGRESS** * display the data from PV strings (#27) * optimize the timing of interval loop +* improved handling of timeout reading from multiple inverters ### 0.1.2 (2024-01-12) * fix: no Data if interval less 20 sec (#24) diff --git a/lib/modbus_connect.js b/lib/modbus_connect.js index 0ba8080..8d370ec 100644 --- a/lib/modbus_connect.js +++ b/lib/modbus_connect.js @@ -22,7 +22,6 @@ class ModbusConnect extends DeviceInterface { constructor(adapterInstance,ip,port) { super(ip,port); this.adapter = adapterInstance; - this.lastErrno = 0; this._id = 0; } @@ -81,8 +80,9 @@ class ModbusConnect extends DeviceInterface { async _checkError(err) { if (err.modbusCode == null) { + this.adapter.log.debug('modbusCode == 0!'); + await this.close(); //https://github.com/yaacov/node-modbus-serial/issues/96 - //this.adapter.log.debug('Client destroy!'); //await this._destroy(); //this.adapter.log.debug('Client destroy!'); await this._create(); @@ -96,7 +96,7 @@ class ModbusConnect extends DeviceInterface { await this.close(); await this.client.setTimeout(5000); await this.client.connectTcpRTUBuffered(this.ipAddress, { port: this.port} ); //hang - await this.delay(1000); + await this.delay(2000); this.adapter.log.info(`Connected Modbus IP to: ${this.ipAddress} /PORT ${this.port}`); } catch(err) { this.adapter.log.warn('Couldnt connect Modbus TCP to ' + this.ipAddress + ':' + this.port+' '+err.message); diff --git a/main.js b/main.js index 5e07072..ece9d50 100644 --- a/main.js +++ b/main.js @@ -26,7 +26,8 @@ class Sun2000 extends utils.Adapter { }); this.lastTimeUpdated = 0; - this.lastStateUpdated = 0; + this.lastStateUpdatedHigh = 0; + this.lastStateUpdatedLow = 0; this.isConnected = false; this.inverters = []; this.settings = { @@ -214,16 +215,24 @@ class Sun2000 extends utils.Adapter { const sinceLastUpdate = new Date().getTime() - this.lastTimeUpdated; //ms this.log.debug('Watchdog: time to last update '+sinceLastUpdate/1000+' sec'); const lastIsConnected = this.isConnected; - this.isConnected = this.lastStateUpdated > 0 && sinceLastUpdate < this.settings.intervall*2; - this.log.debug('lastIsConncted '+lastIsConnected+' isConnectetd '+this.isConnected+' lastStateupdated '+this.lastStateUpdated); + this.isConnected = this.lastStateUpdatedHigh > 0 && sinceLastUpdate < this.settings.intervall*3; + if (this.lastStateUpdatedLow == 0) { + if (this.lastStateUpdatedHigh == 0) { + this.log.warn('Not data can be read! Please check your settings.'); + } else { + this.log.warn('Not all data can be read! Please reduce the intervall value.'); + } + } + if (this.isConnected !== lastIsConnected ) this.setState('info.connection', this.isConnected, true); + this.lastStateUpdatedLow = 0; + this.lastStateUpdatedHigh = 0; - if (this.isConnected !== lastIsConnected ) this.setState('info.connection', this.isConnected, true); if (sinceLastUpdate > this.settings.intervall*10) { this.log.warn('watchdog: restart Adapter...'); this.restart(); } } - },30000); + },60000); } @@ -265,45 +274,37 @@ class Sun2000 extends utils.Adapter { async dataPolling() { - function timeLeft(target) { - const left = target - new Date().getTime(); + function timeLeft(target,factor =1) { + const left = Math.round((target - new Date().getTime())*factor); if (left < 0) return 0; return left; } const start = new Date().getTime(); - this.log.debug('### DataPolling START '+ Math.round((start-this.lastTimeUpdated)/1000)+' sec ###'); if (this.lastTimeUpdated > 0 && (start-this.lastTimeUpdated)/1000 > this.settings.intervall/1000 + 1) { this.log.warn('time intervall '+(start-this.lastTimeUpdated)/1000+' sec'); } this.lastTimeUpdated = start; - let stateUpdated = 0; - const nextLoop = this.settings.intervall - start % (this.settings.intervall) + start; //High Loop for (const item of this.inverters) { this.modbusClient.setID(item.modbusId); - //this.log.info('### Left Time '+timeLeft/1000); - stateUpdated += await this.state.updateStates(item,this.modbusClient,dataRefreshRate.high,timeLeft(nextLoop)); + this.lastStateUpdatedHigh += await this.state.updateStates(item,this.modbusClient,dataRefreshRate.high,timeLeft(nextLoop)); } if (timeLeft(nextLoop) > 500) { await this.state.runProcessHooks(dataRefreshRate.high); //Low Loop - for (const item of this.inverters) { + for (const [i,item] of this.inverters.entries()) { this.modbusClient.setID(item.modbusId); - //this.log.info('### Left Time '+timeLeft/1000); - stateUpdated += await this.state.updateStates(item,this.modbusClient,dataRefreshRate.low,timeLeft(nextLoop)); + //this.log.debug('+++++ Loop: '+i+' Left Time: '+timeLeft(nextLoop,(i+1)/this.inverters.length)+' Faktor '+((i+1)/this.inverters.length)); + this.lastStateUpdatedLow += await this.state.updateStates(item,this.modbusClient,dataRefreshRate.low,timeLeft(nextLoop,(i+1)/this.inverters.length)); } - //if (timeLeft(nextLoop) > 1000) { await this.state.runProcessHooks(dataRefreshRate.low); - //} } - this.lastStateUpdated = stateUpdated; - if (this.pollingTimer) this.clearTimeout(this.pollingTimer); this.pollingTimer = this.setTimeout(() => { this.dataPolling(); //recursiv From beb4f46dbfff9cf54e04dff6435405d796ac9f0b Mon Sep 17 00:00:00 2001 From: Stephan Mante Date: Wed, 17 Jan 2024 03:02:57 +0100 Subject: [PATCH 2/4] new channel string --- README.md | 2 +- main.js | 28 +++++++++++++++------------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index d51a071..27f1ad8 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ If you use two inverters, then connect to the second inverter and read the commu ### **WORK IN PROGRESS** * display the data from PV strings (#27) * optimize the timing of interval loop -* improved handling of timeout reading from multiple inverters +* improved handling of read timeouts from more then 2 inverters ### 0.1.2 (2024-01-12) * fix: no Data if interval less 20 sec (#24) diff --git a/main.js b/main.js index ece9d50..03e448b 100644 --- a/main.js +++ b/main.js @@ -77,16 +77,14 @@ class Sun2000 extends utils.Adapter { await this.extendObjectAsync('meter', { type: 'device', common: { - name: 'meter', - role: 'info' + name: 'device meter' }, native: {} }); await this.extendObjectAsync('collected', { type: 'channel', common: { - name: 'collected', - role: 'info' + name: 'channel collected' }, native: {} }); @@ -94,8 +92,7 @@ class Sun2000 extends utils.Adapter { await this.extendObjectAsync('inverter', { type: 'device', common: { - name: 'meter', - role: 'info' + name: 'device inverter' }, native: {} }); @@ -116,8 +113,7 @@ class Sun2000 extends utils.Adapter { await this.extendObjectAsync(path+'.grid', { type: 'channel', common: { - name: 'grid', - role: 'info' + name: 'channel grid' }, native: {} }); @@ -125,8 +121,15 @@ class Sun2000 extends utils.Adapter { await this.extendObjectAsync(path+'.battery', { type: 'channel', common: { - name: 'battery', - role: 'info' + name: 'channel battery' + }, + native: {} + }); + + await this.extendObjectAsync(path+'.string', { + type: 'channel', + common: { + name: 'channel string' }, native: {} }); @@ -134,8 +137,7 @@ class Sun2000 extends utils.Adapter { await this.extendObjectAsync(path+'.derived', { type: 'channel', common: { - name: 'derived', - role: 'indicator' + name: 'channel derived' }, native: {} }); @@ -213,7 +215,7 @@ class Sun2000 extends utils.Adapter { if (!this.lastTimeUpdated) this.lastUpdated = 0; if (this.lastTimeUpdated > 0) { const sinceLastUpdate = new Date().getTime() - this.lastTimeUpdated; //ms - this.log.debug('Watchdog: time to last update '+sinceLastUpdate/1000+' sec'); + this.log.debug('Watchdog: time of last update '+sinceLastUpdate/1000+' sec'); const lastIsConnected = this.isConnected; this.isConnected = this.lastStateUpdatedHigh > 0 && sinceLastUpdate < this.settings.intervall*3; if (this.lastStateUpdatedLow == 0) { From 6998d0dace4526aa315a5a12e588ce8adf8a2624 Mon Sep 17 00:00:00 2001 From: Stephan Mante Date: Wed, 17 Jan 2024 03:08:35 +0100 Subject: [PATCH 3/4] change channel role --- main.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/main.js b/main.js index 03e448b..c66c8df 100644 --- a/main.js +++ b/main.js @@ -55,7 +55,7 @@ class Sun2000 extends utils.Adapter { await this.extendObjectAsync('info', { type: 'channel', common: { - name: 'info', + name: 'channel info', role: 'info' }, native: {} @@ -104,7 +104,7 @@ class Sun2000 extends utils.Adapter { await this.extendObjectAsync(path, { type: 'channel', common: { - name: 'modbus'+i, + name: 'channel modbus'+i, role: 'indicator' }, native: {} @@ -118,6 +118,15 @@ class Sun2000 extends utils.Adapter { native: {} }); + await this.extendObjectAsync(path+'.info', { + type: 'channel', + common: { + name: 'channel info', + role: 'info' + }, + native: {} + }); + await this.extendObjectAsync(path+'.battery', { type: 'channel', common: { From fcc249b44a0f1f4773b30c66e25b4557e995593a Mon Sep 17 00:00:00 2001 From: Stephan Mante Date: Wed, 17 Jan 2024 03:53:26 +0100 Subject: [PATCH 4/4] reduce connect delay --- lib/modbus_connect.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/modbus_connect.js b/lib/modbus_connect.js index 8d370ec..486c328 100644 --- a/lib/modbus_connect.js +++ b/lib/modbus_connect.js @@ -96,7 +96,7 @@ class ModbusConnect extends DeviceInterface { await this.close(); await this.client.setTimeout(5000); await this.client.connectTcpRTUBuffered(this.ipAddress, { port: this.port} ); //hang - await this.delay(2000); + await this.delay(1000); this.adapter.log.info(`Connected Modbus IP to: ${this.ipAddress} /PORT ${this.port}`); } catch(err) { this.adapter.log.warn('Couldnt connect Modbus TCP to ' + this.ipAddress + ':' + this.port+' '+err.message);