iobroker.sigenergy 2.2.4 → 2.2.7
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 +9 -25
- package/io-package.json +16 -13
- package/lib/registers.js +35 -25
- package/main.js +189 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -153,6 +153,15 @@ Status and power readings for the DC charger.
|
|
|
153
153
|
|
|
154
154
|
## Changelog
|
|
155
155
|
|
|
156
|
+
### 2.2.7 (2026-06-10)
|
|
157
|
+
- (ssbingo) fix: add missing native defaults enableSmartLoads/enableCumulativeEnergy/enableGridCode to io-package.json
|
|
158
|
+
- (ssbingo) fix: update register 30003 desc with V2.7 EMS modes 5 (FullFeedIn) and 9 (Custom)
|
|
159
|
+
|
|
160
|
+
### 2.2.6 (2026-06-10)
|
|
161
|
+
- (ssbingo) feat: V2.9 register audit — add missing register 30279 (current control command value), move DC Charger PV registers 31509/31511 to dcCharger namespace, fix ESS Preheating TOU time gain (null→1)
|
|
162
|
+
- (ssbingo) feat: implement control write-back for plant.control.*, plant.gridCode.*, inverter.control.*, dcCharger.control.* (FC06/FC10); read RW holding registers on startup
|
|
163
|
+
- (ssbingo) fix: suppress repeated ESS Preheating warn after device reports unsupported registers; downgrade control register startup read errors to debug
|
|
164
|
+
|
|
156
165
|
### 2.2.4 (2026-06-10)
|
|
157
166
|
- (ssbingo) fix: implement ESS Preheating TOU polling (FC03, 50000–50183, 94 registers) and write-back via onStateChange; add encodeValue to ModbusConnection
|
|
158
167
|
|
|
@@ -218,31 +227,6 @@ Status and power readings for the DC charger.
|
|
|
218
227
|
- (ssbingo) feat: added calculated states plant.pv1Power, plant.pv2Power, plant.pv3Power
|
|
219
228
|
|
|
220
229
|
|
|
221
|
-
### 1.9.6 (2026-04-16)
|
|
222
|
-
- (ssbingo) feat: added calculated states plant.pv1Power, plant.pv2Power, plant.pv3Power
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
### 1.9.5 (2026-04-08)
|
|
226
|
-
- (ssbingo) fix: removed unused common.schedule from io-package.json
|
|
227
|
-
|
|
228
|
-
### 1.9.4 (2026-04-08)
|
|
229
|
-
- (ssbingo) fix: Changelog / adding CHANGELOG_OLD.md
|
|
230
|
-
|
|
231
|
-
### 1.9.3 (2026-04-08)
|
|
232
|
-
- (ssbingo) fix remove admin/index.html
|
|
233
|
-
|
|
234
|
-
### 1.9.2 (2026-04-08)
|
|
235
|
-
- (ssbingo) fixes
|
|
236
|
-
|
|
237
|
-
### 1.9.1 (2026-04-08)
|
|
238
|
-
- (ssbingo) Fixed admin UI: removed legacy index.html/index_m.html/words.js; fixed jsonData type in jsonConfig sendTo buttons
|
|
239
|
-
|
|
240
|
-
### 1.9.0 (2026-03-26)
|
|
241
|
-
- (ssbingo) Test abgeschlossen
|
|
242
|
-
|
|
243
|
-
### 1.8.23 (2026-03-26)
|
|
244
|
-
- (ssbingo) Fixed copyright year to 2026 in LICENSE and README; technical corrections: CI/CD workflow, linting, tests
|
|
245
|
-
|
|
246
230
|
---
|
|
247
231
|
|
|
248
232
|
[Older changelogs can be found there](CHANGELOG_OLD.md)
|
package/io-package.json
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "sigenergy",
|
|
4
|
-
"version": "2.2.
|
|
4
|
+
"version": "2.2.7",
|
|
5
5
|
"news": {
|
|
6
|
-
"2.2.
|
|
7
|
-
"en": "(ssbingo) fix:
|
|
8
|
-
"de": "(ssbingo) fix:
|
|
9
|
-
"ru": "(ssbingo) fix:
|
|
10
|
-
"pt": "(ssbingo) fix:
|
|
11
|
-
"nl": "(ssbingo) fix:
|
|
12
|
-
"fr": "(ssbingo) fix:
|
|
13
|
-
"it": "(ssbingo) fix:
|
|
14
|
-
"es": "(ssbingo) fix:
|
|
15
|
-
"pl": "(ssbingo) fix:
|
|
16
|
-
"uk": "(ssbingo) fix:
|
|
17
|
-
"zh-cn": "(ssbingo) fix:
|
|
6
|
+
"2.2.7": {
|
|
7
|
+
"en": "(ssbingo) fix: add missing native defaults enableSmartLoads/enableCumulativeEnergy/enableGridCode to io-package.json; update register 30003 desc with V2.7 EMS modes 5 (FullFeedIn) and 9 (Custom)",
|
|
8
|
+
"de": "(ssbingo) fix: fehlende native-Defaults enableSmartLoads/enableCumulativeEnergy/enableGridCode in io-package.json ergänzt; Register 30003 Beschreibung um V2.7 EMS-Modi 5 (FullFeedIn) und 9 (Custom) erweitert",
|
|
9
|
+
"ru": "(ssbingo) fix: добавлены отсутствующие native-дефолты enableSmartLoads/enableCumulativeEnergy/enableGridCode в io-package.json; обновлено описание регистра 30003 с режимами EMS V2.7: 5 (FullFeedIn) и 9 (Custom)",
|
|
10
|
+
"pt": "(ssbingo) fix: defaults native enableSmartLoads/enableCumulativeEnergy/enableGridCode adicionados ao io-package.json; descrição do registo 30003 atualizada com modos EMS V2.7 5 (FullFeedIn) e 9 (Custom)",
|
|
11
|
+
"nl": "(ssbingo) fix: ontbrekende native-standaarden enableSmartLoads/enableCumulativeEnergy/enableGridCode toegevoegd aan io-package.json; beschrijving register 30003 bijgewerkt met V2.7 EMS-modi 5 (FullFeedIn) en 9 (Custom)",
|
|
12
|
+
"fr": "(ssbingo) fix: defaults native enableSmartLoads/enableCumulativeEnergy/enableGridCode ajoutés à io-package.json ; description registre 30003 mise à jour avec modes EMS V2.7 5 (FullFeedIn) et 9 (Custom)",
|
|
13
|
+
"it": "(ssbingo) fix: default native enableSmartLoads/enableCumulativeEnergy/enableGridCode aggiunti a io-package.json; descrizione registro 30003 aggiornata con modalità EMS V2.7 5 (FullFeedIn) e 9 (Custom)",
|
|
14
|
+
"es": "(ssbingo) fix: defaults native enableSmartLoads/enableCumulativeEnergy/enableGridCode añadidos a io-package.json; descripción del registro 30003 actualizada con modos EMS V2.7 5 (FullFeedIn) y 9 (Custom)",
|
|
15
|
+
"pl": "(ssbingo) fix: brakujące domyślne native enableSmartLoads/enableCumulativeEnergy/enableGridCode dodane do io-package.json; opis rejestru 30003 zaktualizowany o tryby EMS V2.7 5 (FullFeedIn) i 9 (Custom)",
|
|
16
|
+
"uk": "(ssbingo) fix: відсутні native-дефолти enableSmartLoads/enableCumulativeEnergy/enableGridCode додано до io-package.json; опис регістру 30003 оновлено з режимами EMS V2.7 5 (FullFeedIn) та 9 (Custom)",
|
|
17
|
+
"zh-cn": "(ssbingo) fix: 在 io-package.json 中添加缺失的 native 默认值 enableSmartLoads/enableCumulativeEnergy/enableGridCode;更新寄存器 30003 描述以包含 V2.7 EMS 模式 5(完全并网)和 9(自定义)"
|
|
18
18
|
}
|
|
19
19
|
},
|
|
20
20
|
"titleLang": {
|
|
@@ -121,6 +121,9 @@
|
|
|
121
121
|
"sigenMicroScanFrom": 10,
|
|
122
122
|
"sigenMicroScanTo": 30,
|
|
123
123
|
"sigenMicroDevices": "[]",
|
|
124
|
+
"enableSmartLoads": false,
|
|
125
|
+
"enableCumulativeEnergy": false,
|
|
126
|
+
"enableGridCode": false,
|
|
124
127
|
"enablePss": false,
|
|
125
128
|
"pssSlaveId": 5,
|
|
126
129
|
"enablePid": false,
|
package/lib/registers.js
CHANGED
|
@@ -37,7 +37,7 @@ const PLANT_READ_REGISTERS = [
|
|
|
37
37
|
gain: null,
|
|
38
38
|
unit: '',
|
|
39
39
|
role: 'value',
|
|
40
|
-
desc: 'EMS work mode: 0=MaxSelfConsumption,1=AI,2=TOU,7=RemoteEMS',
|
|
40
|
+
desc: 'EMS work mode: 0=MaxSelfConsumption,1=AI,2=TOU,5=FullFeedIn,7=RemoteEMS,9=Custom',
|
|
41
41
|
},
|
|
42
42
|
{
|
|
43
43
|
addr: 30004,
|
|
@@ -1294,6 +1294,16 @@ const PLANT_READ_REGISTERS = [
|
|
|
1294
1294
|
role: 'value.voltage',
|
|
1295
1295
|
desc: 'Grid code rated voltage (V2.9)',
|
|
1296
1296
|
},
|
|
1297
|
+
{
|
|
1298
|
+
addr: 30279,
|
|
1299
|
+
qty: 1,
|
|
1300
|
+
name: 'plant.currentCtrlCmdValue',
|
|
1301
|
+
type: 'U16',
|
|
1302
|
+
gain: 100,
|
|
1303
|
+
unit: '%',
|
|
1304
|
+
role: 'value',
|
|
1305
|
+
desc: 'Current control command value (V2.8)',
|
|
1306
|
+
},
|
|
1297
1307
|
{
|
|
1298
1308
|
addr: 30280,
|
|
1299
1309
|
qty: 1,
|
|
@@ -2529,27 +2539,6 @@ const INVERTER_READ_REGISTERS = [
|
|
|
2529
2539
|
role: 'value',
|
|
2530
2540
|
desc: 'Power factor adjustment feedback (V2.6)',
|
|
2531
2541
|
},
|
|
2532
|
-
// V2.6 — separate FC04 group (gap > 4 from 31041)
|
|
2533
|
-
{
|
|
2534
|
-
addr: 31509,
|
|
2535
|
-
qty: 2,
|
|
2536
|
-
name: 'inverter.pvDailyGeneration',
|
|
2537
|
-
type: 'U32',
|
|
2538
|
-
gain: 100,
|
|
2539
|
-
unit: 'kWh',
|
|
2540
|
-
role: 'value.energy',
|
|
2541
|
-
desc: 'PV daily generation (V2.6)',
|
|
2542
|
-
},
|
|
2543
|
-
{
|
|
2544
|
-
addr: 31511,
|
|
2545
|
-
qty: 2,
|
|
2546
|
-
name: 'inverter.pvTotalGeneration',
|
|
2547
|
-
type: 'U32',
|
|
2548
|
-
gain: 100,
|
|
2549
|
-
unit: 'kWh',
|
|
2550
|
-
role: 'value.energy',
|
|
2551
|
-
desc: 'PV total generation (V2.6)',
|
|
2552
|
-
},
|
|
2553
2542
|
];
|
|
2554
2543
|
|
|
2555
2544
|
// ============================================================
|
|
@@ -2849,7 +2838,28 @@ const DC_CHARGER_READ_REGISTERS = [
|
|
|
2849
2838
|
role: 'value.time',
|
|
2850
2839
|
desc: 'Current charging duration (single session)',
|
|
2851
2840
|
},
|
|
2852
|
-
// V2.
|
|
2841
|
+
// V2.6 — PV generation (DC Charger only, gap of 1 from 31508)
|
|
2842
|
+
{
|
|
2843
|
+
addr: 31509,
|
|
2844
|
+
qty: 2,
|
|
2845
|
+
name: 'dcCharger.pvDailyGeneration',
|
|
2846
|
+
type: 'U32',
|
|
2847
|
+
gain: 100,
|
|
2848
|
+
unit: 'kWh',
|
|
2849
|
+
role: 'value.energy',
|
|
2850
|
+
desc: '[DC Charger] PV daily generation (V2.6)',
|
|
2851
|
+
},
|
|
2852
|
+
{
|
|
2853
|
+
addr: 31511,
|
|
2854
|
+
qty: 2,
|
|
2855
|
+
name: 'dcCharger.pvTotalGeneration',
|
|
2856
|
+
type: 'U32',
|
|
2857
|
+
gain: 100,
|
|
2858
|
+
unit: 'kWh',
|
|
2859
|
+
role: 'value.energy',
|
|
2860
|
+
desc: '[DC Charger] PV total generation (V2.6)',
|
|
2861
|
+
},
|
|
2862
|
+
// V2.8/V2.9 — separate FC04 group (gap of 1 from 31512)
|
|
2853
2863
|
{
|
|
2854
2864
|
addr: 31513,
|
|
2855
2865
|
qty: 1,
|
|
@@ -4559,7 +4569,7 @@ const ESS_PREHEATING_WRITE_REGISTERS = (() => {
|
|
|
4559
4569
|
qty: 2,
|
|
4560
4570
|
name: `plant.essPreheating.tou${n}.startTime`,
|
|
4561
4571
|
type: 'U32',
|
|
4562
|
-
gain:
|
|
4572
|
+
gain: 1,
|
|
4563
4573
|
unit: 's',
|
|
4564
4574
|
perm: 'RW',
|
|
4565
4575
|
desc: `TOU ${n} start time`,
|
|
@@ -4569,7 +4579,7 @@ const ESS_PREHEATING_WRITE_REGISTERS = (() => {
|
|
|
4569
4579
|
qty: 2,
|
|
4570
4580
|
name: `plant.essPreheating.tou${n}.endTime`,
|
|
4571
4581
|
type: 'U32',
|
|
4572
|
-
gain:
|
|
4582
|
+
gain: 1,
|
|
4573
4583
|
unit: 's',
|
|
4574
4584
|
perm: 'RW',
|
|
4575
4585
|
desc: `TOU ${n} end time`,
|
package/main.js
CHANGED
|
@@ -17,6 +17,9 @@ const {
|
|
|
17
17
|
PSS_READ_REGISTERS,
|
|
18
18
|
PID_READ_REGISTERS,
|
|
19
19
|
ESS_PREHEATING_WRITE_REGISTERS,
|
|
20
|
+
PLANT_WRITE_REGISTERS,
|
|
21
|
+
INVERTER_WRITE_REGISTERS,
|
|
22
|
+
DC_CHARGER_WRITE_REGISTERS,
|
|
20
23
|
} = require('./lib/registers');
|
|
21
24
|
const SigenMicroScanner = require('./lib/scanner');
|
|
22
25
|
const { getRegistersForDevice } = require('./lib/sigenMicroRegisters');
|
|
@@ -42,6 +45,8 @@ class Sigenergy extends utils.Adapter {
|
|
|
42
45
|
// (modbus reads, scans, setTimeout-chains) can abort gracefully instead of
|
|
43
46
|
// calling setStateAsync on a stopped adapter.
|
|
44
47
|
this._stopped = false;
|
|
48
|
+
this._controlRegistersRead = false;
|
|
49
|
+
this._essPreheatingUnsupported = false;
|
|
45
50
|
|
|
46
51
|
this.on('ready', this.onReady.bind(this));
|
|
47
52
|
this.on('stateChange', this.onStateChange.bind(this));
|
|
@@ -224,6 +229,11 @@ class Sigenergy extends utils.Adapter {
|
|
|
224
229
|
this.log.debug('[poll] cycle started');
|
|
225
230
|
|
|
226
231
|
try {
|
|
232
|
+
if (!this._controlRegistersRead) {
|
|
233
|
+
await this._readControlRegisters();
|
|
234
|
+
this._controlRegistersRead = true;
|
|
235
|
+
}
|
|
236
|
+
|
|
227
237
|
const _t0 = Date.now();
|
|
228
238
|
await this._readPlant();
|
|
229
239
|
if (this._stopped) {
|
|
@@ -442,11 +452,18 @@ class Sigenergy extends utils.Adapter {
|
|
|
442
452
|
}
|
|
443
453
|
|
|
444
454
|
async _readEssPreheating() {
|
|
455
|
+
if (this._essPreheatingUnsupported) {
|
|
456
|
+
this.log.debug(
|
|
457
|
+
'[essPreheating] Skipping — registers not supported by device (disable in adapter settings)',
|
|
458
|
+
);
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
445
461
|
const plantId = this.config.plantId || 247;
|
|
446
462
|
const batchSize = 50;
|
|
447
463
|
const groups = this._buildReadGroups(ESS_PREHEATING_WRITE_REGISTERS, batchSize);
|
|
448
464
|
this.log.debug(`Reading ESS Preheating (slaveId=${plantId}): ${groups.length} group(s)`);
|
|
449
465
|
|
|
466
|
+
let failCount = 0;
|
|
450
467
|
for (const group of groups) {
|
|
451
468
|
if (this._stopped) {
|
|
452
469
|
return;
|
|
@@ -457,7 +474,71 @@ class Sigenergy extends utils.Adapter {
|
|
|
457
474
|
await this._processReadGroup(group, raw, 'essPreheating');
|
|
458
475
|
await this._sleep(100);
|
|
459
476
|
} catch (err) {
|
|
460
|
-
|
|
477
|
+
failCount++;
|
|
478
|
+
this.log.debug(`[essPreheating] read error at ${group.startAddr}: ${err.message}`);
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
if (failCount === groups.length && groups.length > 0) {
|
|
482
|
+
this._essPreheatingUnsupported = true;
|
|
483
|
+
this.log.warn(
|
|
484
|
+
'ESS Preheating: all register groups failed (Modbus exception 2 — device does not support these registers). ' +
|
|
485
|
+
'Polling disabled for this session. Disable "ESS Preheating" in adapter settings to suppress this message.',
|
|
486
|
+
);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
async _readControlRegisters() {
|
|
491
|
+
const plantId = this.config.plantId || 247;
|
|
492
|
+
const inverterId = this.config.inverterId || 1;
|
|
493
|
+
this.log.debug('[controlRegs] Reading RW holding registers (one-time on startup)');
|
|
494
|
+
|
|
495
|
+
const plantRw = PLANT_WRITE_REGISTERS.filter(r => r.perm === 'RW' && (!r.feature || this.config[r.feature]));
|
|
496
|
+
if (plantRw.length > 0) {
|
|
497
|
+
for (const group of this._buildReadGroups(plantRw, 50)) {
|
|
498
|
+
if (this._stopped) {
|
|
499
|
+
return;
|
|
500
|
+
}
|
|
501
|
+
try {
|
|
502
|
+
const raw = await this.modbus.readHoldingRegisters(plantId, group.startAddr, group.totalQty);
|
|
503
|
+
await this._processReadGroup(group, raw, 'control');
|
|
504
|
+
await this._sleep(100);
|
|
505
|
+
} catch (err) {
|
|
506
|
+
this.log.debug(`[controlRegs] plant addr=${group.startAddr}: ${err.message}`);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
const invRw = INVERTER_WRITE_REGISTERS.filter(r => r.perm === 'RW');
|
|
512
|
+
if (invRw.length > 0) {
|
|
513
|
+
for (const group of this._buildReadGroups(invRw, 50)) {
|
|
514
|
+
if (this._stopped) {
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
try {
|
|
518
|
+
const raw = await this.modbus.readHoldingRegisters(inverterId, group.startAddr, group.totalQty);
|
|
519
|
+
await this._processReadGroup(group, raw, 'control');
|
|
520
|
+
await this._sleep(100);
|
|
521
|
+
} catch (err) {
|
|
522
|
+
this.log.debug(`[controlRegs] inverter addr=${group.startAddr}: ${err.message}`);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
if (this.config.hasDcCharger) {
|
|
528
|
+
const dcRw = DC_CHARGER_WRITE_REGISTERS.filter(r => r.perm === 'RW');
|
|
529
|
+
if (dcRw.length > 0) {
|
|
530
|
+
for (const group of this._buildReadGroups(dcRw, 50)) {
|
|
531
|
+
if (this._stopped) {
|
|
532
|
+
return;
|
|
533
|
+
}
|
|
534
|
+
try {
|
|
535
|
+
const raw = await this.modbus.readHoldingRegisters(inverterId, group.startAddr, group.totalQty);
|
|
536
|
+
await this._processReadGroup(group, raw, 'control');
|
|
537
|
+
await this._sleep(100);
|
|
538
|
+
} catch (err) {
|
|
539
|
+
this.log.debug(`[controlRegs] dcCharger addr=${group.startAddr}: ${err.message}`);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
461
542
|
}
|
|
462
543
|
}
|
|
463
544
|
}
|
|
@@ -693,6 +774,25 @@ class Sigenergy extends utils.Adapter {
|
|
|
693
774
|
await this._createStateFromRegister(reg);
|
|
694
775
|
}
|
|
695
776
|
|
|
777
|
+
// Plant control write states
|
|
778
|
+
await this._createChannel('plant.control', 'Plant Control');
|
|
779
|
+
if (this.config.enableGridCode) {
|
|
780
|
+
await this._createChannel('plant.gridCode', 'Grid Code Parameters');
|
|
781
|
+
}
|
|
782
|
+
for (const reg of PLANT_WRITE_REGISTERS) {
|
|
783
|
+
if (this._stopped) {
|
|
784
|
+
return;
|
|
785
|
+
}
|
|
786
|
+
if (reg.feature && !this.config[reg.feature]) {
|
|
787
|
+
continue;
|
|
788
|
+
}
|
|
789
|
+
await this._createWriteStateFromRegister(reg);
|
|
790
|
+
}
|
|
791
|
+
this.subscribeStates('plant.control.*');
|
|
792
|
+
if (this.config.enableGridCode) {
|
|
793
|
+
this.subscribeStates('plant.gridCode.*');
|
|
794
|
+
}
|
|
795
|
+
|
|
696
796
|
// Virtual PV string power states (calculated from voltage × current)
|
|
697
797
|
for (const pvState of [
|
|
698
798
|
{ id: 'plant.pv1Power', desc: 'PV string 1 power' },
|
|
@@ -723,6 +823,16 @@ class Sigenergy extends utils.Adapter {
|
|
|
723
823
|
await this._createStateFromRegister(reg);
|
|
724
824
|
}
|
|
725
825
|
|
|
826
|
+
// Inverter control write states
|
|
827
|
+
await this._createChannel('inverter.control', 'Inverter Control');
|
|
828
|
+
for (const reg of INVERTER_WRITE_REGISTERS) {
|
|
829
|
+
if (this._stopped) {
|
|
830
|
+
return;
|
|
831
|
+
}
|
|
832
|
+
await this._createWriteStateFromRegister(reg);
|
|
833
|
+
}
|
|
834
|
+
this.subscribeStates('inverter.control.*');
|
|
835
|
+
|
|
726
836
|
if (this.config.hasAcCharger) {
|
|
727
837
|
this.log.debug('Creating AC charger objects');
|
|
728
838
|
await this._createChannel('acCharger', 'AC Charger');
|
|
@@ -743,6 +853,14 @@ class Sigenergy extends utils.Adapter {
|
|
|
743
853
|
}
|
|
744
854
|
await this._createStateFromRegister(reg);
|
|
745
855
|
}
|
|
856
|
+
await this._createChannel('dcCharger.control', 'DC Charger Control');
|
|
857
|
+
for (const reg of DC_CHARGER_WRITE_REGISTERS) {
|
|
858
|
+
if (this._stopped) {
|
|
859
|
+
return;
|
|
860
|
+
}
|
|
861
|
+
await this._createWriteStateFromRegister(reg);
|
|
862
|
+
}
|
|
863
|
+
this.subscribeStates('dcCharger.control.*');
|
|
746
864
|
}
|
|
747
865
|
|
|
748
866
|
if (this.config.hasSigenMicro) {
|
|
@@ -861,6 +979,27 @@ class Sigenergy extends utils.Adapter {
|
|
|
861
979
|
});
|
|
862
980
|
}
|
|
863
981
|
|
|
982
|
+
async _createWriteStateFromRegister(reg) {
|
|
983
|
+
const type = reg.type === 'STRING' ? 'string' : 'number';
|
|
984
|
+
await this.setObjectNotExistsAsync(reg.name, {
|
|
985
|
+
type: 'state',
|
|
986
|
+
common: {
|
|
987
|
+
name: reg.desc,
|
|
988
|
+
type,
|
|
989
|
+
role: 'value',
|
|
990
|
+
unit: reg.unit || '',
|
|
991
|
+
read: reg.perm === 'RW',
|
|
992
|
+
write: true,
|
|
993
|
+
},
|
|
994
|
+
native: {
|
|
995
|
+
addr: reg.addr,
|
|
996
|
+
qty: reg.qty,
|
|
997
|
+
dataType: reg.type,
|
|
998
|
+
gain: reg.gain,
|
|
999
|
+
},
|
|
1000
|
+
});
|
|
1001
|
+
}
|
|
1002
|
+
|
|
864
1003
|
/**
|
|
865
1004
|
* Create ioBroker objects for all active SigenMicro devices
|
|
866
1005
|
*/
|
|
@@ -978,27 +1117,68 @@ class Sigenergy extends utils.Adapter {
|
|
|
978
1117
|
if (!state || state.ack) {
|
|
979
1118
|
return;
|
|
980
1119
|
}
|
|
981
|
-
|
|
1120
|
+
if (!this.modbus || !this.modbus.connected) {
|
|
1121
|
+
this.log.warn(`Cannot write state ${id}: Modbus not connected`);
|
|
1122
|
+
return;
|
|
1123
|
+
}
|
|
982
1124
|
const localId = id.replace(/^[^.]+\.\d+\./, '');
|
|
983
|
-
|
|
1125
|
+
|
|
1126
|
+
// ESS Preheating writes (FC03/FC10)
|
|
1127
|
+
if (localId.startsWith('plant.essPreheating.')) {
|
|
1128
|
+
const reg = ESS_PREHEATING_WRITE_REGISTERS.find(r => r.name === localId);
|
|
1129
|
+
if (!reg) {
|
|
1130
|
+
return;
|
|
1131
|
+
}
|
|
1132
|
+
const plantId = this.config.plantId || 247;
|
|
1133
|
+
const raw = ModbusConnection.encodeValue(state.val, reg.type, reg.gain);
|
|
1134
|
+
try {
|
|
1135
|
+
if (raw.length === 1) {
|
|
1136
|
+
await this.modbus.writeSingleRegister(plantId, reg.addr, raw[0]);
|
|
1137
|
+
} else {
|
|
1138
|
+
await this.modbus.writeMultipleRegisters(plantId, reg.addr, raw);
|
|
1139
|
+
}
|
|
1140
|
+
await this.setStateAsync(id, { val: state.val, ack: true });
|
|
1141
|
+
this.log.debug(`[essPreheating] wrote ${localId} = ${state.val} → addr ${reg.addr}`);
|
|
1142
|
+
} catch (err) {
|
|
1143
|
+
this.log.error(`ESS Preheating write error for ${localId}: ${err.message}`);
|
|
1144
|
+
}
|
|
984
1145
|
return;
|
|
985
1146
|
}
|
|
986
|
-
|
|
1147
|
+
|
|
1148
|
+
// Plant / Inverter / DC Charger control register writes
|
|
1149
|
+
let reg = null;
|
|
1150
|
+
let slaveId = null;
|
|
1151
|
+
let category = '';
|
|
1152
|
+
|
|
1153
|
+
if (localId.startsWith('plant.control.') || localId.startsWith('plant.gridCode.')) {
|
|
1154
|
+
reg = PLANT_WRITE_REGISTERS.find(r => r.name === localId);
|
|
1155
|
+
slaveId = this.config.plantId || 247;
|
|
1156
|
+
category = 'plant';
|
|
1157
|
+
} else if (localId.startsWith('inverter.control.')) {
|
|
1158
|
+
reg = INVERTER_WRITE_REGISTERS.find(r => r.name === localId);
|
|
1159
|
+
slaveId = this.config.inverterId || 1;
|
|
1160
|
+
category = 'inverter';
|
|
1161
|
+
} else if (localId.startsWith('dcCharger.control.')) {
|
|
1162
|
+
reg = DC_CHARGER_WRITE_REGISTERS.find(r => r.name === localId);
|
|
1163
|
+
slaveId = this.config.inverterId || 1;
|
|
1164
|
+
category = 'dcCharger';
|
|
1165
|
+
}
|
|
1166
|
+
|
|
987
1167
|
if (!reg) {
|
|
988
1168
|
return;
|
|
989
1169
|
}
|
|
990
|
-
|
|
1170
|
+
|
|
991
1171
|
const raw = ModbusConnection.encodeValue(state.val, reg.type, reg.gain);
|
|
992
1172
|
try {
|
|
993
1173
|
if (raw.length === 1) {
|
|
994
|
-
await this.modbus.writeSingleRegister(
|
|
1174
|
+
await this.modbus.writeSingleRegister(slaveId, reg.addr, raw[0]);
|
|
995
1175
|
} else {
|
|
996
|
-
await this.modbus.writeMultipleRegisters(
|
|
1176
|
+
await this.modbus.writeMultipleRegisters(slaveId, reg.addr, raw);
|
|
997
1177
|
}
|
|
998
1178
|
await this.setStateAsync(id, { val: state.val, ack: true });
|
|
999
|
-
this.log.debug(`[
|
|
1179
|
+
this.log.debug(`[${category}] wrote ${localId} = ${state.val} → addr ${reg.addr} slave ${slaveId}`);
|
|
1000
1180
|
} catch (err) {
|
|
1001
|
-
this.log.error(`
|
|
1181
|
+
this.log.error(`Control register write error for ${localId}: ${err.message}`);
|
|
1002
1182
|
}
|
|
1003
1183
|
}
|
|
1004
1184
|
|