iobroker.sun2000 0.1.2-alpha.3 → 0.1.3
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/README.md +10 -11
- package/io-package.json +27 -1
- package/lib/modbus_connect.js +2 -2
- package/lib/register.js +79 -4
- package/main.js +50 -39
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -26,6 +26,8 @@ The development of this adapter was inspired by discussions from the forum threa
|
|
|
26
26
|
* HUAWEI Luna2000 Battery
|
|
27
27
|
* HUAWEI Smart Power Sensor DTSU666-H or DDSU666-H
|
|
28
28
|
|
|
29
|
+
[Huawei product information](https://solar.huawei.com/en/professionals/all-products?residential-smart-pv)
|
|
30
|
+
|
|
29
31
|
## Feature list
|
|
30
32
|
|
|
31
33
|
* Maximum 5 inverters (master/slave) can be processed, each with a battery module (max. 30kWh).
|
|
@@ -33,7 +35,6 @@ The development of this adapter was inspired by discussions from the forum threa
|
|
|
33
35
|
* States are only written for changed data from the inverter. This relieves the burden on the iobroker instance.
|
|
34
36
|
* The states “inputPower” or “activePower” in the “collected” path can be monitored with a “was updated” trigger element. Because these states are always written within the set interval.
|
|
35
37
|
|
|
36
|
-
|
|
37
38
|
## Configure inverters
|
|
38
39
|
|
|
39
40
|
In order to use the Modbus connection, all Huawei devices must use the latest firmware
|
|
@@ -45,8 +46,9 @@ To log into the app as an `installer` you need usually the password:`00000a` or
|
|
|
45
46
|
You may also need a password to connect to the inverters own WLAN: `Changeme`
|
|
46
47
|
|
|
47
48
|
After login on the inverter go to `Settings` (Einstellungen) > `Communication configuration` (Kommunikationskonfiguration) > `Dongle parameter settings` (Dongle‐Parametereinstellungen) > `Modbus TCP` > Activate the `connection without restriction` (Verbindung uneingeschränkt aktivieren). You can also enter the Modbus comm address at the same time read out.
|
|
48
|
-
If you use two inverters, then connect to the second inverter and read the communication address there too.
|
|
49
|
+
If you use two inverters, then connect to the second inverter and read the communication address there too.
|
|
49
50
|
|
|
51
|
+
[How activate 'Modbus TCP' - from huawei forum](https://forum.huawei.com/enterprise/en/modbus-tcp-guide/thread/789585-100027)
|
|
50
52
|
|
|
51
53
|
## Settings
|
|
52
54
|
|
|
@@ -61,19 +63,16 @@ If you use two inverters, then connect to the second inverter and read the commu
|
|
|
61
63
|
Placeholder for the next version (at the beginning of the line):
|
|
62
64
|
### **WORK IN PROGRESS**
|
|
63
65
|
-->
|
|
64
|
-
### 0.1.
|
|
65
|
-
*
|
|
66
|
+
### 0.1.3 (2024-01-17)
|
|
67
|
+
* display the data from PV strings (#27)
|
|
68
|
+
* optimize the timing of interval loop
|
|
69
|
+
* improved handling of read timeouts from more then 2 inverters
|
|
66
70
|
|
|
67
|
-
### 0.1.2
|
|
71
|
+
### 0.1.2 (2024-01-12)
|
|
68
72
|
* fix: no Data if interval less 20 sec (#24)
|
|
69
|
-
|
|
70
|
-
### 0.1.2-alpha.1 (2024-01-11)
|
|
71
|
-
* deploy npm package
|
|
72
|
-
|
|
73
|
-
### 0.1.2-alpha.0 (2024-01-11)
|
|
74
73
|
* prepare collected values more precisely
|
|
75
74
|
* expand up to 5 inverters #18
|
|
76
|
-
* fix problems with multiple inverters
|
|
75
|
+
* fix: problems with multiple inverters
|
|
77
76
|
|
|
78
77
|
### 0.1.1 (2024-01-07)
|
|
79
78
|
* fix some collected values
|
package/io-package.json
CHANGED
|
@@ -1,8 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "sun2000",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.3",
|
|
5
5
|
"news": {
|
|
6
|
+
"0.1.3": {
|
|
7
|
+
"en": "display the data from PV strings (#27)\noptimize the timing of interval loop\nimproved handling of read timeouts from more then 2 inverters",
|
|
8
|
+
"de": "die Daten von PV-Strings anzeigen (#27)\noptimieren sie das timing der intervallschleife\nverbesserte handhabung von lesezeitausgängen von mehr als 2 wechselrichtern",
|
|
9
|
+
"ru": "отобразить данные из строк PV (#27)\nоптимизировать время интервального цикла\nулучшенная обработка считываемых таймаутов от более чем 2 инверторов",
|
|
10
|
+
"pt": "exibir os dados de strings PV (#27)\notimizar o tempo de loop de intervalo\nmelhor manuseio de leitura timeouts de mais, em seguida, 2 inversores",
|
|
11
|
+
"nl": "weergave van de gegevens van PV strings (#27)\noptimaliseren van de timing van intervallus\nverbeterde behandeling van leestijd-outs van meer dan 2 inverters",
|
|
12
|
+
"fr": "afficher les données des chaînes PV (#27)\noptimiser le timing de la boucle d'intervalle\namélioration de la gestion des temps de lecture de plus de 2 onduleurs",
|
|
13
|
+
"it": "visualizzare i dati dalle stringhe PV (#27)\nottimizzare la tempistica del loop di intervallo\nmigliore gestione dei timeout di lettura da più di 2 inverter",
|
|
14
|
+
"es": "mostrar los datos de cadenas PV (#27)\noptimizar el tiempo del bucle de intervalo\nmejor manejo de tiempo de lectura de más de 2 inversores",
|
|
15
|
+
"pl": "wyświetla dane z łańcuchów fotowoltaicznych (# 27)\noptymalizacja czasu pętli interwałowej\nulepszona obsługa timeout odczytu z więcej niż 2 inwerterów",
|
|
16
|
+
"uk": "відображення даних з ПВ-рядок (#27)\nоптимізуйте частимізацію інтервалної петлі\nполіпшена обробка часу читання з більш ніж 2 інверторів",
|
|
17
|
+
"zh-cn": "显示 PV 字符串中的数据 (# 27)\n优化间隔循环的时间\n改进对超过2个反转器的断读处理"
|
|
18
|
+
},
|
|
19
|
+
"0.1.2": {
|
|
20
|
+
"en": "fix: no Data if interval less 20 sec (#24)\nprepare collected values more precisely\nexpand up to 5 inverters #18\nfix problems with multiple inverters",
|
|
21
|
+
"de": "fix: keine Daten, wenn Intervall weniger 20 sec (#24)\ndie gesammelten werte genauer\nbis zu 5 wechselrichtern #18 erweitern\nprobleme mit mehreren wechselrichtern beheben",
|
|
22
|
+
"ru": "исправление: нет данных, если интервал менее 20 секунд (#24)\nготовить собранные значения точнее\n#18\nисправить проблемы с несколькими инверторами",
|
|
23
|
+
"pt": "correção: não Dados se intervalo menos 20 segundos (#24)\npreparar valores coletados mais precisamente\nexpandir até 5 inversores #18\ncorrigir problemas com vários inversores",
|
|
24
|
+
"nl": "fix: geen Gegevens indien interval minder 20 sec (#24)\nverzamelde waarden nauwkeuriger voorbereiden\nuit te breiden tot 5 omvormers #18\nproblemen oplossen met meerdere inverters",
|
|
25
|
+
"fr": "correction : pas de données si l'intervalle est inférieur à 20 secondes (#24)\npréparer plus précisément les valeurs collectées\nétendre jusqu'à 5 onduleurs #18\nrésoudre les problèmes avec plusieurs onduleurs",
|
|
26
|
+
"it": "correzione: no Dati se intervallo meno 20 sec (#24)\npreparare i valori raccolti più precisamente\nespandere fino a 5 inverter #18\nrisolvere problemi con più inverter",
|
|
27
|
+
"es": "fijado: no Datos si intervalo menos 20 segundos (#24)\npreparar los valores recogidos con mayor precisión\nampliar hasta 5 inversores #18\nsolucionar problemas con múltiples inversores",
|
|
28
|
+
"pl": "fix: no Data if interval less 20 sec (# 24)\ndokładniej przygotować zebrane wartości\nrozszerzyć do 5 inwerterów # 18\nrozwiązać problemy z wieloma inwerterami",
|
|
29
|
+
"uk": "виправити: немає даних, якщо інтервал менше 20 сек (#24)\nпідготовка зібраних значень точно\nрозширити до 5 інверторів #18\nвиправити проблеми з декількома інверторами",
|
|
30
|
+
"zh-cn": "固定: 如果间隔小于20秒(# 24) 则无数据\n更准确地编制收集的数值\n扩展至5个反转器 # 18\n解决多个反转器的问题"
|
|
31
|
+
},
|
|
6
32
|
"0.1.2-alpha.3": {
|
|
7
33
|
"en": "fix: wrong deploying date",
|
|
8
34
|
"de": "fix: falsches bereitstellungsdatum",
|
package/lib/modbus_connect.js
CHANGED
|
@@ -22,7 +22,6 @@ class ModbusConnect extends DeviceInterface {
|
|
|
22
22
|
constructor(adapterInstance,ip,port) {
|
|
23
23
|
super(ip,port);
|
|
24
24
|
this.adapter = adapterInstance;
|
|
25
|
-
this.lastErrno = 0;
|
|
26
25
|
this._id = 0;
|
|
27
26
|
}
|
|
28
27
|
|
|
@@ -81,8 +80,9 @@ class ModbusConnect extends DeviceInterface {
|
|
|
81
80
|
|
|
82
81
|
async _checkError(err) {
|
|
83
82
|
if (err.modbusCode == null) {
|
|
83
|
+
this.adapter.log.debug('modbusCode == 0!');
|
|
84
|
+
await this.close();
|
|
84
85
|
//https://github.com/yaacov/node-modbus-serial/issues/96
|
|
85
|
-
//this.adapter.log.debug('Client destroy!');
|
|
86
86
|
//await this._destroy();
|
|
87
87
|
//this.adapter.log.debug('Client destroy!');
|
|
88
88
|
await this._create();
|
package/lib/register.js
CHANGED
|
@@ -151,6 +151,10 @@ class Registers {
|
|
|
151
151
|
state: {id: 'info.ratedPower', name: 'Rated power', type: 'number', unit: 'kW', role: 'value.power'},
|
|
152
152
|
register: {reg: 30073, type: dataType.int32, gain:1000}
|
|
153
153
|
},
|
|
154
|
+
{
|
|
155
|
+
state: {id: 'info.numberPVStrings', name: 'Number of PV Strings', type: 'number', unit: '', role: 'value'},
|
|
156
|
+
register: {reg: 30071, type: dataType.uint16}
|
|
157
|
+
},
|
|
154
158
|
{
|
|
155
159
|
state: {id: 'info.numberMPPTrackers', name: 'Number of MPP trackers', type: 'number', unit: '', role: 'value'},
|
|
156
160
|
register: {reg: 30072, type: dataType.uint16}
|
|
@@ -326,7 +330,45 @@ class Registers {
|
|
|
326
330
|
{
|
|
327
331
|
state: {id: 'dailyEnergyYield', name: 'Daily Energy Yield', type: 'number', unit: 'kWh', role: 'value.power.produced'},
|
|
328
332
|
register: {reg: 32114, type: dataType.uint32, gain: 100}
|
|
329
|
-
}
|
|
333
|
+
}
|
|
334
|
+
],
|
|
335
|
+
preHook: (path,reg) => {
|
|
336
|
+
const noPVString = this.stateCache.get(path+'info.numberPVStrings')?.value;
|
|
337
|
+
if (noPVString > 0) {
|
|
338
|
+
if (!stringFieldsTemplate.generated) stringFieldsTemplate.generated = 0;
|
|
339
|
+
if (stringFieldsTemplate.generated < noPVString) {
|
|
340
|
+
for (let i = stringFieldsTemplate.generated; i < noPVString; i++) {
|
|
341
|
+
//clonen
|
|
342
|
+
//const statePV = Object.assign({},stringFieldsTemplate.states[0]);
|
|
343
|
+
const statePV = JSON.parse(JSON.stringify(stringFieldsTemplate.states[0]));
|
|
344
|
+
const stateCu = JSON.parse(JSON.stringify(stringFieldsTemplate.states[1]));
|
|
345
|
+
const statePo = JSON.parse(JSON.stringify(stringFieldsTemplate.states[2]));
|
|
346
|
+
statePV.state.id = 'string.PV'+(i+1)+'Voltage';
|
|
347
|
+
statePV.register.reg = (stringFieldsTemplate.states[0].register?.reg ?? 0)+ (i*2);
|
|
348
|
+
statePV.register.type = stringFieldsTemplate.states[0].register?.type; //types are not copied?!
|
|
349
|
+
stateCu.state.id = 'string.PV'+(i+1)+'Current';
|
|
350
|
+
stateCu.register.reg = (stringFieldsTemplate.states[1].register?.reg ?? 0)+ (i*2);
|
|
351
|
+
stateCu.register.type = stringFieldsTemplate.states[1].register?.type;
|
|
352
|
+
statePo.state.id = 'string.PV'+(i+1)+'Power';
|
|
353
|
+
reg.states.push(statePV);
|
|
354
|
+
reg.states.push(stateCu);
|
|
355
|
+
reg.states.push(statePo);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
stringFieldsTemplate.generated = noPVString;
|
|
359
|
+
}
|
|
360
|
+
},
|
|
361
|
+
postHook: (path) => {
|
|
362
|
+
const noPVString = this.stateCache.get(path+'info.numberPVStrings')?.value;
|
|
363
|
+
if (noPVString > 0) {
|
|
364
|
+
for (let i = 1; i <= noPVString; i++) {
|
|
365
|
+
const voltage = this.stateCache.get(path+'string.PV'+i+'Voltage')?.value;
|
|
366
|
+
const current = this.stateCache.get(path+'string.PV'+i+'Current')?.value;
|
|
367
|
+
this.stateCache.set(path+'string.PV'+i+'Power',Math.round(voltage*current),{type: 'number'});
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
330
372
|
},
|
|
331
373
|
{
|
|
332
374
|
address : 37100,
|
|
@@ -457,6 +499,23 @@ class Registers {
|
|
|
457
499
|
]
|
|
458
500
|
}
|
|
459
501
|
];
|
|
502
|
+
//Vorlage für die StringsRegiter
|
|
503
|
+
const stringFieldsTemplate = {
|
|
504
|
+
states : [
|
|
505
|
+
{
|
|
506
|
+
state: {id: 'string.PV1Voltage', name: 'string voltage', type: 'number', unit: 'V', role: 'value.voltage'},
|
|
507
|
+
register: {reg: 32016, type: dataType.int16, length: 1, gain: 10}
|
|
508
|
+
},
|
|
509
|
+
{
|
|
510
|
+
state: {id: 'string.PV1Current', name: 'string current', type: 'number', unit: 'A', role: 'value.current'},
|
|
511
|
+
register: {reg: 32017, type: dataType.int16, length: 1, gain: 100}
|
|
512
|
+
},
|
|
513
|
+
{
|
|
514
|
+
state: {id: 'string.PV1Power', name: 'string power', type: 'number', unit: 'W', role: 'value.power'}
|
|
515
|
+
}
|
|
516
|
+
]
|
|
517
|
+
};
|
|
518
|
+
|
|
460
519
|
this.postUpdateHooks = [
|
|
461
520
|
{
|
|
462
521
|
refresh : dataRefreshRate.low,
|
|
@@ -469,7 +528,7 @@ class Registers {
|
|
|
469
528
|
}
|
|
470
529
|
}
|
|
471
530
|
];
|
|
472
|
-
this.
|
|
531
|
+
this.postProcessHooks = [
|
|
473
532
|
{
|
|
474
533
|
refresh : dataRefreshRate.high,
|
|
475
534
|
states : [
|
|
@@ -623,6 +682,7 @@ class Registers {
|
|
|
623
682
|
|
|
624
683
|
async processRegister(reg,data) {
|
|
625
684
|
const path = this.getStatePath(reg.type);
|
|
685
|
+
if (reg.preHook) reg.preHook(path,reg);
|
|
626
686
|
if (reg.states) {
|
|
627
687
|
for(const field of reg.states) {
|
|
628
688
|
const state = field.state;
|
|
@@ -658,7 +718,7 @@ class Registers {
|
|
|
658
718
|
let readRegisters = 0;
|
|
659
719
|
for (const reg of this.registerFields) {
|
|
660
720
|
if (duration) {
|
|
661
|
-
if (new Date().getTime() - start > (duration -
|
|
721
|
+
if (new Date().getTime() - start > (duration - 1000)) {
|
|
662
722
|
this.adapter.log.debug('Duration: '+Math.round(duration/1000)+' used time: '+ (new Date().getTime() - start)/1000);
|
|
663
723
|
break;
|
|
664
724
|
}
|
|
@@ -722,7 +782,7 @@ class Registers {
|
|
|
722
782
|
|
|
723
783
|
|
|
724
784
|
async runProcessHooks(refreshRate) {
|
|
725
|
-
for (const hook of this.
|
|
785
|
+
for (const hook of this.postProcessHooks) {
|
|
726
786
|
if (dataRefreshRate.compare(refreshRate,hook.refresh)) {
|
|
727
787
|
for (const state of hook.states) {
|
|
728
788
|
if (!hook['initState'+this.inverterInfo.index]) {
|
|
@@ -736,6 +796,21 @@ class Registers {
|
|
|
736
796
|
this.storeStates(); //fire and forget
|
|
737
797
|
}
|
|
738
798
|
|
|
799
|
+
/*
|
|
800
|
+
setStateOfStrings() {
|
|
801
|
+
jsonPricesTomorrow = jsonPricesToday.map( x =>
|
|
802
|
+
{
|
|
803
|
+
//console.log(x);
|
|
804
|
+
const json = Object.assign({}, x); //Object clonen, flaches Clonen!
|
|
805
|
+
const date = new Date(json.startsAt);
|
|
806
|
+
// add a day
|
|
807
|
+
date.setDate(date.getDate() + 1);
|
|
808
|
+
json.startsAt = date.toISOString();
|
|
809
|
+
return json;
|
|
810
|
+
} );
|
|
811
|
+
}
|
|
812
|
+
*/
|
|
813
|
+
|
|
739
814
|
async _loadStates() {
|
|
740
815
|
let value = await this.adapter.getStateAsync('collected.gridExportStart');
|
|
741
816
|
this.stateCache.set('collected.gridExportStart',value?.val, {type : 'number', stored : true });
|
package/main.js
CHANGED
|
@@ -26,7 +26,8 @@ class Sun2000 extends utils.Adapter {
|
|
|
26
26
|
});
|
|
27
27
|
|
|
28
28
|
this.lastTimeUpdated = 0;
|
|
29
|
-
this.
|
|
29
|
+
this.lastStateUpdatedHigh = 0;
|
|
30
|
+
this.lastStateUpdatedLow = 0;
|
|
30
31
|
this.isConnected = false;
|
|
31
32
|
this.inverters = [];
|
|
32
33
|
this.settings = {
|
|
@@ -54,7 +55,7 @@ class Sun2000 extends utils.Adapter {
|
|
|
54
55
|
await this.extendObjectAsync('info', {
|
|
55
56
|
type: 'channel',
|
|
56
57
|
common: {
|
|
57
|
-
name: 'info',
|
|
58
|
+
name: 'channel info',
|
|
58
59
|
role: 'info'
|
|
59
60
|
},
|
|
60
61
|
native: {}
|
|
@@ -76,16 +77,14 @@ class Sun2000 extends utils.Adapter {
|
|
|
76
77
|
await this.extendObjectAsync('meter', {
|
|
77
78
|
type: 'device',
|
|
78
79
|
common: {
|
|
79
|
-
name: 'meter'
|
|
80
|
-
role: 'info'
|
|
80
|
+
name: 'device meter'
|
|
81
81
|
},
|
|
82
82
|
native: {}
|
|
83
83
|
});
|
|
84
84
|
await this.extendObjectAsync('collected', {
|
|
85
85
|
type: 'channel',
|
|
86
86
|
common: {
|
|
87
|
-
name: 'collected'
|
|
88
|
-
role: 'info'
|
|
87
|
+
name: 'channel collected'
|
|
89
88
|
},
|
|
90
89
|
native: {}
|
|
91
90
|
});
|
|
@@ -93,21 +92,19 @@ class Sun2000 extends utils.Adapter {
|
|
|
93
92
|
await this.extendObjectAsync('inverter', {
|
|
94
93
|
type: 'device',
|
|
95
94
|
common: {
|
|
96
|
-
name: '
|
|
97
|
-
role: 'info'
|
|
95
|
+
name: 'device inverter'
|
|
98
96
|
},
|
|
99
97
|
native: {}
|
|
100
98
|
});
|
|
101
99
|
|
|
102
|
-
//ES6 use a for (const [index, item] of array.entries())
|
|
103
|
-
//for (const [i, item] of this.conf.entries()) {
|
|
100
|
+
//ES6 use a for (const [index, item] of array.entries()) of loop
|
|
104
101
|
for (const [i, item] of this.inverters.entries()) {
|
|
105
102
|
const path = 'inverter.'+String(i);
|
|
106
103
|
item.path = path;
|
|
107
104
|
await this.extendObjectAsync(path, {
|
|
108
105
|
type: 'channel',
|
|
109
106
|
common: {
|
|
110
|
-
name: 'modbus'+i,
|
|
107
|
+
name: 'channel modbus'+i,
|
|
111
108
|
role: 'indicator'
|
|
112
109
|
},
|
|
113
110
|
native: {}
|
|
@@ -116,7 +113,15 @@ class Sun2000 extends utils.Adapter {
|
|
|
116
113
|
await this.extendObjectAsync(path+'.grid', {
|
|
117
114
|
type: 'channel',
|
|
118
115
|
common: {
|
|
119
|
-
name: 'grid'
|
|
116
|
+
name: 'channel grid'
|
|
117
|
+
},
|
|
118
|
+
native: {}
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
await this.extendObjectAsync(path+'.info', {
|
|
122
|
+
type: 'channel',
|
|
123
|
+
common: {
|
|
124
|
+
name: 'channel info',
|
|
120
125
|
role: 'info'
|
|
121
126
|
},
|
|
122
127
|
native: {}
|
|
@@ -125,8 +130,15 @@ class Sun2000 extends utils.Adapter {
|
|
|
125
130
|
await this.extendObjectAsync(path+'.battery', {
|
|
126
131
|
type: 'channel',
|
|
127
132
|
common: {
|
|
128
|
-
name: 'battery'
|
|
129
|
-
|
|
133
|
+
name: 'channel battery'
|
|
134
|
+
},
|
|
135
|
+
native: {}
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
await this.extendObjectAsync(path+'.string', {
|
|
139
|
+
type: 'channel',
|
|
140
|
+
common: {
|
|
141
|
+
name: 'channel string'
|
|
130
142
|
},
|
|
131
143
|
native: {}
|
|
132
144
|
});
|
|
@@ -134,8 +146,7 @@ class Sun2000 extends utils.Adapter {
|
|
|
134
146
|
await this.extendObjectAsync(path+'.derived', {
|
|
135
147
|
type: 'channel',
|
|
136
148
|
common: {
|
|
137
|
-
name: 'derived'
|
|
138
|
-
role: 'indicator'
|
|
149
|
+
name: 'channel derived'
|
|
139
150
|
},
|
|
140
151
|
native: {}
|
|
141
152
|
});
|
|
@@ -213,18 +224,26 @@ class Sun2000 extends utils.Adapter {
|
|
|
213
224
|
if (!this.lastTimeUpdated) this.lastUpdated = 0;
|
|
214
225
|
if (this.lastTimeUpdated > 0) {
|
|
215
226
|
const sinceLastUpdate = new Date().getTime() - this.lastTimeUpdated; //ms
|
|
216
|
-
this.log.debug('Watchdog: time
|
|
227
|
+
this.log.debug('Watchdog: time of last update '+sinceLastUpdate/1000+' sec');
|
|
217
228
|
const lastIsConnected = this.isConnected;
|
|
218
|
-
this.isConnected = this.
|
|
219
|
-
|
|
229
|
+
this.isConnected = this.lastStateUpdatedHigh > 0 && sinceLastUpdate < this.settings.intervall*3;
|
|
230
|
+
if (this.lastStateUpdatedLow == 0) {
|
|
231
|
+
if (this.lastStateUpdatedHigh == 0) {
|
|
232
|
+
this.log.warn('Not data can be read! Please check your settings.');
|
|
233
|
+
} else {
|
|
234
|
+
this.log.warn('Not all data can be read! Please reduce the intervall value.');
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
if (this.isConnected !== lastIsConnected ) this.setState('info.connection', this.isConnected, true);
|
|
238
|
+
this.lastStateUpdatedLow = 0;
|
|
239
|
+
this.lastStateUpdatedHigh = 0;
|
|
220
240
|
|
|
221
|
-
if (this.isConnected !== lastIsConnected ) this.setState('info.connection', this.isConnected, true);
|
|
222
241
|
if (sinceLastUpdate > this.settings.intervall*10) {
|
|
223
242
|
this.log.warn('watchdog: restart Adapter...');
|
|
224
243
|
this.restart();
|
|
225
244
|
}
|
|
226
245
|
}
|
|
227
|
-
},
|
|
246
|
+
},60000);
|
|
228
247
|
}
|
|
229
248
|
|
|
230
249
|
|
|
@@ -265,46 +284,38 @@ class Sun2000 extends utils.Adapter {
|
|
|
265
284
|
}
|
|
266
285
|
|
|
267
286
|
async dataPolling() {
|
|
268
|
-
|
|
269
|
-
|
|
287
|
+
|
|
288
|
+
function timeLeft(target,factor =1) {
|
|
289
|
+
const left = Math.round((target - new Date().getTime())*factor);
|
|
270
290
|
if (left < 0) return 0;
|
|
271
291
|
return left;
|
|
272
292
|
}
|
|
273
293
|
|
|
274
294
|
const start = new Date().getTime();
|
|
275
|
-
|
|
276
|
-
this.log.debug('### DataPolling START <> '+ Math.round((start-this.lastTimeUpdated)/1000)+' sec ###');
|
|
295
|
+
this.log.debug('### DataPolling START '+ Math.round((start-this.lastTimeUpdated)/1000)+' sec ###');
|
|
277
296
|
if (this.lastTimeUpdated > 0 && (start-this.lastTimeUpdated)/1000 > this.settings.intervall/1000 + 1) {
|
|
278
297
|
this.log.warn('time intervall '+(start-this.lastTimeUpdated)/1000+' sec');
|
|
279
298
|
}
|
|
280
299
|
this.lastTimeUpdated = start;
|
|
281
|
-
let stateUpdated = 0;
|
|
282
|
-
|
|
283
300
|
const nextLoop = this.settings.intervall - start % (this.settings.intervall) + start;
|
|
284
301
|
|
|
285
302
|
//High Loop
|
|
286
303
|
for (const item of this.inverters) {
|
|
287
304
|
this.modbusClient.setID(item.modbusId);
|
|
288
|
-
|
|
289
|
-
stateUpdated += await this.state.updateStates(item,this.modbusClient,dataRefreshRate.high,timeLeft(nextLoop));
|
|
305
|
+
this.lastStateUpdatedHigh += await this.state.updateStates(item,this.modbusClient,dataRefreshRate.high,timeLeft(nextLoop));
|
|
290
306
|
}
|
|
291
307
|
|
|
292
|
-
if (timeLeft(nextLoop) >
|
|
308
|
+
if (timeLeft(nextLoop) > 500) {
|
|
293
309
|
await this.state.runProcessHooks(dataRefreshRate.high);
|
|
294
|
-
|
|
295
310
|
//Low Loop
|
|
296
|
-
for (const item of this.inverters) {
|
|
311
|
+
for (const [i,item] of this.inverters.entries()) {
|
|
297
312
|
this.modbusClient.setID(item.modbusId);
|
|
298
|
-
//this.log.
|
|
299
|
-
|
|
300
|
-
}
|
|
301
|
-
if (timeLeft(nextLoop) > 1000) {
|
|
302
|
-
await this.state.runProcessHooks(dataRefreshRate.low);
|
|
313
|
+
//this.log.debug('+++++ Loop: '+i+' Left Time: '+timeLeft(nextLoop,(i+1)/this.inverters.length)+' Faktor '+((i+1)/this.inverters.length));
|
|
314
|
+
this.lastStateUpdatedLow += await this.state.updateStates(item,this.modbusClient,dataRefreshRate.low,timeLeft(nextLoop,(i+1)/this.inverters.length));
|
|
303
315
|
}
|
|
316
|
+
await this.state.runProcessHooks(dataRefreshRate.low);
|
|
304
317
|
}
|
|
305
318
|
|
|
306
|
-
this.lastStateUpdated = stateUpdated;
|
|
307
|
-
|
|
308
319
|
if (this.pollingTimer) this.clearTimeout(this.pollingTimer);
|
|
309
320
|
this.pollingTimer = this.setTimeout(() => {
|
|
310
321
|
this.dataPolling(); //recursiv
|