iobroker.sigenergy 3.1.2 → 3.2.0

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
@@ -49,7 +49,7 @@ Supports the Sigenergy Modbus Protocol V2.9 (released 2026-05-13).
49
49
  | Component | Minimum version |
50
50
  |-----------|-----------------|
51
51
  | **js-controller** | >= 6.0.11 |
52
- | **admin** | >= 8.0.0 |
52
+ | **admin** | >= 7.8.23 |
53
53
  | **Node.js** | >= 22 |
54
54
 
55
55
  ---
@@ -255,6 +255,15 @@ Status and power readings for the DC charger.
255
255
 
256
256
  ## Changelog
257
257
 
258
+ ### 3.2.0 (2026-09-04)
259
+ - (MMeinhardt1) feat: new state `statistics.emsWorkMode` exposing the EMS work mode as plain text, so consumers do not need the `common.states` lookup table
260
+ - (MMeinhardt1) feat: added EMS work mode 6 (Virtual Power Plant) to the register description and the mode map
261
+ - (MMeinhardt1) change: the `*HM` duration states now hold a bare `H:MM` value with unit `h`, instead of embedding an `h` suffix in the value itself
262
+ - (MMeinhardt1) fix: statistics objects are created with `extendObjectAsync`, so corrected units and roles reach installations where the object already exists
263
+ - (ssbingo) chore: admin minimum requirement lowered back to >= 7.8.23 to keep serving admin 7.x installations
264
+ - (ssbingo) fix: restored the JSDoc parameter descriptions on `_formatMinutesAsHM` to keep `npm run lint` warning-free
265
+ - (ssbingo) chore: repository checker findings — track `.vscode/settings.json` deliberately, bump `@alcalzone/release-script-plugin-license` to 5.2.2, pin `testing-action-deploy` to the major version again
266
+
258
267
  ### 3.1.2 (2026-08-06)
259
268
  - (ssbingo) chore: resolved all 28 npm audit findings (3 critical, 11 high) — development tooling only, the published adapter is unchanged
260
269
  - (ssbingo) chore: removed `@iobroker/dev-server`; it was the sole source of the critical findings via the deprecated `request` and `xmldom` packages, for which no fixed release exists. This also removes the `npm start` / `npm run watch` scripts
