iobroker.sun2000 0.16.0 → 0.17.1
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 +11 -1
- package/admin/jsonConfig.json5 +50 -10
- package/io-package.json +27 -27
- package/lib/drivers/driver_inverter.js +50 -59
- package/lib/modbus/modbus_server.js +19 -21
- package/lib/register.js +1 -1
- package/main.js +16 -14
- package/package.json +6 -3
package/README.md
CHANGED
|
@@ -28,7 +28,7 @@ Read and write register data from Huawei SUN2000 inverter and LUNA2000 battery u
|
|
|
28
28
|
Feel free to follow the discussions in the german [iobroker forum](https://forum.iobroker.net/topic/71768/test-adapter-sun2000-v0-1-x-huawei-wechselrichter)
|
|
29
29
|
|
|
30
30
|
## Dependencies
|
|
31
|
-
* Node.js 18.
|
|
31
|
+
* Node.js 18.18.0 or higher
|
|
32
32
|
* ioBroker host (js-controller) 5.0.19 or higher
|
|
33
33
|
* ioBroker admin 5.1.13 or higher
|
|
34
34
|
|
|
@@ -65,6 +65,16 @@ browse in the [wiki](https://github.com/bolliy/ioBroker.sun2000/wiki)
|
|
|
65
65
|
Placeholder for the next version (at the beginning of the line):
|
|
66
66
|
### **WORK IN PROGRESS**
|
|
67
67
|
-->
|
|
68
|
+
### 0.17.1 (2024-11-21)
|
|
69
|
+
* during the device status "Standby: detecting irradiation" (0x0002) register data is now also read from the inverter
|
|
70
|
+
* The reading order of the battery data has been adjusted
|
|
71
|
+
|
|
72
|
+
### 0.17.0 (2024-11-05)
|
|
73
|
+
* adjust for Responsive Design #134
|
|
74
|
+
* migrate to ESLint 9.x
|
|
75
|
+
* node >= v18.18.0
|
|
76
|
+
* modbus-proxy: enabled reading data via input register
|
|
77
|
+
|
|
68
78
|
### 0.16.0 (2024-11-01)
|
|
69
79
|
* dependency and configuration updates
|
|
70
80
|
* read additional register data of Huawei Emma
|
package/admin/jsonConfig.json5
CHANGED
|
@@ -11,7 +11,12 @@
|
|
|
11
11
|
"items": {
|
|
12
12
|
"donateTxt": {
|
|
13
13
|
"type": "staticText",
|
|
14
|
-
"text": "donateTxt"
|
|
14
|
+
"text": "donateTxt",
|
|
15
|
+
"xs": 12,
|
|
16
|
+
"sm": 12,
|
|
17
|
+
"md": 6,
|
|
18
|
+
"lg": 4,
|
|
19
|
+
"xl": 4
|
|
15
20
|
},
|
|
16
21
|
"donateImage": {
|
|
17
22
|
"type": "staticImage",
|
|
@@ -19,8 +24,8 @@
|
|
|
19
24
|
"href" : "https://www.paypal.com/donate/?hosted_button_id=ZTX3VP9LZBDCG",
|
|
20
25
|
"src" : "paypal-button.png",
|
|
21
26
|
"newLine": true,
|
|
22
|
-
"xs":
|
|
23
|
-
"sm":
|
|
27
|
+
"xs": 6,
|
|
28
|
+
"sm": 4,
|
|
24
29
|
"md": 2,
|
|
25
30
|
"lg": 2,
|
|
26
31
|
"xl": 2
|
|
@@ -114,7 +119,12 @@
|
|
|
114
119
|
"chipsTxt": {
|
|
115
120
|
"type": "staticText",
|
|
116
121
|
"text": "Provides the collected data from the SDongle",
|
|
117
|
-
"newLine": true
|
|
122
|
+
"newLine": true,
|
|
123
|
+
"xs": 12,
|
|
124
|
+
"sm": 12,
|
|
125
|
+
"md": 6,
|
|
126
|
+
"lg": 4,
|
|
127
|
+
"xl": 4
|
|
118
128
|
},
|
|
119
129
|
"sd_active": {
|
|
120
130
|
"type": "checkbox",
|
|
@@ -166,7 +176,12 @@
|
|
|
166
176
|
"chipsTxt1": {
|
|
167
177
|
"type": "staticText",
|
|
168
178
|
"text": "Placeholder for future Settings",
|
|
169
|
-
"newLine": true
|
|
179
|
+
"newLine": true,
|
|
180
|
+
"xs": 12,
|
|
181
|
+
"sm": 12,
|
|
182
|
+
"md": 6,
|
|
183
|
+
"lg": 4,
|
|
184
|
+
"xl": 4
|
|
170
185
|
}
|
|
171
186
|
}
|
|
172
187
|
},
|
|
@@ -183,7 +198,12 @@
|
|
|
183
198
|
"chipsTxt": {
|
|
184
199
|
"type": "staticText",
|
|
185
200
|
"text": "Third party device such as wallbox, energy manager etc. can receive and send data even if the modbus interface of inverter is already in use. In addition you can mirror the sun2000 data to another IoBroker instance.",
|
|
186
|
-
"newLine": true
|
|
201
|
+
"newLine": true,
|
|
202
|
+
"xs": 12,
|
|
203
|
+
"sm": 12,
|
|
204
|
+
"md": 6,
|
|
205
|
+
"lg": 4,
|
|
206
|
+
"xl": 4
|
|
187
207
|
},
|
|
188
208
|
"ms_active": {
|
|
189
209
|
"type": "checkbox",
|
|
@@ -244,7 +264,12 @@
|
|
|
244
264
|
"chipsTxt1": {
|
|
245
265
|
"type": "staticText",
|
|
246
266
|
"text": "This control is set in the opject path `sun2000.0.inverter.x.control.battery`",
|
|
247
|
-
"newLine": true
|
|
267
|
+
"newLine": true,
|
|
268
|
+
"xs": 12,
|
|
269
|
+
"sm": 12,
|
|
270
|
+
"md": 6,
|
|
271
|
+
"lg": 4,
|
|
272
|
+
"xl": 4
|
|
248
273
|
},
|
|
249
274
|
"cb_tou": {
|
|
250
275
|
"type": "checkbox",
|
|
@@ -279,7 +304,12 @@
|
|
|
279
304
|
"chipsTxt2": {
|
|
280
305
|
"type": "staticText",
|
|
281
306
|
"text": "This control is set in the opject path `sun2000.0.inverter.x.control.battery`",
|
|
282
|
-
"newLine": true
|
|
307
|
+
"newLine": true,
|
|
308
|
+
"xs": 12,
|
|
309
|
+
"sm": 12,
|
|
310
|
+
"md": 6,
|
|
311
|
+
"lg": 4,
|
|
312
|
+
"xl": 4
|
|
283
313
|
},
|
|
284
314
|
"staticLink2": {
|
|
285
315
|
"type": "staticLink",
|
|
@@ -303,7 +333,12 @@
|
|
|
303
333
|
"chipsTxt3": {
|
|
304
334
|
"type": "staticText",
|
|
305
335
|
"text": "This control is set in the opject path `sun2000.0.inverter.0.control.grid`",
|
|
306
|
-
"newLine": true
|
|
336
|
+
"newLine": true,
|
|
337
|
+
"xs": 12,
|
|
338
|
+
"sm": 12,
|
|
339
|
+
"md": 6,
|
|
340
|
+
"lg": 4,
|
|
341
|
+
"xl": 4
|
|
307
342
|
},
|
|
308
343
|
"staticLink3": {
|
|
309
344
|
"type": "staticLink",
|
|
@@ -429,7 +464,12 @@
|
|
|
429
464
|
"chipsTxt": {
|
|
430
465
|
"type": "staticText",
|
|
431
466
|
"text": "Do you need help? There are multiple ways of getting support. ",
|
|
432
|
-
"newLine": true
|
|
467
|
+
"newLine": true,
|
|
468
|
+
"xs": 12,
|
|
469
|
+
"sm": 12,
|
|
470
|
+
"md": 6,
|
|
471
|
+
"lg": 4,
|
|
472
|
+
"xl": 4
|
|
433
473
|
},
|
|
434
474
|
"staticLink1": {
|
|
435
475
|
"type": "staticLink",
|
package/io-package.json
CHANGED
|
@@ -1,8 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "sun2000",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.17.1",
|
|
5
5
|
"news": {
|
|
6
|
+
"0.17.1": {
|
|
7
|
+
"en": "during the device status \"Standby: detecting irradiation\" (0x0002) register data is now also read from the inverter\nThe reading order of the battery data has been adjusted",
|
|
8
|
+
"de": "während des Gerätestatus \"Standby: Detektion von Bestrahlung\" (0x0002) werden nun auch Registerdaten aus dem Wechselrichter gelesen\nDie Lesereihenfolge der Batteriedaten wurde angepasst",
|
|
9
|
+
"ru": "во время состояния устройства «Стандби: обнаружение облучения» (0x0002) данные регистров теперь также читаются из инвертора\nПорядок чтения данных батареи был скорректирован",
|
|
10
|
+
"pt": "durante o status do dispositivo \"Standby: detecção de irradiação\" (0x0002) dados de registro agora também é lido a partir do inversor\nA ordem de leitura dos dados da bateria foi ajustada",
|
|
11
|
+
"nl": "tijdens de apparaatstatus \"Standby: detectie van bestraling\" (0x0002) worden nu ook gegevens van de omvormer gelezen\nDe leesvolgorde van de batterijgegevens is aangepast",
|
|
12
|
+
"fr": "pendant l'état de l'appareil \"Standby: détecter l'irradiation\" (0x0002) les données du registre sont maintenant également lues à partir de l'onduleur\nL'ordre de lecture des données de la batterie a été ajusté",
|
|
13
|
+
"it": "durante lo stato del dispositivo \"Standby: rilevamento dell'irradiazione\" (0x0002) i dati di registro sono ora letti anche dall'inverter\nL'ordine di lettura dei dati della batteria è stato regolato",
|
|
14
|
+
"es": "durante el estado del dispositivo \"Standby: detecting irradiation\" (0x0002) datos del registro ahora también se lee desde el inversor\nEl orden de lectura de los datos de la batería se ha ajustado",
|
|
15
|
+
"pl": "podczas statusu urządzenia \"Standby: detection irradiation\" (0x0002) dane rejestru są teraz również odczytywane z inwertera\nKolejność odczytu danych baterii została dostosowana",
|
|
16
|
+
"uk": "при статусі пристрою \"Стандарт: виявлення опромінення\" (0x0002) реєстраційні дані тепер також читайте з інвертора\nВиправлено порядок читання даних акумулятора",
|
|
17
|
+
"zh-cn": "在设备状态“ Standby: 检测辐照” (0x0002) 注册数据现在也从反转器读取\n电池数据的读取顺序已调整"
|
|
18
|
+
},
|
|
19
|
+
"0.17.0": {
|
|
20
|
+
"en": "adjust for Responsive Design #134\nmigrate to ESLint 9.x\nnode >= v18.18.0\nmodbus-proxy: enabled reading data via input register",
|
|
21
|
+
"de": "anpassung für Responsive Design #134\nmigration auf ESLint 9.x\nknoten >= v18.18.0\nmodbus-proxy: lesedaten über eingaberegister aktiviert",
|
|
22
|
+
"ru": "#134\nмигрировать в ESLint 9.x\nnode >= v18.18.0\nmodbus-proxy: включено чтение данных через регистр ввода",
|
|
23
|
+
"pt": "ajustar para Design responsivo #134\nmigrar para ESLint 9.x\nnode >= v18.18.0\nmodbus-proxy: dados de leitura habilitados via registro de entrada",
|
|
24
|
+
"nl": "aanpassen voor Responsive Design #134\nmigreren naar ESLint 9.x\nn.v.t\nmodbus-proxy: leesgegevens ingeschakeld via invoerregister",
|
|
25
|
+
"fr": "ajuster pour Responsive Design #134\nmigrer vers ESLint 9.x\nnoeud >= v18.18.0\nmodbus-proxy: activé la lecture des données via le registre d'entrée",
|
|
26
|
+
"it": "regolazione per Responsive Design #134\nmigrare a ESLint 9.x\nnodo >= v18.18.0\nmodbus-proxy: dati di lettura abilitati tramite registro input",
|
|
27
|
+
"es": "ajuste para el diseño responsable #134\nmigrar a ESLint 9.x\nnodo\nmodbus-proxy: datos de lectura habilitados mediante registro de entrada",
|
|
28
|
+
"pl": "dostosowanie dla Responsive Design # 134\nmigrate do ESLint 9.x\nwęzeł > = v18.18.0\nmodbus- proxy: włączone odczytywanie danych poprzez rejestr wejściowy",
|
|
29
|
+
"uk": "конфігурація для відповідального дизайну #134\nmigrate до ESLint 9.x\nвершина >= v18.18.0\nmodbus-proxy: ввімкнено дані читання через вхідний реєстр",
|
|
30
|
+
"zh-cn": "调整响应设计 # 134\n迁移到 ESLint 9.x\n节点 {v18.18.0}\nmodbus- 代理: 启用通过输入寄存器读取数据"
|
|
31
|
+
},
|
|
6
32
|
"0.16.0": {
|
|
7
33
|
"en": "dependency and configuration updates\nread additional register data of Huawei Emma",
|
|
8
34
|
"de": "abhängigkeits- und konfigurationsupdates\nweitere Registrierungsdaten von Huawei Emma lesen",
|
|
@@ -67,32 +93,6 @@
|
|
|
67
93
|
"pl": "dostosowanie do projektu Responsive Design # 121\nblokada asynchronicznego kodu modbusa\nzapisywanie danych za pośrednictwem modbus- proxy # 119\nprzeczytaj dodatkowe dane rejestru Huawei Emma",
|
|
68
94
|
"uk": "регульований для відповідального дизайну #121\nблокування на коді asynchronous modbus\nнаписання даних через modbus-proxy #119\nчитати додаткові реєстраційні дані Huawei Emma",
|
|
69
95
|
"zh-cn": "适应设计 # 121\n锁定同步调制解码\n通过modbus- 代理 119 写入数据\n读取 Huawei Emma 的额外注册数据"
|
|
70
|
-
},
|
|
71
|
-
"0.13.0": {
|
|
72
|
-
"en": "improve Modbus reconnection #116\nconfiguration update\nsimple Integration of Huawei Emma (Huawei Energy Management Assistant) #63",
|
|
73
|
-
"de": "modbus-Reconnection #116 verbessern\nkonfigurationsupdate\neinfache Integration von Huawei Emma (Huawei Energy Management Assistant) #63",
|
|
74
|
-
"ru": "#116\nобновление\nпростая интеграция Huawei Эмма (Huawei Energy Management Assistant) #63",
|
|
75
|
-
"pt": "melhorar a reconexão Modbus #116\natualização de configuração\nsimples integração de Huawei Emma (Huawei Energy Management Assistant) #63",
|
|
76
|
-
"nl": "modbus reconnectie #116 verbeteren\nconfiguratie-update\neenvoudige integratie van Huawei Emma (Huawei Energie Management Assistent) #63",
|
|
77
|
-
"fr": "améliorer la connexion Modbus #116\nmise à jour de configuration\nsimple intégration de Huawei Emma (Huawei Energy Management Assistant) #63",
|
|
78
|
-
"it": "migliorare la riconnessione Modbus #116\naggiornamento configurazione\nintegrazione semplice di Huawei Emma (Huawei Energy Management Assistant) #63",
|
|
79
|
-
"es": "mejorar la reconexión Modbus #116\nactualización de configuración\nsimple integración de Huawei Emma (Auxiliador de Gestión de Energía de Huawei) #63",
|
|
80
|
-
"pl": "poprawić ponowne połączenie Modbus # 116\naktualizacja konfiguracji\nprosta integracja Huawei Emma (Huawei Energy Management Assistant) # 63",
|
|
81
|
-
"uk": "поліпшення відключення Modbus #116\nоновлення конфігурації\nпроста інтеграція Huawei Emma (Huawei Energy Management Assistant) #63",
|
|
82
|
-
"zh-cn": "改进 Modbus 重联 # 116\n配置更新\n简单整合Huawei Emma(Huawei能源管理助理)#63"
|
|
83
|
-
},
|
|
84
|
-
"0.12.1": {
|
|
85
|
-
"en": "no warning from check the valid number during standby: \"no irradiation\"",
|
|
86
|
-
"de": "keine warnung vor der prüfung der gültigen nummer im standby: \"keine bestrahlung\"",
|
|
87
|
-
"ru": "не предупредить проверить действительный номер во время ожидания: «без облучения»",
|
|
88
|
-
"pt": "sem aviso de verificar o número válido durante o standby: \"nenhuma irradiação\"",
|
|
89
|
-
"nl": "geen waarschuwing van controle van het geldige nummer tijdens standby: \"geen bestraling\"",
|
|
90
|
-
"fr": "aucun avertissement de vérifier le nombre valide en attente: \"pas d'irradiation\"",
|
|
91
|
-
"it": "nessun avviso da controllare il numero valido durante la standby: \"nessuna irradiazione\"",
|
|
92
|
-
"es": "no hay advertencia de comprobar el número válido durante la espera: \"no irradiación\"",
|
|
93
|
-
"pl": "brak ostrzeżenia z sprawdzenia poprawnego numeru podczas czuwania: \"brak napromieniowania\"",
|
|
94
|
-
"uk": "без попередження про перевірку дійсного числа під час очікування: \"не опромінення\"",
|
|
95
|
-
"zh-cn": "在待命时不检查有效号码的警告 : “ 不辐射 ”"
|
|
96
96
|
}
|
|
97
97
|
},
|
|
98
98
|
"titleLang": {
|
|
@@ -200,6 +200,7 @@ class InverterSun2000 extends DriverBase{
|
|
|
200
200
|
length : 2,
|
|
201
201
|
info : 'meter activePower',
|
|
202
202
|
refresh : dataRefreshRate.high,
|
|
203
|
+
//standby : true,
|
|
203
204
|
type : deviceType.meter,
|
|
204
205
|
states: [{
|
|
205
206
|
state: {id: 'meter.activePower', name: 'ActivePower', type: 'number', unit: 'kW', role: 'value.power.active', desc: 'reg:37113, len:2 (>0: feed-in to grid. <0: supply from grid.)' },
|
|
@@ -452,6 +453,53 @@ class InverterSun2000 extends DriverBase{
|
|
|
452
453
|
],
|
|
453
454
|
checkIfActive: () => this._batteryExists()
|
|
454
455
|
},
|
|
456
|
+
{
|
|
457
|
+
address : 37758,
|
|
458
|
+
length : 30,
|
|
459
|
+
info : 'battery information',
|
|
460
|
+
refresh : dataRefreshRate.low,
|
|
461
|
+
type : deviceType.battery,
|
|
462
|
+
states: [
|
|
463
|
+
{
|
|
464
|
+
state: {id: 'battery.ratedCapacity', name: 'Rated Capacity', type: 'number', unit: 'Wh', role: 'value.capacity', desc: 'reg:37758, len:2'},
|
|
465
|
+
register: {reg: 37758, type: dataType.uint32}
|
|
466
|
+
},
|
|
467
|
+
{
|
|
468
|
+
state: {id: 'battery.SOC', name: 'State of capacity', type: 'number', unit: '%', role: 'value.battery', desc: 'reg:37760, len:1'},
|
|
469
|
+
register: {reg: 37760, type: dataType.uint16, gain: 10}
|
|
470
|
+
},
|
|
471
|
+
{
|
|
472
|
+
state: {id: 'battery.runningStatus', name: 'Running status', type: 'string', role: 'value', desc: 'reg:37762, len:1'},
|
|
473
|
+
register: {reg: 37762, type: dataType.uint16, length: 1},
|
|
474
|
+
mapper: value => Promise.resolve(batteryStatus[value])
|
|
475
|
+
},
|
|
476
|
+
{
|
|
477
|
+
state: {id: 'battery.busVoltage', name: 'Bus Voltage', type: 'number', unit: 'V', role: 'value.voltage', desc: 'reg:37763, len:1'},
|
|
478
|
+
register: {reg: 37763, type: dataType.uint16, gain: 10},
|
|
479
|
+
},
|
|
480
|
+
{
|
|
481
|
+
state: {id: 'battery.busCurrent', name: 'Bus Current', type: 'number', unit: 'A', role: 'value.current', desc: 'reg:37764, len:1'},
|
|
482
|
+
register: {reg: 37764, type: dataType.int16, gain: 10},
|
|
483
|
+
},
|
|
484
|
+
{
|
|
485
|
+
state: {id: 'battery.totalCharge', name: 'Total Charge', type: 'number', unit: 'kWh', role: 'value.power.consumption', desc: 'reg:37780, len:2'},
|
|
486
|
+
register: {reg: 37780, type: dataType.uint32, gain: 100}
|
|
487
|
+
},
|
|
488
|
+
{
|
|
489
|
+
state: {id: 'battery.totalDischarge', name: 'Total Discharge', type: 'number', unit: 'kWh', role: 'value.power.consumption', desc: 'reg:37782, len:2'},
|
|
490
|
+
register: {reg: 37782, type: dataType.uint32, gain: 100}
|
|
491
|
+
},
|
|
492
|
+
{
|
|
493
|
+
state: {id: 'battery.currentDayChargeCapacity', name: 'Current Day Charge Capacity', type: 'number', unit: 'kWh', role: 'value.power.consumption', desc: 'reg:37784, len:2' },
|
|
494
|
+
register: { reg: 37784, type: dataType.uint32, gain: 100 }
|
|
495
|
+
},
|
|
496
|
+
{
|
|
497
|
+
state: {id: 'battery.currentDayDischargeCapacity', name: 'Current Day Discharge Capacity', type: 'number', unit: 'kWh', role: 'value.power.consumption', desc: 'reg:37786, len:2' },
|
|
498
|
+
register: { reg: 37786, type: dataType.uint32, gain: 100 }
|
|
499
|
+
}
|
|
500
|
+
],
|
|
501
|
+
checkIfActive: () => this._batteryExists()
|
|
502
|
+
},
|
|
455
503
|
{ //for NRGKick
|
|
456
504
|
address : 47000,
|
|
457
505
|
length : 1,
|
|
@@ -503,7 +551,6 @@ class InverterSun2000 extends DriverBase{
|
|
|
503
551
|
address : 47101,
|
|
504
552
|
length : 6,
|
|
505
553
|
info : 'additional battery information',
|
|
506
|
-
//refresh : dataRefreshRate.low,
|
|
507
554
|
type : deviceType.battery,
|
|
508
555
|
states: [
|
|
509
556
|
{
|
|
@@ -826,53 +873,6 @@ class InverterSun2000 extends DriverBase{
|
|
|
826
873
|
}
|
|
827
874
|
]
|
|
828
875
|
},
|
|
829
|
-
{
|
|
830
|
-
address : 37758,
|
|
831
|
-
length : 30,
|
|
832
|
-
info : 'battery information',
|
|
833
|
-
refresh : dataRefreshRate.low,
|
|
834
|
-
type : deviceType.battery,
|
|
835
|
-
states: [
|
|
836
|
-
{
|
|
837
|
-
state: {id: 'battery.ratedCapacity', name: 'Rated Capacity', type: 'number', unit: 'Wh', role: 'value.capacity', desc: 'reg:37758, len:2'},
|
|
838
|
-
register: {reg: 37758, type: dataType.uint32}
|
|
839
|
-
},
|
|
840
|
-
{
|
|
841
|
-
state: {id: 'battery.SOC', name: 'State of capacity', type: 'number', unit: '%', role: 'value.battery', desc: 'reg:37760, len:1'},
|
|
842
|
-
register: {reg: 37760, type: dataType.uint16, gain: 10}
|
|
843
|
-
},
|
|
844
|
-
{
|
|
845
|
-
state: {id: 'battery.runningStatus', name: 'Running status', type: 'string', role: 'value', desc: 'reg:37762, len:1'},
|
|
846
|
-
register: {reg: 37762, type: dataType.uint16, length: 1},
|
|
847
|
-
mapper: value => Promise.resolve(batteryStatus[value])
|
|
848
|
-
},
|
|
849
|
-
{
|
|
850
|
-
state: {id: 'battery.busVoltage', name: 'Bus Voltage', type: 'number', unit: 'V', role: 'value.voltage', desc: 'reg:37763, len:1'},
|
|
851
|
-
register: {reg: 37763, type: dataType.uint16, gain: 10},
|
|
852
|
-
},
|
|
853
|
-
{
|
|
854
|
-
state: {id: 'battery.busCurrent', name: 'Bus Current', type: 'number', unit: 'A', role: 'value.current', desc: 'reg:37764, len:1'},
|
|
855
|
-
register: {reg: 37764, type: dataType.int16, gain: 10},
|
|
856
|
-
},
|
|
857
|
-
{
|
|
858
|
-
state: {id: 'battery.totalCharge', name: 'Total Charge', type: 'number', unit: 'kWh', role: 'value.power.consumption', desc: 'reg:37780, len:2'},
|
|
859
|
-
register: {reg: 37780, type: dataType.uint32, gain: 100}
|
|
860
|
-
},
|
|
861
|
-
{
|
|
862
|
-
state: {id: 'battery.totalDischarge', name: 'Total Discharge', type: 'number', unit: 'kWh', role: 'value.power.consumption', desc: 'reg:37782, len:2'},
|
|
863
|
-
register: {reg: 37782, type: dataType.uint32, gain: 100}
|
|
864
|
-
},
|
|
865
|
-
{
|
|
866
|
-
state: {id: 'battery.currentDayChargeCapacity', name: 'Current Day Charge Capacity', type: 'number', unit: 'kWh', role: 'value.power.consumption', desc: 'reg:37784, len:2' },
|
|
867
|
-
register: { reg: 37784, type: dataType.uint32, gain: 100 }
|
|
868
|
-
},
|
|
869
|
-
{
|
|
870
|
-
state: {id: 'battery.currentDayDischargeCapacity', name: 'Current Day Discharge Capacity', type: 'number', unit: 'kWh', role: 'value.power.consumption', desc: 'reg:37786, len:2' },
|
|
871
|
-
register: { reg: 37786, type: dataType.uint32, gain: 100 }
|
|
872
|
-
}
|
|
873
|
-
],
|
|
874
|
-
checkIfActive: () => this._batteryExists()
|
|
875
|
-
},
|
|
876
876
|
{
|
|
877
877
|
//https://photomate.zendesk.com/hc/en-gb/articles/5701625507485-Export-limitation-for-SUN2000-inverters-via-FusionSolar-App
|
|
878
878
|
address : 47415,
|
|
@@ -957,12 +957,6 @@ class InverterSun2000 extends DriverBase{
|
|
|
957
957
|
_batteryExists(unit=0,pack=0) {
|
|
958
958
|
if (unit === 0) {
|
|
959
959
|
return this.numberBatteryUnits() > 0;
|
|
960
|
-
/*
|
|
961
|
-
//if (!this.adapter.settings.ds.batteryUnits) return false;
|
|
962
|
-
const state1 = this.stateCache.get(this.deviceInfo.path+'.battery.unit.1.SN');
|
|
963
|
-
const state2 = this.stateCache.get(this.deviceInfo.path+'.battery.unit.2.SN');
|
|
964
|
-
return (state1 && state1.value) || (state2 && state2.value);
|
|
965
|
-
*/
|
|
966
960
|
} else {
|
|
967
961
|
if (pack === 0) {
|
|
968
962
|
const state = this.stateCache.get(`${this.deviceInfo.path}.battery.unit.${unit}.SN`);
|
|
@@ -971,11 +965,8 @@ class InverterSun2000 extends DriverBase{
|
|
|
971
965
|
} else {
|
|
972
966
|
const state = this.stateCache.get(`${this.deviceInfo.path}.battery.unit.${unit}.batteryPack.${pack}.SN`);
|
|
973
967
|
return this.adapter.settings.ds.batteryPacks && state && state.value;
|
|
974
|
-
//return state && state.value;
|
|
975
|
-
//return (state && 'test');
|
|
976
968
|
}
|
|
977
969
|
}
|
|
978
|
-
|
|
979
970
|
}
|
|
980
971
|
|
|
981
972
|
//overload
|
|
@@ -999,7 +990,7 @@ class InverterSun2000 extends DriverBase{
|
|
|
999
990
|
}
|
|
1000
991
|
if (modbusAllowed) {
|
|
1001
992
|
//430 = SUN2000-8KTL-M2
|
|
1002
|
-
if (this.deviceStatus === 0x0002 && this._modelId < 430) modbusAllowed = false;
|
|
993
|
+
//if (this.deviceStatus === 0x0002 && this._modelId < 430) modbusAllowed = false;
|
|
1003
994
|
if (this.deviceStatus >= 0x0300 && this.deviceStatus <= 0x0307 ) modbusAllowed = false; //shutdown
|
|
1004
995
|
//if (this._modelId < 430) modbusAllowed = this.deviceStatus !== 0x0002;
|
|
1005
996
|
if (this._errorCount > 3) modbusAllowed = false;
|
|
@@ -1012,7 +1003,7 @@ class InverterSun2000 extends DriverBase{
|
|
|
1012
1003
|
if (modbusAllowed && this.log.quiet) {
|
|
1013
1004
|
this.log.beQuiet(false);
|
|
1014
1005
|
this.log.info(`The inverter with modbus ID ${this._modbusId} is accessible again.`);
|
|
1015
|
-
this._errorCount = 0;
|
|
1006
|
+
//this._errorCount = 0;
|
|
1016
1007
|
}
|
|
1017
1008
|
this._modbusAllowed = modbusAllowed;
|
|
1018
1009
|
return this._modbusAllowed;
|
|
@@ -13,19 +13,17 @@ class ModbusServer {
|
|
|
13
13
|
|
|
14
14
|
//https://github.com/yaacov/node-modbus-serial/blob/master/ServerTCP.d.ts
|
|
15
15
|
this.vector = {
|
|
16
|
-
getInputRegister: (addr, unitId, callback) => {
|
|
17
|
-
this.
|
|
18
|
-
callback({ modbusErrorCode: 0x01, msg: 'Illegal function (device does not support this read/write function)' });
|
|
16
|
+
getInputRegister: async (addr, unitId, callback) => {
|
|
17
|
+
await this._handleGetReg('getInputRegister',addr, 1, unitId, callback);
|
|
19
18
|
},
|
|
20
19
|
getHoldingRegister: async (addr, unitId, callback) => {
|
|
21
|
-
await this._handleGetReg(addr, 1, unitId, callback);
|
|
20
|
+
await this._handleGetReg('getHoldingRegister',addr, 1, unitId, callback);
|
|
22
21
|
},
|
|
23
|
-
getMultipleInputRegisters: (startAddr, length,unitId, callback ) => {
|
|
24
|
-
this.
|
|
25
|
-
callback({ modbusErrorCode: 0x01, msg: 'Illegal function (device does not support this read/write function)' });
|
|
22
|
+
getMultipleInputRegisters: async (startAddr, length,unitId, callback ) => {
|
|
23
|
+
await this._handleGetReg('getMultipleInputRegisters',startAddr, length, unitId, callback);
|
|
26
24
|
},
|
|
27
25
|
getMultipleHoldingRegisters: async (startAddr, length, unitId, callback) => {
|
|
28
|
-
await this._handleGetReg(startAddr, length, unitId, callback);
|
|
26
|
+
await this._handleGetReg('getMultipleHoldingRegisters',startAddr, length, unitId, callback);
|
|
29
27
|
},
|
|
30
28
|
getCoil: (addr,unitId, callback) => {
|
|
31
29
|
this._addInfoStat('#getCoil',addr, 1 , unitId);
|
|
@@ -33,10 +31,10 @@ class ModbusServer {
|
|
|
33
31
|
},
|
|
34
32
|
//https://github.com/yaacov/node-modbus-serial/blob/cbd4379bed9672c13ec3a8517d622b728a737a5e/servers/servertcp_handler.js#L925C16-L925C32
|
|
35
33
|
setRegisterArray: async (addr, values, unitId, callback) => {
|
|
36
|
-
await this._handleSetReg(addr,values,unitId, callback);
|
|
34
|
+
await this._handleSetReg('setRegisterArray',addr,values,unitId, callback);
|
|
37
35
|
},
|
|
38
36
|
setRegister: async (addr, value,unitId, callback) => {
|
|
39
|
-
await this._handleSetReg(addr,value,unitId, callback);
|
|
37
|
+
await this._handleSetReg('setRegister',addr,value,unitId, callback);
|
|
40
38
|
},
|
|
41
39
|
setCoil: (addr, value, unitId, callback) => {
|
|
42
40
|
this._addInfoStat('#setCoil',addr, value, unitId);
|
|
@@ -138,7 +136,7 @@ class ModbusServer {
|
|
|
138
136
|
}
|
|
139
137
|
}
|
|
140
138
|
|
|
141
|
-
async _handleGetReg (startAddr, length, unitId, callback) {
|
|
139
|
+
async _handleGetReg (fnName,startAddr, length, unitId, callback) {
|
|
142
140
|
//this.adapter.log.debug('getMultipleHolgingRegisters '+unitId+' '+startAddr+' len '+length+' '+this._isConnected);
|
|
143
141
|
try {
|
|
144
142
|
const device = this.getDeviceInstance(unitId);
|
|
@@ -151,27 +149,27 @@ class ModbusServer {
|
|
|
151
149
|
callback({ modbusErrorCode: 0x05, msg: 'Acknowledge (requested data will be available later)' });
|
|
152
150
|
} else {
|
|
153
151
|
if (values[0] == null) {
|
|
154
|
-
this._addInfoStat('#
|
|
152
|
+
this._addInfoStat('#'+fnName,startAddr, length, unitId);
|
|
155
153
|
await this.wait(200);
|
|
156
154
|
} else {
|
|
157
|
-
this._addInfoStat(
|
|
155
|
+
this._addInfoStat(fnName,startAddr, length, unitId);
|
|
158
156
|
await this.wait(50);
|
|
159
157
|
}
|
|
160
158
|
callback(undefined,values);
|
|
161
159
|
}
|
|
162
160
|
} else {
|
|
163
|
-
this._addInfoStat('#
|
|
161
|
+
this._addInfoStat('#'+fnName,startAddr, length, unitId);
|
|
164
162
|
await this.wait(500);
|
|
165
163
|
callback({ modbusErrorCode: 0x01, msg: 'Illegal function (device does not support this read/write function)' });
|
|
166
164
|
}
|
|
167
|
-
} catch
|
|
168
|
-
this._addInfoStat('#
|
|
165
|
+
} catch {
|
|
166
|
+
this._addInfoStat('#'+fnName,startAddr, length, unitId);
|
|
169
167
|
await this.wait(500);
|
|
170
168
|
callback({ modbusErrorCode: 0x04, msg: 'Slave device failure (device reports internal error)' });
|
|
171
169
|
}
|
|
172
170
|
}
|
|
173
171
|
|
|
174
|
-
async _handleSetReg(address, data, unitId, callback) {
|
|
172
|
+
async _handleSetReg(fnName,address, data, unitId, callback) {
|
|
175
173
|
try {
|
|
176
174
|
this.log.debug('Modbus-proxy: Try to write data to id/address ' + unitId + '/' + address +'/'+ data);
|
|
177
175
|
const device = this.getDeviceInstance(unitId);
|
|
@@ -195,20 +193,20 @@ class ModbusServer {
|
|
|
195
193
|
await this.adapter.modbusClient.writeRegisters(address,data);
|
|
196
194
|
//write also to the read cache
|
|
197
195
|
device.addHoldingRegisters(address,data);
|
|
198
|
-
this._addInfoStat(
|
|
196
|
+
this._addInfoStat(fnName,address,data.length, unitId);
|
|
199
197
|
} else {
|
|
200
198
|
await this.adapter.modbusClient.writeRegister(address,data);
|
|
201
199
|
device.addHoldingRegisters(address,[data]);
|
|
202
|
-
this._addInfoStat(
|
|
200
|
+
this._addInfoStat(fnName,address,1, unitId);
|
|
203
201
|
}
|
|
204
202
|
callback();
|
|
205
203
|
} catch (err) {
|
|
206
204
|
this.log.warn('Modbus-proxy: can not write data to id/address ' + unitId + '/' + address +'/'+ data);
|
|
207
205
|
this.log.warn('Modbus-proxy: '+err?.message);
|
|
208
206
|
if (Array.isArray(data)) {
|
|
209
|
-
this._addInfoStat('#
|
|
207
|
+
this._addInfoStat('#'+fnName,address,data.length, unitId);
|
|
210
208
|
} else {
|
|
211
|
-
this._addInfoStat('#
|
|
209
|
+
this._addInfoStat('#'+fnName,address,1, unitId);
|
|
212
210
|
}
|
|
213
211
|
await this.wait(500);
|
|
214
212
|
callback({ modbusErrorCode: err?.modbusCode, msg: err?.message });
|
package/lib/register.js
CHANGED
|
@@ -219,10 +219,10 @@ class Registers {
|
|
|
219
219
|
for (const [i, reg] of device.instance.registerFields.entries()) {
|
|
220
220
|
if (!device.instance.modbusAllowed) continue; //standby
|
|
221
221
|
if (reg.type == deviceType.meter && !device?.meter) continue; //not meter
|
|
222
|
+
if (reg.type == deviceType.gridPowerControl && !device?.meter) continue; //power control v0.8.x
|
|
222
223
|
|
|
223
224
|
if (reg.checkIfActive && !reg.checkIfActive()) continue; //NEW, PATH
|
|
224
225
|
|
|
225
|
-
if (reg.type == deviceType.gridPowerControl && !device?.meter) continue; //power control v0.8.x
|
|
226
226
|
if (reg.states && reg.refresh) {
|
|
227
227
|
const lastread = reg.lastread;
|
|
228
228
|
const ret = {
|
package/main.js
CHANGED
|
@@ -320,7 +320,6 @@ class Sun2000 extends utils.Adapter {
|
|
|
320
320
|
this.config.integration = 1;
|
|
321
321
|
this.updateConfig(this.config);
|
|
322
322
|
}
|
|
323
|
-
|
|
324
323
|
await this.setState('info.ip', {val: this.config.address, ack: true});
|
|
325
324
|
await this.setState('info.port', {val: this.config.port, ack: true});
|
|
326
325
|
await this.setState('info.modbusIds', {val: this.config.modbusIds, ack: true});
|
|
@@ -339,6 +338,7 @@ class Sun2000 extends utils.Adapter {
|
|
|
339
338
|
this.settings.modbusIds = this.config.modbusIds.split(',').map((n) => {return Number(n);});
|
|
340
339
|
//SmartDongle
|
|
341
340
|
this.settings.sd.active = this.config.sd_active;
|
|
341
|
+
// eslint-disable-next-line no-constant-binary-expression
|
|
342
342
|
this.settings.sd.sDongleId = Number(this.config.sDongleId) ?? 0;
|
|
343
343
|
if (this.settings.sd.sDongleId < 0 || this.settings.sd.sDongleId >= 255) this.settings.sd.active = false;
|
|
344
344
|
this.settings.highInterval = this.config.updateInterval*1000; //ms
|
|
@@ -468,34 +468,36 @@ class Sun2000 extends utils.Adapter {
|
|
|
468
468
|
const sinceLastUpdate = new Date().getTime() - this.lastTimeUpdated; //ms
|
|
469
469
|
this.logger.debug('### Watchdog: time since last update '+sinceLastUpdate/1000+' sec');
|
|
470
470
|
const lastIsConnected = this.isConnected;
|
|
471
|
-
this.isConnected = this.lastStateUpdatedHigh > 0 && sinceLastUpdate < this.settings.highInterval*3;
|
|
471
|
+
//this.isConnected = this.lastStateUpdatedHigh > 0 && sinceLastUpdate < this.settings.highInterval*3;
|
|
472
|
+
this.isConnected = this.lastStateUpdatedHigh > 0 || this.lastStateUpdatedLow > 0;
|
|
473
|
+
|
|
472
474
|
if (this.isConnected !== lastIsConnected ) this.setState('info.connection', this.isConnected, true);
|
|
473
475
|
if (!this.settings.modbusAdjust) {
|
|
474
476
|
if (!this.isConnected) {
|
|
475
477
|
this.setState('info.JSONhealth', {val: '{errno:1, message: "Can\'t connect to inverter"}', ack: true});
|
|
476
478
|
}
|
|
477
479
|
const ret = this.state.CheckReadError(this.settings.lowInterval*2);
|
|
478
|
-
const obj = {...ret,modbus: {...this.modbusClient.info}};
|
|
479
480
|
this.logger.debug(JSON.stringify(this.modbusClient.info));
|
|
480
481
|
//v0.8.x
|
|
481
482
|
if (!this.isReady) this.isReady = this.isConnected && !ret.errno;
|
|
482
483
|
// after 2 Minutes
|
|
483
|
-
if (this.
|
|
484
|
+
if (this.toggleRunWatchDog) {
|
|
484
485
|
if (ret.errno) this.logger.warn(ret.message);
|
|
486
|
+
const obj = {...ret,modbus: {...this.modbusClient.info}};
|
|
485
487
|
this.setState('info.JSONhealth', {val: JSON.stringify(obj), ack: true});
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
488
|
+
}
|
|
489
|
+
if (this.modbusServer) {
|
|
490
|
+
!this.modbusServer.isConnected && this.modbusServer.connect();
|
|
491
|
+
if (this.settings.ms.log) {
|
|
492
|
+
//const stat = this.modbusServer.info?.stat;
|
|
493
|
+
//object is not empty
|
|
494
|
+
//if (Object.keys(stat).length > 0) this.log.info('Modbus tcp server: '+JSON.stringify(this.modbusServer.info));
|
|
495
|
+
this.logger.info('Modbus tcp server: '+JSON.stringify(this.modbusServer.info));
|
|
494
496
|
}
|
|
495
497
|
}
|
|
496
498
|
}
|
|
497
499
|
|
|
498
|
-
|
|
500
|
+
this.toggleRunWatchDog = !this.toggleRunWatchDog;
|
|
499
501
|
this.lastStateUpdatedLow = 0;
|
|
500
502
|
this.lastStateUpdatedHigh = 0;
|
|
501
503
|
|
|
@@ -527,7 +529,7 @@ class Sun2000 extends utils.Adapter {
|
|
|
527
529
|
this.modbusClient && this.modbusClient.close();
|
|
528
530
|
this.setState('info.connection', false, true);
|
|
529
531
|
callback();
|
|
530
|
-
} catch
|
|
532
|
+
} catch {
|
|
531
533
|
callback();
|
|
532
534
|
}
|
|
533
535
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iobroker.sun2000",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.1",
|
|
4
4
|
"description": "sun2000",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "bolliy",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"url": "https://github.com/bolliy/ioBroker.sun2000.git"
|
|
25
25
|
},
|
|
26
26
|
"engines": {
|
|
27
|
-
"node": ">= 18"
|
|
27
|
+
"node": ">= 18.18.0"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@iobroker/adapter-core": "^3.2.2",
|
|
@@ -37,6 +37,8 @@
|
|
|
37
37
|
"@alcalzone/release-script-plugin-iobroker": "^3.7.2",
|
|
38
38
|
"@alcalzone/release-script-plugin-license": "^3.7.0",
|
|
39
39
|
"@alcalzone/release-script-plugin-manual-review": "^3.7.0",
|
|
40
|
+
"@eslint/eslintrc": "^3.1.0",
|
|
41
|
+
"@eslint/js": "^9.14.0",
|
|
40
42
|
"@iobroker/adapter-dev": "^1.3.0",
|
|
41
43
|
"@iobroker/testing": "^5.0.0",
|
|
42
44
|
"@tsconfig/node16": "^16.1.3",
|
|
@@ -49,7 +51,8 @@
|
|
|
49
51
|
"@types/sinon-chai": "^3.2.12",
|
|
50
52
|
"chai": "^4.5.0",
|
|
51
53
|
"chai-as-promised": "^7.1.2",
|
|
52
|
-
"eslint": "^
|
|
54
|
+
"eslint": "^9.14.0",
|
|
55
|
+
"globals": "^15.11.0",
|
|
53
56
|
"mocha": "^10.8.2",
|
|
54
57
|
"proxyquire": "^2.1.3",
|
|
55
58
|
"sinon": "^19.0.2",
|