iobroker.sun2000 1.1.0 → 1.2.2

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
@@ -64,6 +64,17 @@ browse in the [wiki](https://github.com/bolliy/ioBroker.sun2000/wiki)
64
64
  Placeholder for the next version (at the beginning of the line):
65
65
  ### **WORK IN PROGRESS**
66
66
  -->
67
+ ### 1.2.2 (2025-04-01)
68
+ * deploy 1.2
69
+
70
+ ### 1.2.1 (2025-04-01)
71
+ * dependency update
72
+
73
+ ### 1.2.0 (2025-04-01)
74
+ * dependency and configuration updates
75
+ * fix: Object state sDongle.OSVersion to short
76
+ * new setting path for controlling the usableSurplusPower parameters `control.usableSurplus`
77
+
67
78
  ### 1.1.0 (2025-03-19)
68
79
  * startupTime/shutdownTime are read from the inverter as local time and not as UTC - fixed times are saved in path `derived`
69
80
  * new state [usableSurplusPower](https://github.com/bolliy/ioBroker.sun2000/wiki/%C3%9Cberschuss-(surplus))
package/io-package.json CHANGED
@@ -1,8 +1,60 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "sun2000",
4
- "version": "1.1.0",
4
+ "version": "1.2.2",
5
5
  "news": {
6
+ "1.2.2": {
7
+ "en": "deploy 1.2",
8
+ "de": "bereitstellung 1.2",
9
+ "ru": "развернуть 1.2",
10
+ "pt": "implementação 1.2",
11
+ "nl": "1.2 inzetten",
12
+ "fr": "déploiement 1,2",
13
+ "it": "distribuzione 1.2",
14
+ "es": "despliegue 1.2",
15
+ "pl": "rozmieszczenie 1.2",
16
+ "uk": "розгортання 1.2",
17
+ "zh-cn": "部署"
18
+ },
19
+ "1.2.2-alpha.0": {
20
+ "en": "test release",
21
+ "de": "prüfbericht",
22
+ "ru": "испытательный выпуск",
23
+ "pt": "liberação de teste",
24
+ "nl": "loslaten van de test",
25
+ "fr": "libération d'essai",
26
+ "it": "rilascio del test",
27
+ "es": "prueba de liberación",
28
+ "pl": "uwalnianie testowe",
29
+ "uk": "тестовий реліз",
30
+ "zh-cn": "测试发布"
31
+ },
32
+ "1.2.1": {
33
+ "en": "dependency update",
34
+ "de": "aktualisierung der abhängigkeit",
35
+ "ru": "обновление зависимостей",
36
+ "pt": "atualização de dependência",
37
+ "nl": "afhankelijkheidsupdate",
38
+ "fr": "mise à jour de la dépendance",
39
+ "it": "aggiornamento della dipendenza",
40
+ "es": "actualización de la dependencia",
41
+ "pl": "aktualizacja zależności",
42
+ "uk": "оновлення залежності",
43
+ "zh-cn": "依赖性更新"
44
+ },
45
+ "1.2.0": {
46
+ "en": "dependency and configuration updates updates\nfix: Object state sDongle.OSVersion to short\nnew setting path for controlling the usableSurplus parameters `control.usableSurplus`",
47
+ "de": "abhängigkeit und konfiguration updates\nfix: Objektzustand sDongle. OSVersion kurz\nneuer Einstellpfad zur Steuerung des Nutzbar Überschüssige Parameter `control.usableSurplus `",
48
+ "ru": "обновления зависимостей и конфигураций\nобсуждение Object State sDongle. OSVersion to Short\nновый путь настройки для контроля полезного Дополнительные параметры 'control.usable Surplus пункт",
49
+ "pt": "atualizações de dependência e configuração\ncorreção: Objeto estado sDongle. OSVersion to short\nnovo caminho de configuração para controlar a usável Parâmetros do Surplus `control.usableSurplus \"",
50
+ "nl": "afhankelijkheid en configuratie updates\nfix: Object state sDongle. OSVersion to short\nnieuw instellingspad voor het bedienen van het bruikbare Overschotparameters Controle.bruikbaarSurplus Wat",
51
+ "fr": "mises à jour de la dépendance et de la configuration\ncorrection : État de l'objet sDongle. OSVersion à court\nnouveau chemin de réglage pour contrôler l'utilisable Paramètres excédentaires \"control.usableExcédent \"",
52
+ "it": "aggiornamenti di dipendenza e configurazione\ncorrezione: SDongle di stato dell'oggetto. OSVersione a breve\nnuovo percorso di regolazione per il controllo dell'utilizzabile Parametri in eccesso `control.usableSurplus #",
53
+ "es": "actualizaciones de dependencia y configuración\nresolver: \"Objeto estado sDongle\". OSVersion to short\nnuevo camino de configuración para controlar el usable Parámetros adicionales `control.usableSurplus `",
54
+ "pl": "aktualizacje zależności i konfiguracji\nfix: Object state sDongle. OSVersion to short\nnowa ścieżka ustawień do sterowania użytecznym Parametry nadwyżki 'control.usableSurplus'",
55
+ "uk": "оновлення залежності та конфігурації\nвиправити: Об'єктний стан sDongle. OSVersion до короткого\nновий шлях налаштування для контролю Параметри Surplus `control.usableSurplus й",
56
+ "zh-cn": "依赖性和配置更新\n固定:对象状态 sDongle。 OSVsion 缩写\n用于控制可用的新设置路径 盈余参数 `控制.可使用余额' `"
57
+ },
6
58
  "1.1.0": {
7
59
  "en": "startupTime/shutdownTime are read from the inverter as local time and not as UTC - fixed times are saved in path `derived`\nnew state [usableSurplusPower](https://github.com/bolliy/ioBroker.sun2000/wiki/%C3%9Cberschuss-(surplus))\ncontrol: checking and rounding integer numbers\nbetter solution for math rounding",
8
60
  "de": "startzeit/Shutdown Zeit wird vom Wechselrichter als Ortszeit gelesen und nicht als UTC - Festzeiten werden im Pfad gespeichert `derived `\nneuer Staat [usableSurplusPower](https://github.com/bolliy/ioBroker.sun2000/wiki/%C3%9Cberschuss-(surplus))\nsteuerung: überprüfung und rundung ganzzahliger zahlen\nbessere lösung für matherundung",
@@ -41,58 +93,6 @@
41
93
  "pl": "aktualizacje zależności i konfiguracji\nzaktualizowana czułość przypadku nazwy statusu obiektu\nCzas interval inverter niewolnika nieznacznie wzrosła\nDane rejestracyjne nie są odczytywane w \"Standby: detection irradiation\" (0x0002) inwertera niewolnika\nKontrola: battery.maximumDischargePower jest zdeprecjonowane użycie \"maximumDischargingPower\" zamiast\nKontrola: battery.maximumChargePower jest przestarzałe użycie \"maximumChargingPower\" zamiast\nłamanie zmian\nNode.js 20 lub wyższe wymagane\njoBroker host (kontroler js-) 6.0.1 lub wyższy\njoBroker admin 6.13.16 lub wyższy",
42
94
  "uk": "оновлення залежності та конфігурації\nоновлена чутливість корпусу назви стану об'єкта\nМіжвалий час раба інвертора трохи збільшилася\nЗареєструвати дані не читають в \"Станбі: виявлення опромінення\" (0x0002) рабоінвертора\nКонтроль: акумулятор.maximumDischargePower deprecated use \"maximumDischargingPower\" замість\nКонтроль: акумулятор.maximumChargePower deprecated use \"maximumChargingPower\" замість\nполомка змін\nNode.js 20 або вище\nioBroker host (js-controller) 6.0.1 або вище\nioBroker admin 6.13.16 або вище",
43
95
  "zh-cn": "依赖和配置更新\n更新对象状态名称的大小写灵敏度\n奴隶倒转的间隔时间略有增加\n在奴隶反转器的\"Standby:检测辐照\"(0x0002)中不读登记数据\n控制: 电池. 最大充电Power被贬值 使用\"最大充电Power\"代替\n控制:电池. 最大管理员Power被贬值 使用\"最大充电Power\"代替\n断开更改\n需要20个或以上的节点\nioBroker 主机(js-controller) 6.0.1 或更高\nioBroker 管理员 6.13.16或以上"
44
- },
45
- "0.18.1": {
46
- "en": "dependency and configuration updates\ncontrol: if the battery is not running, events related to the battery are discarded\nmodbus-proxy: adjusted advanced logging",
47
- "de": "abhängigkeits- und konfigurationsupdates\nsteuerung: wenn die batterie nicht läuft, werden ereignisse im zusammenhang mit der batterie verworfen\nmodbus-proxy: angepasste erweiterte protokollierung",
48
- "ru": "обновления зависимости и конфигурации\nуправление: если батарея не работает, события, связанные с батареей, отбрасываются\nmodbus-proxy: скорректированные передовые лесозаготовки",
49
- "pt": "atualizações de dependência e configuração\ncontrole: se a bateria não estiver funcionando, os eventos relacionados à bateria são descartados\nmodbus-proxy: log avançado ajustado",
50
- "nl": "afhankelijkheid en configuratie-updates\ncontrole: als de batterij niet draait, worden gebeurtenissen in verband met de batterij weggegooid\nmodbus-proxy: aangepaste geavanceerde logging",
51
- "fr": "mises à jour de la dépendance et de la configuration\ncontrôle: si la batterie ne fonctionne pas, les événements liés à la batterie sont jetés\nmodbus-proxy: enregistrement avancé ajusté",
52
- "it": "aggiornamenti di dipendenza e configurazione\ncontrollo: se la batteria non è in esecuzione, gli eventi relativi alla batteria vengono scartati\nmodbus-proxy: registrazione avanzata regolata",
53
- "es": "actualizaciones de dependencia y configuración\ncontrol: si la batería no funciona, los eventos relacionados con la batería son descartados\nmodbus-proxy: registro avanzado ajustado",
54
- "pl": "aktualizacje zależności i konfiguracji\nsterowanie: jeśli akumulator nie jest uruchomiony, zdarzenia związane z akumulatorem są odrzucane\nmodbus- proxy: dostosowane zaawansowane logowanie",
55
- "uk": "оновлення залежності та конфігурації\nконтроль: якщо акумулятор не працює, події, пов'язані з акумулятором, відкидаються\nmodbus-proxy: регульований розширений журналювання",
56
- "zh-cn": "依赖和配置更新\n控件: 如果电池没有运行, 与电池相关的事件会被丢弃\nmodbus-代用:经过调整的高级记录"
57
- },
58
- "0.18.0": {
59
- "en": "dependency and configuration updates\nmodbus-proxy: the modbus ID 250 is mapped to ID 0",
60
- "de": "abhängigkeits- und konfigurationsupdates\nmodbus-proxy: die modbus ID 250 wird auf ID 0 abgebildet",
61
- "ru": "обновления зависимости и конфигурации\nmodbus-proxy: modbus ID 250 отображается на ID 0",
62
- "pt": "atualizações de dependência e configuração\nmodbus-proxy: o modbus ID 250 é mapeado para ID 0",
63
- "nl": "afhankelijkheid en configuratie-updates\nmodbus-proxy: de modbus ID 250 is toegewezen aan ID 0",
64
- "fr": "mises à jour de la dépendance et de la configuration\nmodbus-proxy: le modbus ID 250 est mapé à ID 0",
65
- "it": "aggiornamenti di dipendenza e configurazione\nmodbus-proxy: il modbus ID 250 è mappato su ID 0",
66
- "es": "actualizaciones de dependencia y configuración\nmodbus-proxy: el modbus ID 250 se asigna al ID 0",
67
- "pl": "aktualizacje zależności i konfiguracji\nmodbus- proxy: modbus ID 250 jest odwzorowany na ID 0",
68
- "uk": "оновлення залежності та конфігурації\nmodbus-proxy: modbus ID 250 is mapped to ID 0",
69
- "zh-cn": "依赖和配置更新\nmodbus-代用:modbus ID 250被映射到ID 0"
70
- },
71
- "0.17.1": {
72
- "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",
73
- "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",
74
- "ru": "во время состояния устройства «Стандби: обнаружение облучения» (0x0002) данные регистров теперь также читаются из инвертора\nПорядок чтения данных батареи был скорректирован",
75
- "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",
76
- "nl": "tijdens de apparaatstatus \"Standby: detectie van bestraling\" (0x0002) worden nu ook gegevens van de omvormer gelezen\nDe leesvolgorde van de batterijgegevens is aangepast",
77
- "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é",
78
- "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",
79
- "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",
80
- "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",
81
- "uk": "при статусі пристрою \"Стандарт: виявлення опромінення\" (0x0002) реєстраційні дані тепер також читайте з інвертора\nВиправлено порядок читання даних акумулятора",
82
- "zh-cn": "在设备状态“ Standby: 检测辐照” (0x0002) 注册数据现在也从反转器读取\n电池数据的读取顺序已调整"
83
- },
84
- "0.17.0": {
85
- "en": "adjust for Responsive Design #134\nmigrate to ESLint 9.x\nnode >= v18.18.0\nmodbus-proxy: enabled reading data via input register",
86
- "de": "anpassung für Responsive Design #134\nmigration auf ESLint 9.x\nknoten >= v18.18.0\nmodbus-proxy: lesedaten über eingaberegister aktiviert",
87
- "ru": "#134\nмигрировать в ESLint 9.x\nnode >= v18.18.0\nmodbus-proxy: включено чтение данных через регистр ввода",
88
- "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",
89
- "nl": "aanpassen voor Responsive Design #134\nmigreren naar ESLint 9.x\nn.v.t\nmodbus-proxy: leesgegevens ingeschakeld via invoerregister",
90
- "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",
91
- "it": "regolazione per Responsive Design #134\nmigrare a ESLint 9.x\nnodo >= v18.18.0\nmodbus-proxy: dati di lettura abilitati tramite registro input",
92
- "es": "ajuste para el diseño responsable #134\nmigrar a ESLint 9.x\nnodo\nmodbus-proxy: datos de lectura habilitados mediante registro de entrada",
93
- "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",
94
- "uk": "конфігурація для відповідального дизайну #134\nmigrate до ESLint 9.x\nвершина >= v18.18.0\nmodbus-proxy: ввімкнено дані читання через вхідний реєстр",
95
- "zh-cn": "调整响应设计 # 134\n迁移到 ESLint 9.x\n节点 {v18.18.0}\nmodbus- 代理: 启用通过输入寄存器读取数据"
96
96
  }
97
97
  },
98
98
  "titleLang": {
@@ -0,0 +1,187 @@
1
+ 'use strict';
2
+ //const { deviceType } = require(`${__dirname}/../types.js`);
3
+ class ConfigMap {
4
+ constructor(adapterInstance) {
5
+ this.adapter = adapterInstance;
6
+ this.log = this.adapter.logger;
7
+ this._serviceMap = new Map();
8
+ this._eventMap = new Map();
9
+ this._initialized = false;
10
+ this._path = 'control';
11
+
12
+ this.serviceFields = [
13
+ {
14
+ state: {
15
+ id: 'usableSurplus.minSoc',
16
+ name: 'minmum SoC',
17
+ type: 'number',
18
+ unit: '%',
19
+ role: 'level',
20
+ desc: 'Use of battery charging power above the specified SoC value (%)',
21
+ },
22
+ fn: async event => {
23
+ if (event.value > 100) {
24
+ event.value = 100;
25
+ }
26
+ if (event.value < 0) {
27
+ event.value = 0;
28
+ }
29
+ return true;
30
+ },
31
+ },
32
+ {
33
+ state: {
34
+ id: 'usableSurplus.bufferSoc',
35
+ name: 'buffer SoC',
36
+ type: 'number',
37
+ unit: '%',
38
+ role: 'level',
39
+ desc: 'battery is used as a buffer above Soc (%) value',
40
+ },
41
+ fn: async event => {
42
+ if (event.value > 100) {
43
+ event.value = 100;
44
+ }
45
+ if (event.value < 0) {
46
+ event.value = 0;
47
+ }
48
+ return true;
49
+ },
50
+ },
51
+ {
52
+ state: {
53
+ id: 'usableSurplus.bufferPower',
54
+ name: 'Discharge power from buffer',
55
+ type: 'number',
56
+ unit: 'W',
57
+ role: 'level.power',
58
+ desc: 'battery is used as a buffer with power',
59
+ },
60
+ fn: async event => {
61
+ if (event.value > 5000) {
62
+ event.value = 5000;
63
+ }
64
+ if (event.value < 0) {
65
+ event.value = 0;
66
+ }
67
+ return true;
68
+ },
69
+ },
70
+ {
71
+ state: {
72
+ id: 'usableSurplus.residualPower',
73
+ name: 'residual Power',
74
+ type: 'number',
75
+ unit: 'W',
76
+ role: 'level.power',
77
+ desc: 'Sets the target operating point of the surplus regulation',
78
+ },
79
+ fn: async event => {
80
+ if (event.value > 1000) {
81
+ event.value = 1000;
82
+ }
83
+ if (event.value < -1000) {
84
+ event.value = -1000;
85
+ }
86
+ return true;
87
+ },
88
+ },
89
+ ];
90
+ }
91
+
92
+ async init() {
93
+ for (const item of this.serviceFields) {
94
+ if (item?.state) {
95
+ this._serviceMap.set(item.state.id, item);
96
+ }
97
+ }
98
+ //read value
99
+ for (const entry of this._serviceMap.values()) {
100
+ await this._initState(`${this._path}.`, entry.state);
101
+ const state = await this.adapter.getState(`${this._path}.${entry.state.id}`);
102
+
103
+ if (state) {
104
+ this.set(entry.state.id, state);
105
+ }
106
+ }
107
+ this.adapter.subscribeStates(`${this._path}.*`);
108
+ this._initialized = true;
109
+ /*
110
+ if (this._initialized) {
111
+ this.log.info('Control: Config map initialized');
112
+ }
113
+ */
114
+ }
115
+
116
+ /**
117
+ * @description Check if the value of the event is a number and optionally round it to the nearest integer.
118
+ * @param {object} event The event object
119
+ * @param {boolean} [round] If true, the value is rounded to the nearest integer
120
+ * @returns {boolean} True if the value is a number, false otherwise
121
+ */
122
+ isNumber(event, round = true) {
123
+ if (isNaN(event.value)) {
124
+ return false;
125
+ }
126
+ if (round) event.value = Math.round(event.value);
127
+ return true;
128
+ }
129
+
130
+ get(id) {
131
+ return this._eventMap.get(id);
132
+ }
133
+
134
+ set(id, state) {
135
+ const service = this._serviceMap.get(id);
136
+ if (state && service) {
137
+ if (state.val !== null) {
138
+ if (!state.ack) this.log.info(`Control: Event - state: ${this._path}.${id} changed: ${state.val} ack: ${state.ack}`);
139
+ const event = this._eventMap.get(id);
140
+ if (event) {
141
+ event.value = state.val;
142
+ event.ack = state.ack;
143
+ } else {
144
+ this._eventMap.set(id, { id: id, value: state.val, ack: state.ack });
145
+ }
146
+ this._process(id);
147
+ }
148
+ }
149
+ }
150
+
151
+ //state
152
+ async _initState(path, state) {
153
+ await this.adapter.extendObject(path + state.id, {
154
+ type: 'state',
155
+ common: {
156
+ name: state.name,
157
+ type: state.type,
158
+ role: state.role,
159
+ unit: state.unit,
160
+ desc: state.desc,
161
+ read: true,
162
+ write: true,
163
+ },
164
+ native: {},
165
+ });
166
+ }
167
+
168
+ async _process(id) {
169
+ const event = this.get(id);
170
+ const service = this._serviceMap.get(event.id);
171
+ if (event.value !== null && service.fn) {
172
+ if (service.state.type === 'number') {
173
+ if (!this.isNumber(event)) {
174
+ this.log.warn(`Control: Event is discarded because the value ${event.value} is not a number. State: ${this._path}.${event.id}`);
175
+ return;
176
+ }
177
+ event.value = Math.round(event.value * 100) / 100;
178
+ }
179
+ if (await service.fn(event)) {
180
+ await this.adapter.setState(`${this._path}.${event.id}`, { val: event.value, ack: true });
181
+ event.ack = true;
182
+ }
183
+ }
184
+ }
185
+ }
186
+
187
+ module.exports = ConfigMap;
@@ -566,7 +566,7 @@ class ServiceQueueMap {
566
566
  const service = this._serviceMap.get(id);
567
567
  if (state && service) {
568
568
  if (state.val !== null && !state.ack) {
569
- this.log.info(`Control: Event - state: ${id} changed: ${state.val} ack: ${state.ack}`);
569
+ this.log.info(`Control: Event - state: ${this.inverterInfo.path}.control.${id} changed: ${state.val} ack: ${state.ack}`);
570
570
  const event = this._eventMap.get(id);
571
571
  if (event) {
572
572
  event.value = state.val;
@@ -577,11 +577,11 @@ class ServiceQueueMap {
577
577
  }
578
578
  }
579
579
  }
580
-
580
+ /*
581
581
  values() {
582
582
  return this._map.values();
583
583
  }
584
-
584
+ */
585
585
  /**
586
586
  * Processes pending events in the service queue and attempts to execute their associated functions.
587
587
  *
@@ -635,7 +635,7 @@ class ServiceQueueMap {
635
635
  if (service.state.type === 'number') {
636
636
  if (!this.isNumber(event)) {
637
637
  this.log.warn(
638
- `Control: Event is discarded because the value ${event.value} is not a number. State: ${this.inverterInfo.path}.${event.id}`,
638
+ `Control: Event is discarded because the value ${event.value} is not a number. State: ${this.inverterInfo.path}.control.${event.id}`,
639
639
  );
640
640
  this._eventMap.delete(event.id); //forget the event
641
641
  continue;
@@ -21,7 +21,7 @@ class Sdongle extends DriverBase {
21
21
  },
22
22
  {
23
23
  state: { id: 'sdongle.OSVersion', name: 'OS version', type: 'string', unit: '', role: 'value', desc: 'reg:30050, len:15' },
24
- register: { reg: 30050, type: dataType.string, length: 8 },
24
+ register: { reg: 30050, type: dataType.string, length: 9 },
25
25
  },
26
26
  {
27
27
  state: { id: 'sdongle.protokolVersion', name: 'Protokol version', type: 'number', unit: '', role: 'value', desc: 'reg:30068, len:2' },
package/lib/register.js CHANGED
@@ -41,13 +41,39 @@ class Registers {
41
41
  unit: 'kW',
42
42
  role: 'value.power',
43
43
  },
44
- { id: 'collected.usableSurplusPower', name: 'usable surplus power', type: 'number', unit: 'kWh', role: 'value.power' },
44
+ { id: 'collected.usableSurplusPower', name: 'usable surplus power', type: 'number', unit: 'kW', role: 'value.power' },
45
45
  ],
46
46
  fn: inverters => {
47
47
  let actPower = 0;
48
48
  let inPower = 0;
49
49
  let inPowerEff = 0;
50
50
  let chargeDischarge = 0;
51
+
52
+ function calcUsableSurplus() {
53
+ let surplusPower = meterPower;
54
+ if (this.adapter.control) {
55
+ const minSoc = this.adapter.control.get('usableSurplus.minSoc')?.value ?? 0;
56
+ const bufferSoc = this.adapter.control.get('usableSurplus.bufferSoc')?.value ?? 0;
57
+ const residualPower = this.adapter.control.get('usableSurplus.residualPower')?.value ?? 0;
58
+ const soc = this.stateCache.get('collected.SOC')?.value ?? 0;
59
+
60
+ if (soc >= minSoc) {
61
+ surplusPower += chargeDischarge;
62
+ if (soc < bufferSoc || bufferSoc === 0) {
63
+ surplusPower -= residualPower / 1000;
64
+ }
65
+ }
66
+ if (soc >= bufferSoc && bufferSoc > 0) {
67
+ const bufferPower = this.adapter.control.get('usableSurplus.bufferPower')?.value ?? 0;
68
+ surplusPower += bufferPower / 1000;
69
+ }
70
+
71
+ //this.adapter.log.info(`### TEST usableSurplus.minSoc ${minSoc}`);
72
+ }
73
+ if (surplusPower < 0.1) surplusPower = 0;
74
+ return surplusPower;
75
+ }
76
+
51
77
  for (const inverter of inverters) {
52
78
  if (inverter.driverClass != driverClasses.inverter) {
53
79
  continue;
@@ -59,14 +85,14 @@ class Registers {
59
85
  }
60
86
 
61
87
  const meterPower = this.stateCache.get('meter.activePower')?.value ?? 0;
62
- //Überschuss (Differenz)
88
+
63
89
  //Zu geringe Erzeugerenegie
64
90
  let houseConsum = actPower - meterPower;
65
91
  if (houseConsum < 0) {
66
92
  houseConsum = 0;
67
93
  }
68
94
  //Überschuss (Differenz)
69
- const surplusPower = meterPower + chargeDischarge;
95
+ const surplusPower = calcUsableSurplus.bind(this)();
70
96
 
71
97
  this.stateCache.set('collected.inputPower', inPower, { type: 'number', renew: true });
72
98
  this.stateCache.set('collected.inputPowerWithEfficiencyLoss', inPowerEff, { type: 'number' });
package/main.js CHANGED
@@ -13,6 +13,7 @@ const ModbusConnect = require(`${__dirname}/lib/modbus/modbus_connect.js`);
13
13
  const ModbusServer = require(`${__dirname}/lib/modbus/modbus_server.js`);
14
14
  const { driverClasses, dataRefreshRate } = require(`${__dirname}/lib/types.js`);
15
15
  const { Logging, getAstroDate, isSunshine } = require(`${__dirname}/lib/tools.js`);
16
+ const ConfigMap = require(`${__dirname}/lib/controls/config_map.js`);
16
17
 
17
18
  class Sun2000 extends utils.Adapter {
18
19
  /**
@@ -29,8 +30,7 @@ class Sun2000 extends utils.Adapter {
29
30
  this.lastStateUpdatedHigh = 0;
30
31
  this.lastStateUpdatedLow = 0;
31
32
  this.isConnected = false;
32
- this.isReady = false; //v0.8.x
33
-
33
+ this.isReady = false;
34
34
  this.devices = [];
35
35
  this.settings = {
36
36
  highInterval: 20000,
@@ -66,6 +66,9 @@ class Sun2000 extends utils.Adapter {
66
66
  //v0.6.
67
67
  this.logger = new Logging(this); //only for adapter
68
68
 
69
+ //1.1.0
70
+ this.control = new ConfigMap(this);
71
+
69
72
  this.on('ready', this.onReady.bind(this));
70
73
  this.on('stateChange', this.onStateChange.bind(this));
71
74
  // this.on('objectChange', this.onObjectChange.bind(this));
@@ -74,15 +77,14 @@ class Sun2000 extends utils.Adapter {
74
77
  }
75
78
 
76
79
  async initPath() {
77
- /*
78
- await this.extendObject('config', {
80
+ await this.extendObject('control', {
79
81
  type: 'channel',
80
82
  common: {
81
- name: 'channel config',
83
+ name: 'channel control',
82
84
  },
83
85
  native: {},
84
86
  });
85
- */
87
+
86
88
  //inverter
87
89
  await this.extendObject('meter', {
88
90
  type: 'device',
@@ -202,6 +204,8 @@ class Sun2000 extends utils.Adapter {
202
204
 
203
205
  async StartProcess() {
204
206
  await this.initPath();
207
+ await this.control.init();
208
+
205
209
  this.state = new Registers(this);
206
210
  await this.atMidnight();
207
211
  if (this.settings.modbusAdjust) {
@@ -587,8 +591,12 @@ class Sun2000 extends utils.Adapter {
587
591
  onStateChange(id, state) {
588
592
  if (state) {
589
593
  // The state was changed
590
- // sun2000.0.inverter.0.control
594
+ if (state.ack) {
595
+ //this.logger.info(`state ${id} was changed but the ack flag was set. Therefore, no processing takes place!`);
596
+ return;
597
+ }
591
598
  const idArray = id.split('.');
599
+ // sun2000.0.inverter.0.control
592
600
  if (idArray[2] == 'inverter') {
593
601
  const control = this.devices[Number(idArray[3])].instance.control;
594
602
  if (control) {
@@ -600,9 +608,14 @@ class Sun2000 extends utils.Adapter {
600
608
  }
601
609
  //this.log.info(`### state ${id} changed: ${state.val} (ack = ${state.ack})`);
602
610
  }
603
- //New config path
604
- if (idArray[2] == 'config') {
605
- this.log.info(`### state ${id} changed: ${state.val} (ack = ${state.ack})`);
611
+ // sun2000.0.inverter.0.config
612
+ if (idArray[2] == 'control') {
613
+ let serviceId = idArray[3];
614
+ for (let i = 4; i < idArray.length; i++) {
615
+ serviceId += `.${idArray[i]}`;
616
+ }
617
+ //this.log.info(`### id: ${serviceId} state ${id} changed: ${state.val} (ack = ${state.ack})`);
618
+ this.control.set(serviceId, state);
606
619
  }
607
620
  } else {
608
621
  // The state was deleted
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.sun2000",
3
- "version": "1.1.0",
3
+ "version": "1.2.2",
4
4
  "description": "sun2000",
5
5
  "author": {
6
6
  "name": "bolliy",
@@ -28,7 +28,7 @@
28
28
  },
29
29
  "dependencies": {
30
30
  "@iobroker/adapter-core": "^3.2.3",
31
- "modbus-serial": "^8.0.18",
31
+ "modbus-serial": "^8.0.20",
32
32
  "suncalc2": "^1.8.1",
33
33
  "tcp-port-used": "^1.0.2"
34
34
  },
@@ -37,16 +37,16 @@
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.3.0",
40
+ "@eslint/eslintrc": "^3.3.1",
41
41
  "@eslint/js": "^9.20.0",
42
42
  "@iobroker/adapter-dev": "^1.4.0",
43
43
  "@iobroker/eslint-config": "^1.0.1",
44
- "@iobroker/testing": "^5.0.3",
45
- "@tsconfig/node20": "^20.1.4",
44
+ "@iobroker/testing": "^5.0.4",
45
+ "@tsconfig/node20": "^20.1.5",
46
46
  "@types/chai": "^4.3.20",
47
47
  "@types/chai-as-promised": "^7.1.8",
48
48
  "@types/mocha": "^10.0.10",
49
- "@types/node": "^22.13.10",
49
+ "@types/node": "^22.13.16",
50
50
  "@types/proxyquire": "^1.3.31",
51
51
  "@types/sinon": "^17.0.4",
52
52
  "@types/sinon-chai": "^3.2.12",
@@ -55,7 +55,7 @@
55
55
  "globals": "^15.15.0",
56
56
  "mocha": "^11.1.0",
57
57
  "proxyquire": "^2.1.3",
58
- "sinon": "^19.0.4",
58
+ "sinon": "^19.0.5",
59
59
  "sinon-chai": "^3.7.0",
60
60
  "typescript": "~5.7.3"
61
61
  },