package/io-package.json CHANGED
@@ -1,8 +1,21 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "sigenergy",
4
- "version": "3.1.2",
4
+ "version": "3.2.0",
5
5
  "news": {
6
+ "3.2.0": {
7
+ "en": "(MMeinhardt1) feat: EMS work mode as plain text, Virtual Power Plant mode, h:mm values now carry unit 'h' instead of a suffix; statistics objects are updated on every start. (ssbingo) chore: admin requirement lowered back to >=7.8.23",
8
+ "de": "(MMeinhardt1) feat: EMS-Betriebsmodus als Klartext, Modus Virtual Power Plant, h:mm-Werte tragen jetzt die Einheit 'h' statt eines Suffix; Statistik-Objekte werden bei jedem Start aktualisiert. (ssbingo) chore: admin-Anforderung zurück auf >=7.8.23",
9
+ "ru": "(MMeinhardt1) feat: режим работы EMS в виде текста, режим Virtual Power Plant, значения h:mm теперь имеют единицу 'h' вместо суффикса; объекты статистики обновляются при каждом запуске. (ssbingo) chore: требование к admin снижено до >=7.8.23",
10
+ "pt": "(MMeinhardt1) feat: modo de trabalho EMS como texto, modo Virtual Power Plant, valores h:mm passam a ter a unidade 'h' em vez de sufixo; os objetos de estatística são atualizados em cada arranque. (ssbingo) chore: requisito do admin reduzido para >=7.8.23",
11
+ "nl": "(MMeinhardt1) feat: EMS-werkmodus als tekst, modus Virtual Power Plant, h:mm-waarden krijgen nu eenheid 'h' in plaats van een achtervoegsel; statistiekobjecten worden bij elke start bijgewerkt. (ssbingo) chore: admin-vereiste terug naar >=7.8.23",
12
+ "fr": "(MMeinhardt1) feat : mode de fonctionnement EMS en texte clair, mode Virtual Power Plant, les valeurs h:mm portent désormais l'unité « h » au lieu d'un suffixe ; les objets de statistiques sont mis à jour à chaque démarrage. (ssbingo) chore : exigence admin ramenée à >=7.8.23",
13
+ "it": "(MMeinhardt1) feat: modalità di lavoro EMS come testo, modalità Virtual Power Plant, i valori h:mm ora hanno l'unità 'h' invece di un suffisso; gli oggetti statistici vengono aggiornati a ogni avvio. (ssbingo) chore: requisito admin riportato a >=7.8.23",
14
+ "es": "(MMeinhardt1) feat: modo de trabajo EMS como texto, modo Virtual Power Plant, los valores h:mm llevan ahora la unidad 'h' en lugar de un sufijo; los objetos de estadísticas se actualizan en cada arranque. (ssbingo) chore: requisito de admin reducido a >=7.8.23",
15
+ "pl": "(MMeinhardt1) feat: tryb pracy EMS jako tekst, tryb Virtual Power Plant, wartości h:mm mają teraz jednostkę 'h' zamiast sufiksu; obiekty statystyk są aktualizowane przy każdym starcie. (ssbingo) chore: wymaganie admin obniżone do >=7.8.23",
16
+ "uk": "(MMeinhardt1) feat: режим роботи EMS як текст, режим Virtual Power Plant, значення h:mm тепер мають одиницю 'h' замість суфікса; об'єкти статистики оновлюються при кожному запуску. (ssbingo) chore: вимогу до admin знижено до >=7.8.23",
17
+ "zh-cn": "(MMeinhardt1) feat: EMS 工作模式以纯文本提供、新增 Virtual Power Plant 模式、h:mm 值改用单位 'h' 而非后缀;统计对象在每次启动时更新。(ssbingo) chore: admin 要求下调回 >=7.8.23"
18
+ },
6
19
  "3.1.2": {
7
20
  "en": "(ssbingo) chore: all npm audit findings resolved (28 -> 0); removed @iobroker/dev-server, which pulled in unpatchable deprecated packages. Development tooling only — the adapter itself is unchanged.",
8
21
  "de": "(ssbingo) chore: alle npm-audit-Findings behoben (28 -> 0); @iobroker/dev-server entfernt, das nicht patchbare veraltete Pakete mitzog. Betrifft nur das Entwicklungs-Tooling — der Adapter selbst ist unverändert.",
@@ -121,7 +134,7 @@
121
134
  ],
122
135
  "globalDependencies": [
123
136
  {
124
- "admin": ">=8.0.0"
137
+ "admin": ">=7.8.23"
125
138
  }
126
139
  ],
127
140
  "licenseInformation": {
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,5=FullFeedIn,7=RemoteEMS,9=Custom',
40
+ desc: 'EMS work mode: 0=MaxSelfConsumption,1=AI,2=TOU,5=FullFeedIn,6=VirtualPowerPlant,7=RemoteEMS,9=Custom',
41
41
  },
42
42
  {
43
43
  addr: 30004,
@@ -3313,6 +3313,7 @@ const EMS_WORK_MODES = {
3313
3313
  1: 'AI Mode',
3314
3314
  2: 'TOU',
3315
3315
  5: 'Full Feed-in to Grid',
3316
+ 6: 'Virtual Power Plant',
3316
3317
  7: 'Remote EMS',
3317
3318
  9: 'Custom',
3318
3319
  };
package/main.js CHANGED
@@ -1128,6 +1128,7 @@ class Sigenergy extends utils.Adapter {
1128
1128
  'plant.essSoc': 'soc',
1129
1129
  'plant.essRatedEnergyCapacity': 'ratedCapacity',
1130
1130
  'plant.essDischargeSOC': 'cutoffSoc',
1131
+ 'plant.emsWorkMode': 'emsWorkMode',
1131
1132
  'inverter.pv1Voltage': 'pv1Voltage',
1132
1133
  'inverter.pv1Current': 'pv1Current',
1133
1134
  'inverter.pv2Voltage': 'pv2Voltage',
@@ -1141,15 +1142,16 @@ class Sigenergy extends utils.Adapter {
1141
1142
  }
1142
1143
 
1143
1144
  /**
1144
- * Format a minute value as an "H:MMh" string (e.g. 83 -> "1:23h").
1145
- * Hours are not capped at 24. Distinguishes three cases so the caller's
1146
- * null-vs-undefined write semantics (see _updateStatistics) are preserved:
1145
+ * Format a minute value as an "H:MM" string (e.g. 83 -> "1:23").
1146
+ * Hours are not capped at 24.
1147
+ * Distinguishes three cases so the caller's null-vs-undefined write
1148
+ * semantics (see _updateStatistics) are preserved:
1147
1149
  * - undefined (statistic disabled via config) -> undefined (skip write)
1148
1150
  * - null / NaN (statistic enabled but currently N/A) -> null (clears stale value)
1149
- * - number -> formatted "H:MMh" string
1151
+ * - number -> formatted "H:MM" string
1150
1152
  *
1151
1153
  * @param {number|null|undefined} totalMinutes - Duration in minutes, or null/undefined per the cases above
1152
- * @returns {string|null|undefined} Formatted "H:MMh" string, or null/undefined mirroring the input case
1154
+ * @returns {string|null|undefined} Formatted "H:MM" string, or null/undefined mirroring the input case
1153
1155
  */
1154
1156
  _formatMinutesAsHM(totalMinutes) {
1155
1157
  if (totalMinutes === undefined) {
@@ -1162,7 +1164,26 @@ class Sigenergy extends utils.Adapter {
1162
1164
  const abs = Math.round(Math.abs(totalMinutes));
1163
1165
  const hours = Math.floor(abs / 60);
1164
1166
  const minutes = abs % 60;
1165
- return `${sign}${hours}:${String(minutes).padStart(2, '0')}h`;
1167
+ return `${sign}${hours}:${String(minutes).padStart(2, '0')}`;
1168
+ }
1169
+
1170
+ /**
1171
+ * Look up the plain-text label for the numeric EMS work mode (register
1172
+ * 30003 / plant.emsWorkMode), using the same EMS_WORK_MODES map already
1173
+ * used for the `common.states` metadata on plant.emsWorkMode. Unlike that
1174
+ * metadata (only understood by UIs/tools that render `common.states`),
1175
+ * this writes the human-readable text directly as the state value, so any
1176
+ * consumer (VIS, Node-RED, external scripts) can use it without needing
1177
+ * the lookup table.
1178
+ *
1179
+ * @param {number|undefined} mode - Raw value of plant.emsWorkMode
1180
+ * @returns {string|undefined} Plain-text label, or undefined if mode hasn't been read yet
1181
+ */
1182
+ _formatEmsWorkMode(mode) {
1183
+ if (mode === undefined) {
1184
+ return undefined;
1185
+ }
1186
+ return EMS_WORK_MODES[mode] || `Unknown (${mode})`;
1166
1187
  }
1167
1188
 
1168
1189
  /**
@@ -1193,6 +1214,7 @@ class Sigenergy extends utils.Adapter {
1193
1214
  'statistics.housePower': statsValues.housePower,
1194
1215
  'statistics.currentSoc': statsValues.currentSoc,
1195
1216
  'statistics.currentPvPower': statsValues.currentPvPower,
1217
+ 'statistics.emsWorkMode': this._formatEmsWorkMode(this._currentData.emsWorkMode),
1196
1218
  'statistics.dayMaxSoc': statsValues.dayMaxSoc,
1197
1219
  'statistics.dayMinSoc': statsValues.dayMinSoc,
1198
1220
  };
@@ -1674,7 +1696,7 @@ class Sigenergy extends utils.Adapter {
1674
1696
  id: 'statistics.batteryTimeToFullHM',
1675
1697
  name: 'Time until battery is fully charged (h:mm)',
1676
1698
  type: 'string',
1677
- unit: '',
1699
+ unit: 'h',
1678
1700
  role: 'text',
1679
1701
  },
1680
1702
  {
@@ -1688,7 +1710,7 @@ class Sigenergy extends utils.Adapter {
1688
1710
  id: 'statistics.batteryTimeRemainingHM',
1689
1711
  name: 'Battery time remaining at current load (h:mm)',
1690
1712
  type: 'string',
1691
- unit: '',
1713
+ unit: 'h',
1692
1714
  role: 'text',
1693
1715
  },
1694
1716
  {
@@ -1702,7 +1724,7 @@ class Sigenergy extends utils.Adapter {
1702
1724
  id: 'statistics.batteryDailyChargeTimeHM',
1703
1725
  name: 'Today: cumulative time spent charging (h:mm)',
1704
1726
  type: 'string',
1705
- unit: '',
1727
+ unit: 'h',
1706
1728
  role: 'text',
1707
1729
  },
1708
1730
  {
@@ -1716,7 +1738,7 @@ class Sigenergy extends utils.Adapter {
1716
1738
  id: 'statistics.batteryCoverageTodayHM',
1717
1739
  name: 'Today: time battery covered consumption (h:mm)',
1718
1740
  type: 'string',
1719
- unit: '',
1741
+ unit: 'h',
1720
1742
  role: 'text',
1721
1743
  },
1722
1744
  {
@@ -1782,6 +1804,13 @@ class Sigenergy extends utils.Adapter {
1782
1804
  unit: 'kW',
1783
1805
  role: 'value.power',
1784
1806
  },
1807
+ {
1808
+ id: 'statistics.emsWorkMode',
1809
+ name: 'EMS work mode (plain text)',
1810
+ type: 'string',
1811
+ unit: '',
1812
+ role: 'text',
1813
+ },
1785
1814
  {
1786
1815
  id: 'statistics.dayMaxSoc',
1787
1816
  name: 'Today maximum SOC',
@@ -1812,7 +1841,12 @@ class Sigenergy extends utils.Adapter {
1812
1841
  },
1813
1842
  native: {},
1814
1843
  };
1815
- await this.setObjectNotExistsAsync(s.id, statObj);
1844
+ // extendObjectAsync (not setObjectNotExistsAsync) so that changes to
1845
+ // an existing definition (e.g. a corrected unit or role) are applied
1846
+ // on every adapter start, instead of being silently ignored forever
1847
+ // once the object has been created once. The state's current value
1848
+ // is untouched by this — only the object's common metadata is merged.
1849
+ await this.extendObjectAsync(s.id, statObj);
1816
1850
  }
1817
1851
  }
1818
1852
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.sigenergy",
3
- "version": "3.1.2",
3
+ "version": "3.2.0",
4
4
  "description": "ioBroker adapter for Sigenergy solar energy systems via Modbus TCP/RTU",
5
5
  "author": {
6
6
  "name": "ssbingo",
@@ -30,12 +30,12 @@
30
30
  "devDependencies": {
31
31
  "@alcalzone/release-script": "^5.2.1",
32
32
  "@alcalzone/release-script-plugin-iobroker": "^5.2.0",
33
- "@alcalzone/release-script-plugin-license": "^5.2.0",
33
+ "@alcalzone/release-script-plugin-license": "^5.2.2",
34
34
  "@alcalzone/release-script-plugin-manual-review": "^5.2.0",
35
35
  "@iobroker/adapter-dev": "^1.5.0",
36
36
  "@iobroker/eslint-config": "^2.3.4",
37
37
  "@iobroker/testing": "^5.3.0",
38
- "@tsconfig/node22": "^22.0.5",
38
+ "@tsconfig/node22": "^22.0.6",
39
39
  "@types/node": "^22.20.1"
40
40
  },
41
41
  "main": "main.js",