iobroker.sigenergy 2.2.3 → 2.2.4

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 CHANGED
@@ -153,6 +153,9 @@ Status and power readings for the DC charger.
153
153
 
154
154
  ## Changelog
155
155
 
156
+ ### 2.2.4 (2026-06-10)
157
+ - (ssbingo) fix: implement ESS Preheating TOU polling (FC03, 50000–50183, 94 registers) and write-back via onStateChange; add encodeValue to ModbusConnection
158
+
156
159
  ### 2.2.3 (2026-06-10)
157
160
  - (ssbingo) fix: add 25 missing admin i18n keys for PSS, PID, ESS Preheating, Extended Registers across all 11 languages
158
161
 
package/io-package.json CHANGED
@@ -1,20 +1,20 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "sigenergy",
4
- "version": "2.2.3",
4
+ "version": "2.2.4",
5
5
  "news": {
6
- "2.2.3": {
7
- "en": "(ssbingo) fix: add 25 missing admin i18n keys for PSS, PID, ESS Preheating, Extended Registers, Smart Loads, Grid Code across all 11 languages",
8
- "de": "(ssbingo) fix: 25 fehlende Admin-i18n-Schlüssel für PSS, PID, ESS-Vorheizung, Erweiterte Register, Smart Loads, Netzcode in allen 11 Sprachen ergänzt",
9
- "ru": "(ssbingo) fix: добавлены 25 отсутствующих ключей i18n для PSS, PID, предварительного нагрева ESS, расширенных регистров, умных нагрузок, кода сети во всех 11 языках",
10
- "pt": "(ssbingo) fix: adicionadas 25 chaves i18n em falta para PSS, PID, pré-aquecimento ESS, registos alargados, cargas inteligentes, código de rede em todos os 11 idiomas",
11
- "nl": "(ssbingo) fix: 25 ontbrekende i18n-sleutels toegevoegd voor PSS, PID, ESS-voorverwarming, uitgebreide registers, slimme verbruikers, netcodes in alle 11 talen",
12
- "fr": "(ssbingo) fix: ajout de 25 clés i18n manquantes pour PSS, PID, préchauffage ESS, registres étendus, charges intelligentes, code réseau dans les 11 langues",
13
- "it": "(ssbingo) fix: aggiunte 25 chiavi i18n mancanti per PSS, PID, preriscaldamento ESS, registri estesi, carichi intelligenti, codice rete in tutte le 11 lingue",
14
- "es": "(ssbingo) fix: añadidas 25 claves i18n faltantes para PSS, PID, precalentamiento ESS, registros extendidos, cargas inteligentes, código de red en los 11 idiomas",
15
- "pl": "(ssbingo) fix: dodano 25 brakujących kluczy i18n dla PSS, PID, podgrzewania ESS, rejestrów rozszerzonych, inteligentnych obciążeń, kodu sieci we wszystkich 11 językach",
16
- "uk": "(ssbingo) fix: додано 25 відсутніх ключів i18n для PSS, PID, нагрівання ESS, розширених регістрів, розумних навантажень, коду мережі у всіх 11 мовах",
17
- "zh-cn": "(ssbingo) fix: PSS、PID、ESS 预热、扩展寄存器、智能负载、电网规格在所有 11 种语言中添加 25 个缺失的 i18n "
6
+ "2.2.4": {
7
+ "en": "(ssbingo) fix: implement ESS Preheating TOU read (FC03 registers 50000–50183) and write-back; 94 states with read+write; subscribe to state changes",
8
+ "de": "(ssbingo) fix: ESS-Vorheizung TOU-Lesen (FC03 Register 50000–50183) und Rückschreiben implementiert; 94 States mit read+write; Zustandsänderungen werden abonniert",
9
+ "ru": "(ssbingo) fix: реализовано чтение TOU предварительного нагрева ESS (FC03 регистры 50000–50183) и запись; 94 состояния read+write",
10
+ "pt": "(ssbingo) fix: implementada leitura TOU de pré-aquecimento ESS (FC03 registos 50000–50183) e escrita; 94 estados read+write",
11
+ "nl": "(ssbingo) fix: ESS-voorverwarming TOU lezen (FC03 registers 50000–50183) en terugschrijven geïmplementeerd; 94 states read+write",
12
+ "fr": "(ssbingo) fix: lecture TOU préchauffage ESS (FC03 registres 50000–50183) et écriture implémentées; 94 états read+write",
13
+ "it": "(ssbingo) fix: implementata lettura TOU preriscaldamento ESS (FC03 registri 50000–50183) e scrittura; 94 stati read+write",
14
+ "es": "(ssbingo) fix: implementada lectura TOU precalentamiento ESS (FC03 registros 50000–50183) y escritura; 94 estados read+write",
15
+ "pl": "(ssbingo) fix: zaimplementowano odczyt TOU podgrzewania ESS (FC03 rejestry 50000–50183) i zapis; 94 stany read+write",
16
+ "uk": "(ssbingo) fix: реалізовано читання TOU попереднього нагрівання ESS (FC03 регістри 50000–50183) та запис; 94 стани read+write",
17
+ "zh-cn": "(ssbingo) fix: 实现 ESS 预热 TOU 读取(FC03 寄存器 50000–50183)和写回;94 read+write 状态"
18
18
  }
19
19
  },
20
20
  "titleLang": {
package/lib/modbus.js CHANGED
@@ -244,6 +244,26 @@ class ModbusConnection {
244
244
  * @param {number|null} gain - Scaling factor
245
245
  * @returns {number|string} Decoded value
246
246
  */
247
+ static encodeValue(value, type, gain) {
248
+ const raw = gain && gain !== 1 ? Math.round(value * gain) : Math.round(value);
249
+ switch (type) {
250
+ case 'U16':
251
+ return [raw & 0xffff];
252
+ case 'S16':
253
+ return [raw < 0 ? (raw + 65536) & 0xffff : raw & 0xffff];
254
+ case 'U32': {
255
+ const u = raw >>> 0;
256
+ return [(u >>> 16) & 0xffff, u & 0xffff];
257
+ }
258
+ case 'S32': {
259
+ const u32 = (raw < 0 ? raw + 4294967296 : raw) >>> 0;
260
+ return [(u32 >>> 16) & 0xffff, u32 & 0xffff];
261
+ }
262
+ default:
263
+ return [raw & 0xffff];
264
+ }
265
+ }
266
+
247
267
  static parseValue(rawData, type, gain) {
248
268
  let raw;
249
269
 
package/main.js CHANGED
@@ -16,6 +16,7 @@ const {
16
16
  AC_CHARGER_READ_REGISTERS,
17
17
  PSS_READ_REGISTERS,
18
18
  PID_READ_REGISTERS,
19
+ ESS_PREHEATING_WRITE_REGISTERS,
19
20
  } = require('./lib/registers');
20
21
  const SigenMicroScanner = require('./lib/scanner');
21
22
  const { getRegistersForDevice } = require('./lib/sigenMicroRegisters');
@@ -43,6 +44,7 @@ class Sigenergy extends utils.Adapter {
43
44
  this._stopped = false;
44
45
 
45
46
  this.on('ready', this.onReady.bind(this));
47
+ this.on('stateChange', this.onStateChange.bind(this));
46
48
  this.on('message', this.onMessage.bind(this));
47
49
  this.on('unload', this.onUnload.bind(this));
48
50
  }
@@ -263,6 +265,12 @@ class Sigenergy extends utils.Adapter {
263
265
  return;
264
266
  }
265
267
  }
268
+ if (this.config.enableEssPreheating) {
269
+ await this._readEssPreheating();
270
+ if (this._stopped) {
271
+ return;
272
+ }
273
+ }
266
274
 
267
275
  await this._updateStatistics();
268
276
  await this._updatePvStringPowers();
@@ -433,6 +441,27 @@ class Sigenergy extends utils.Adapter {
433
441
  }
434
442
  }
435
443
 
444
+ async _readEssPreheating() {
445
+ const plantId = this.config.plantId || 247;
446
+ const batchSize = 50;
447
+ const groups = this._buildReadGroups(ESS_PREHEATING_WRITE_REGISTERS, batchSize);
448
+ this.log.debug(`Reading ESS Preheating (slaveId=${plantId}): ${groups.length} group(s)`);
449
+
450
+ for (const group of groups) {
451
+ if (this._stopped) {
452
+ return;
453
+ }
454
+ try {
455
+ this.log.debug(`[essPreheating] FC03 addr=${group.startAddr} qty=${group.totalQty}`);
456
+ const raw = await this.modbus.readHoldingRegisters(plantId, group.startAddr, group.totalQty);
457
+ await this._processReadGroup(group, raw, 'essPreheating');
458
+ await this._sleep(100);
459
+ } catch (err) {
460
+ this.log.warn(`ESS Preheating read error at ${group.startAddr}: ${err.message}`);
461
+ }
462
+ }
463
+ }
464
+
436
465
  /**
437
466
  * Read all active SigenMicro devices
438
467
  */
@@ -754,6 +783,21 @@ class Sigenergy extends utils.Adapter {
754
783
  for (let n = 1; n <= 30; n++) {
755
784
  await this._createChannel(`plant.essPreheating.tou${n}`, `TOU Window ${n}`);
756
785
  }
786
+ for (const reg of ESS_PREHEATING_WRITE_REGISTERS) {
787
+ await this.setObjectNotExistsAsync(reg.name, {
788
+ type: 'state',
789
+ common: {
790
+ name: reg.desc,
791
+ type: 'number',
792
+ role: 'value',
793
+ unit: reg.unit || '',
794
+ read: true,
795
+ write: true,
796
+ },
797
+ native: { addr: reg.addr, qty: reg.qty, dataType: reg.type, gain: reg.gain },
798
+ });
799
+ }
800
+ this.subscribeStates('plant.essPreheating.*');
757
801
  }
758
802
 
759
803
  await this._createStatisticsStates();
@@ -928,7 +972,38 @@ class Sigenergy extends utils.Adapter {
928
972
  /**
929
973
  * Handle messages from admin (connection test, etc.)
930
974
  *
931
- * @param {object} obj - Message object
975
+ * @param {ioBroker.Object} obj - Message object
976
+ */
977
+ async onStateChange(id, state) {
978
+ if (!state || state.ack) {
979
+ return;
980
+ }
981
+ // Strip namespace prefix (e.g. "sigenergy.0.")
982
+ const localId = id.replace(/^[^.]+\.\d+\./, '');
983
+ if (!localId.startsWith('plant.essPreheating.')) {
984
+ return;
985
+ }
986
+ const reg = ESS_PREHEATING_WRITE_REGISTERS.find(r => r.name === localId);
987
+ if (!reg) {
988
+ return;
989
+ }
990
+ const plantId = this.config.plantId || 247;
991
+ const raw = ModbusConnection.encodeValue(state.val, reg.type, reg.gain);
992
+ try {
993
+ if (raw.length === 1) {
994
+ await this.modbus.writeSingleRegister(plantId, reg.addr, raw[0]);
995
+ } else {
996
+ await this.modbus.writeMultipleRegisters(plantId, reg.addr, raw);
997
+ }
998
+ await this.setStateAsync(id, { val: state.val, ack: true });
999
+ this.log.debug(`[essPreheating] wrote ${localId} = ${state.val} → addr ${reg.addr}`);
1000
+ } catch (err) {
1001
+ this.log.error(`ESS Preheating write error for ${localId}: ${err.message}`);
1002
+ }
1003
+ }
1004
+
1005
+ /**
1006
+ * @param {ioBroker.Object} obj - Message object
932
1007
  */
933
1008
  async onMessage(obj) {
934
1009
  if (!obj || !obj.command) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.sigenergy",
3
- "version": "2.2.3",
3
+ "version": "2.2.4",
4
4
  "description": "ioBroker adapter for Sigenergy solar energy systems via Modbus TCP/RTU",
5
5
  "author": {
6
6
  "name": "ssbingo",