iobroker.poolcontrol 1.3.26 → 1.3.27
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 +24 -10
- package/io-package.json +14 -14
- package/lib/helpers/chemistryToolsHelper.js +413 -0
- package/lib/i18n/de.json +16 -1
- package/lib/i18n/en.json +19 -1
- package/lib/i18n/es.json +19 -1
- package/lib/i18n/fr.json +19 -1
- package/lib/i18n/it.json +19 -1
- package/lib/i18n/nl.json +19 -1
- package/lib/i18n/pl.json +19 -1
- package/lib/i18n/pt.json +19 -1
- package/lib/i18n/ru.json +19 -1
- package/lib/i18n/uk.json +19 -1
- package/lib/i18n/zh-cn.json +19 -1
- package/lib/stateDefinitions/chemistryToolsStates.js +599 -0
- package/main.js +14 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -48,7 +48,7 @@ It provides automation for pumps, heating, solar and photovoltaic control as wel
|
|
|
48
48
|
- Priority and block logic
|
|
49
49
|
- Status section under `solar.extended.*`
|
|
50
50
|
|
|
51
|
-
- **Photovoltaic Control
|
|
51
|
+
- **Photovoltaic Control**
|
|
52
52
|
- Pump control based on PV surplus and household consumption
|
|
53
53
|
- Start logic using configurable surplus margins
|
|
54
54
|
- Optional overrun during cloudy phases
|
|
@@ -56,7 +56,7 @@ It provides automation for pumps, heating, solar and photovoltaic control as wel
|
|
|
56
56
|
- Supports external energy object IDs
|
|
57
57
|
- Pump mode: `Automatic (PV)`
|
|
58
58
|
|
|
59
|
-
- **Heating / Heat Pump Control
|
|
59
|
+
- **Heating / Heat Pump Control**
|
|
60
60
|
- Automatic control of heating rod or heat pump
|
|
61
61
|
- Configurable target and safety temperatures
|
|
62
62
|
- Optional pump prerun and overrun
|
|
@@ -102,7 +102,7 @@ It provides automation for pumps, heating, solar and photovoltaic control as wel
|
|
|
102
102
|
- Automatic reset after completed backwash
|
|
103
103
|
- PV integration for circulation targets
|
|
104
104
|
|
|
105
|
-
- **Pressure Sensor Integration
|
|
105
|
+
- **Pressure Sensor Integration**
|
|
106
106
|
- Real-time pressure measurement
|
|
107
107
|
- Trend analysis
|
|
108
108
|
- Learning average values
|
|
@@ -176,6 +176,17 @@ It provides automation for pumps, heating, solar and photovoltaic control as wel
|
|
|
176
176
|
- No chlorine control
|
|
177
177
|
- No automatic dosing
|
|
178
178
|
|
|
179
|
+
**Chemistry Tools**
|
|
180
|
+
- pH Plus calculator
|
|
181
|
+
- pH Minus calculator
|
|
182
|
+
- Salt calculator
|
|
183
|
+
- Manual calculation helpers
|
|
184
|
+
- Pool volume prefill support
|
|
185
|
+
- Optional manual value override
|
|
186
|
+
- Result texts with validation and error handling
|
|
187
|
+
-No automatic chemical dosing
|
|
188
|
+
- Informational only
|
|
189
|
+
|
|
179
190
|
- **AI System**
|
|
180
191
|
- Weather hints (Open-Meteo)
|
|
181
192
|
- Pool recommendations
|
|
@@ -252,6 +263,16 @@ New features are added regularly – please refer to the changelog.
|
|
|
252
263
|
---
|
|
253
264
|
|
|
254
265
|
## Changelog
|
|
266
|
+
### 1.3.27 (2026-05-30)
|
|
267
|
+
|
|
268
|
+
- Added new Chemistry Tools section
|
|
269
|
+
- Added pH Plus Calculator
|
|
270
|
+
- Added pH Minus Calculator
|
|
271
|
+
- Added Salt Calculator
|
|
272
|
+
- Added validation, result texts and error handling for all calculators
|
|
273
|
+
- Added automatic pool volume prefill support
|
|
274
|
+
- Expanded documentation and function overviews
|
|
275
|
+
|
|
255
276
|
### 1.3.26 (2026-05-28)
|
|
256
277
|
|
|
257
278
|
- Reworked multiple warnings and review notes from official ioBroker checks
|
|
@@ -282,13 +303,6 @@ New features are added regularly – please refer to the changelog.
|
|
|
282
303
|
- Switched temperature helper timers to ioBroker adapter timers
|
|
283
304
|
- Improved visibility and troubleshooting for missing or delayed temperature updates
|
|
284
305
|
|
|
285
|
-
### 1.3.22 (2026-05-24)
|
|
286
|
-
|
|
287
|
-
- Improved ORP pH reference synchronization
|
|
288
|
-
- ORP helper now updates pH reference independently from ORP value processing
|
|
289
|
-
- Immediate update of ORP pH reference when pH enabled state or pH value changes
|
|
290
|
-
- Fixed missing pH reference updates when ORP evaluation was blocked, invalid or waiting for measurement conditions
|
|
291
|
-
|
|
292
306
|
## Archived Release History
|
|
293
307
|
|
|
294
308
|
For older releases and archived version history see:
|
package/io-package.json
CHANGED
|
@@ -1,8 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "poolcontrol",
|
|
4
|
-
"version": "1.3.
|
|
4
|
+
"version": "1.3.27",
|
|
5
5
|
"news": {
|
|
6
|
+
"1.3.27": {
|
|
7
|
+
"en": "Added new Chemistry Tools with pH Plus Calculator, pH Minus Calculator and Salt Calculator. Added validation, result texts, error handling and automatic pool volume prefill. Expanded documentation and function overviews.",
|
|
8
|
+
"de": "Neuen Bereich Chemistry Tools mit pH-Plus-Rechner, pH-Minus-Rechner und Salz-Rechner hinzugefügt. Validierungen, Ergebnistexte, Fehlerbehandlung und automatische Vorbelegung des Poolvolumens ergänzt. Dokumentation und Funktionsübersichten erweitert.",
|
|
9
|
+
"ru": "Добавлены новые химические инструменты с калькулятором pH плюс, калькулятором pH минус и калькулятором соли. Добавлена проверка, тексты результатов, обработка ошибок и автоматическое предварительное заполнение объема пула. Расширенная документация и обзоры функций.",
|
|
10
|
+
"pt": "Adicionadas novas ferramentas de química com calculadora pH Plus, calculadora pH menos e calculadora de sal. Adicionados validação, textos de resultados, tratamento de erros e preenchimento automático do volume do pool. Documentação expandida e visões gerais de funções.",
|
|
11
|
+
"nl": "Nieuwe chemiehulpmiddelen toegevoegd met pH Plus-calculator, pH-minuscalculator en Zoutcalculator. Validatie, resultaatteksten, foutafhandeling en automatisch vooraf invullen van poolvolumes toegevoegd. Uitgebreide documentatie en functieoverzichten.",
|
|
12
|
+
"fr": "Ajout de nouveaux outils de chimie avec calculateur de pH Plus, calculateur de pH Moins et calculateur de sel. Ajout de la validation, des textes de résultats, de la gestion des erreurs et du pré-remplissage automatique du volume du pool. Documentation étendue et aperçus des fonctions.",
|
|
13
|
+
"it": "Aggiunti nuovi strumenti di chimica con calcolatore di pH più, calcolatore di pH meno e calcolatore di sale. Aggiunta convalida, testi dei risultati, gestione degli errori e precompilazione automatica del volume del pool. Documentazione estesa e panoramiche delle funzioni.",
|
|
14
|
+
"es": "Se agregaron nuevas herramientas de química con calculadora de pH Plus, calculadora de pH Minus y calculadora de sal. Se agregó validación, textos de resultados, manejo de errores y precarga automática del volumen del grupo. Documentación ampliada y descripciones generales de funciones.",
|
|
15
|
+
"pl": "Dodano nowe narzędzia chemiczne z kalkulatorem pH Plus, kalkulatorem pH Minus i kalkulatorem soli. Dodano weryfikację, teksty wyników, obsługę błędów i automatyczne wstępne wypełnianie objętości puli. Rozszerzona dokumentacja i przeglądy funkcji.",
|
|
16
|
+
"uk": "Додано нові хімічні інструменти з калькулятором pH Plus, калькулятором pH мінус і калькулятором солі. Додано перевірку, тексти результатів, обробку помилок і автоматичне попереднє заповнення обсягу пулу. Розширена документація та огляд функцій.",
|
|
17
|
+
"zh-cn": "添加了新的化学工具,包括 pH 加计算器、pH 减计算器和盐计算器。添加了验证、结果文本、错误处理和自动池容量预填充。扩展的文档和功能概述。"
|
|
18
|
+
},
|
|
6
19
|
"1.3.26": {
|
|
7
20
|
"en": "Reworked several warnings and review notes from official ioBroker checks. Various small improvements and internal cleanups.",
|
|
8
21
|
"de": "Mehrere Warnungen und Review-Hinweise aus offiziellen ioBroker-Checks überarbeitet. Diverse kleine Verbesserungen und interne Bereinigungen.",
|
|
@@ -54,19 +67,6 @@
|
|
|
54
67
|
"pl": "Rozszerzona diagnostyka temperatury: Dodano nowe stany diagnostyczne dla wszystkich czujników temperatury (ostatnia ważna wartość, znacznik czasu, minuty od ostatniej wartości, stan źródła). Dodano mechanizm samonaprawy/odzyskiwania w przypadku zablokowania lub braku zdarzeń związanych z temperaturą. Pomocnik temperatury zaktualizowany do timerów zgodnych z ioBroker.",
|
|
55
68
|
"uk": "Розширено діагностику температури: додано нові діагностичні стани для всіх датчиків температури (останнє дійсне значення, позначка часу, хвилини з останнього значення, статус джерела). Додано механізм самовідновлення/відновлення для зупинених або відсутніх температурних подій. Помічник температури оновлено до таймерів, сумісних із ioBroker.",
|
|
56
69
|
"zh-cn": "温度诊断扩展:为所有温度传感器添加了新的诊断状态(最后一个有效值、时间戳、自最后一个值以来的分钟数、源状态)。添加了针对停滞或丢失温度事件的自我修复/恢复机制。温度助手更新为符合 ioBroker 标准的计时器。"
|
|
57
|
-
},
|
|
58
|
-
"1.3.22": {
|
|
59
|
-
"en": "Improved ORP pH reference synchronization. The ORP helper now updates the pH reference independently from ORP value processing and immediately reflects pH state changes.",
|
|
60
|
-
"de": "ORP-pH-Referenz verbessert. Der ORP-Helper aktualisiert die pH-Referenz jetzt unabhängig von der ORP-Wertverarbeitung und übernimmt pH-Änderungen sofort.",
|
|
61
|
-
"ru": "Улучшена синхронизация эталонного значения pH ОВП. Помощник по ОВП теперь обновляет эталонное значение pH независимо от обработки значений ОВП и немедленно отражает изменения состояния pH.",
|
|
62
|
-
"pt": "Sincronização de referência de pH ORP aprimorada. O auxiliar ORP agora atualiza a referência de pH independentemente do processamento do valor ORP e reflete imediatamente as alterações do estado de pH.",
|
|
63
|
-
"nl": "Verbeterde ORP pH-referentiesynchronisatie. De ORP-helper werkt nu de pH-referentie onafhankelijk van de ORP-waardeverwerking bij en weerspiegelt onmiddellijk veranderingen in de pH-toestand.",
|
|
64
|
-
"fr": "Synchronisation améliorée de la référence ORP pH. L'assistant ORP met désormais à jour la référence pH indépendamment du traitement de la valeur ORP et reflète immédiatement les changements d'état du pH.",
|
|
65
|
-
"it": "Sincronizzazione del riferimento pH ORP migliorata. L'assistente ORP ora aggiorna il riferimento del pH indipendentemente dall'elaborazione del valore ORP e riflette immediatamente i cambiamenti dello stato del pH.",
|
|
66
|
-
"es": "Sincronización de referencia de pH ORP mejorada. El asistente de ORP ahora actualiza la referencia de pH independientemente del procesamiento del valor de ORP y refleja inmediatamente los cambios en el estado del pH.",
|
|
67
|
-
"pl": "Ulepszona synchronizacja odniesienia pH ORP. Pomocnik ORP aktualizuje teraz wartość odniesienia pH niezależnie od przetwarzania wartości ORP i natychmiast odzwierciedla zmiany stanu pH.",
|
|
68
|
-
"uk": "Покращена синхронізація еталонного pH ОВП. Помічник ОВП тепер оновлює еталонний рН незалежно від обробки значення ОВП і негайно відображає зміни стану рН.",
|
|
69
|
-
"zh-cn": "改进了 ORP pH 参考同步。 ORP 助手现在独立于 ORP 值处理更新 pH 参考值,并立即反映 pH 状态变化。"
|
|
70
70
|
}
|
|
71
71
|
},
|
|
72
72
|
"titleLang": {
|
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { I18n } = require('@iobroker/adapter-core');
|
|
4
|
+
|
|
5
|
+
const PH_STEP = 0.1;
|
|
6
|
+
const VOLUME_REFERENCE_L = 10000;
|
|
7
|
+
|
|
8
|
+
const chemistryToolsHelper = {
|
|
9
|
+
adapter: null,
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @param {import('iobroker').Adapter} adapter - ioBroker adapter instance
|
|
13
|
+
*/
|
|
14
|
+
init(adapter) {
|
|
15
|
+
this.adapter = adapter;
|
|
16
|
+
|
|
17
|
+
void this._subscribeStates();
|
|
18
|
+
void this._prefillCalculatorValues();
|
|
19
|
+
|
|
20
|
+
this.adapter.log.debug('[chemistryToolsHelper] Initialized');
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
async _subscribeStates() {
|
|
24
|
+
const ids = [
|
|
25
|
+
'general.pool_size',
|
|
26
|
+
'chemistry.ph.input.current_value',
|
|
27
|
+
|
|
28
|
+
'chemistry.tools.ph_plus_calculator.05_calculate',
|
|
29
|
+
'chemistry.tools.ph_plus_calculator.01_pool_volume_l',
|
|
30
|
+
'chemistry.tools.ph_plus_calculator.02_current_ph',
|
|
31
|
+
'chemistry.tools.ph_plus_calculator.03_target_ph',
|
|
32
|
+
'chemistry.tools.ph_plus_calculator.04_grams_per_10000l_01ph',
|
|
33
|
+
|
|
34
|
+
'chemistry.tools.ph_minus_calculator.05_calculate',
|
|
35
|
+
'chemistry.tools.ph_minus_calculator.01_pool_volume_l',
|
|
36
|
+
'chemistry.tools.ph_minus_calculator.02_current_ph',
|
|
37
|
+
'chemistry.tools.ph_minus_calculator.03_target_ph',
|
|
38
|
+
'chemistry.tools.ph_minus_calculator.04_grams_per_10000l_01ph',
|
|
39
|
+
|
|
40
|
+
'chemistry.tools.salt_calculator.04_calculate',
|
|
41
|
+
'chemistry.tools.salt_calculator.01_pool_volume_l',
|
|
42
|
+
'chemistry.tools.salt_calculator.02_current_salt_ppm',
|
|
43
|
+
'chemistry.tools.salt_calculator.03_target_salt_ppm',
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
for (const id of ids) {
|
|
47
|
+
await this.adapter.subscribeStatesAsync(id);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
this.adapter.log.debug('[chemistryToolsHelper] Own states subscribed');
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* @param {string} id - Changed state ID
|
|
55
|
+
* @param {ioBroker.State | null | undefined} state - Changed state
|
|
56
|
+
* @returns {Promise<void>}
|
|
57
|
+
*/
|
|
58
|
+
async handleStateChange(id, state) {
|
|
59
|
+
if (!state) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
if (id.endsWith('general.pool_size') || id.endsWith('chemistry.ph.input.current_value')) {
|
|
65
|
+
await this._prefillCalculatorValues();
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (
|
|
70
|
+
id.endsWith('chemistry.tools.ph_plus_calculator.05_calculate') &&
|
|
71
|
+
state.ack === false &&
|
|
72
|
+
state.val === true
|
|
73
|
+
) {
|
|
74
|
+
await this._calculatePhPlus();
|
|
75
|
+
await this._setBool('chemistry.tools.ph_plus_calculator.05_calculate', false);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (
|
|
80
|
+
id.endsWith('chemistry.tools.ph_minus_calculator.05_calculate') &&
|
|
81
|
+
state.ack === false &&
|
|
82
|
+
state.val === true
|
|
83
|
+
) {
|
|
84
|
+
await this._calculatePhMinus();
|
|
85
|
+
await this._setBool('chemistry.tools.ph_minus_calculator.05_calculate', false);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (
|
|
89
|
+
id.endsWith('chemistry.tools.salt_calculator.04_calculate') &&
|
|
90
|
+
state.ack === false &&
|
|
91
|
+
state.val === true
|
|
92
|
+
) {
|
|
93
|
+
await this._calculateSalt();
|
|
94
|
+
await this._setBool('chemistry.tools.salt_calculator.04_calculate', false);
|
|
95
|
+
}
|
|
96
|
+
} catch (err) {
|
|
97
|
+
this.adapter.log.warn(`[chemistryToolsHelper] Error in handleStateChange: ${err.message}`);
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
async _prefillCalculatorValues() {
|
|
102
|
+
const poolVolume = await this._readNumber('general.pool_size');
|
|
103
|
+
const currentPh = await this._readNumber('chemistry.ph.input.current_value');
|
|
104
|
+
|
|
105
|
+
await this._prefillNumberIfEmpty('chemistry.tools.ph_plus_calculator.01_pool_volume_l', poolVolume);
|
|
106
|
+
await this._prefillNumberIfEmpty('chemistry.tools.ph_minus_calculator.01_pool_volume_l', poolVolume);
|
|
107
|
+
await this._prefillNumberIfEmpty('chemistry.tools.salt_calculator.01_pool_volume_l', poolVolume);
|
|
108
|
+
|
|
109
|
+
await this._prefillNumberIfEmpty('chemistry.tools.ph_plus_calculator.02_current_ph', currentPh);
|
|
110
|
+
await this._prefillNumberIfEmpty('chemistry.tools.ph_minus_calculator.02_current_ph', currentPh);
|
|
111
|
+
},
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Calculates the pH Plus amount using the manufacturer dosage formula.
|
|
115
|
+
*
|
|
116
|
+
* @returns {Promise<void>}
|
|
117
|
+
*/
|
|
118
|
+
async _calculatePhPlus() {
|
|
119
|
+
const base = 'chemistry.tools.ph_plus_calculator';
|
|
120
|
+
|
|
121
|
+
const poolVolume = await this._readNumber(`${base}.01_pool_volume_l`);
|
|
122
|
+
const currentPh = await this._readNumber(`${base}.02_current_ph`);
|
|
123
|
+
const targetPh = await this._readNumber(`${base}.03_target_ph`);
|
|
124
|
+
const dosageFactor = await this._readNumber(`${base}.04_grams_per_10000l_01ph`);
|
|
125
|
+
|
|
126
|
+
const validation = this._validateInputs({
|
|
127
|
+
type: 'plus',
|
|
128
|
+
poolVolume,
|
|
129
|
+
currentPh,
|
|
130
|
+
targetPh,
|
|
131
|
+
dosageFactor,
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
if (!validation.valid) {
|
|
135
|
+
await this._writeInvalidResult(base, validation.error);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const resultGrams = this._calculateAmountGrams(currentPh, targetPh, poolVolume, dosageFactor);
|
|
140
|
+
const roundedGrams = Math.round(resultGrams);
|
|
141
|
+
|
|
142
|
+
const resultText =
|
|
143
|
+
`${I18n.translate('Calculated amount')}: ${roundedGrams} g pH Plus. ` +
|
|
144
|
+
`${I18n.translate('Reference value based on common manufacturer dosage.')} ` +
|
|
145
|
+
`${I18n.translate('Follow the manufacturer instructions and re-measure afterwards.')}`;
|
|
146
|
+
|
|
147
|
+
await this._writeValidResult(base, roundedGrams, resultText);
|
|
148
|
+
},
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Calculates the pH Minus amount using the manufacturer dosage formula.
|
|
152
|
+
*
|
|
153
|
+
* @returns {Promise<void>}
|
|
154
|
+
*/
|
|
155
|
+
async _calculatePhMinus() {
|
|
156
|
+
const base = 'chemistry.tools.ph_minus_calculator';
|
|
157
|
+
|
|
158
|
+
const poolVolume = await this._readNumber(`${base}.01_pool_volume_l`);
|
|
159
|
+
const currentPh = await this._readNumber(`${base}.02_current_ph`);
|
|
160
|
+
const targetPh = await this._readNumber(`${base}.03_target_ph`);
|
|
161
|
+
const dosageFactor = await this._readNumber(`${base}.04_grams_per_10000l_01ph`);
|
|
162
|
+
|
|
163
|
+
const validation = this._validateInputs({
|
|
164
|
+
type: 'minus',
|
|
165
|
+
poolVolume,
|
|
166
|
+
currentPh,
|
|
167
|
+
targetPh,
|
|
168
|
+
dosageFactor,
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
if (!validation.valid) {
|
|
172
|
+
await this._writeInvalidResult(base, validation.error);
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const resultGrams = this._calculateAmountGrams(currentPh, targetPh, poolVolume, dosageFactor);
|
|
177
|
+
const roundedGrams = Math.round(resultGrams);
|
|
178
|
+
|
|
179
|
+
const resultText =
|
|
180
|
+
`${I18n.translate('Calculated amount')}: ${roundedGrams} g pH Minus. ` +
|
|
181
|
+
`${I18n.translate('Reference value based on common manufacturer dosage.')} ` +
|
|
182
|
+
`${I18n.translate('Follow the manufacturer instructions and re-measure afterwards.')}`;
|
|
183
|
+
|
|
184
|
+
await this._writeValidResult(base, roundedGrams, resultText);
|
|
185
|
+
},
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Calculates the salt amount needed to raise the salt concentration.
|
|
189
|
+
*
|
|
190
|
+
* @returns {Promise<void>} Resolves when the salt calculation result has been written.
|
|
191
|
+
*/
|
|
192
|
+
async _calculateSalt() {
|
|
193
|
+
const base = 'chemistry.tools.salt_calculator';
|
|
194
|
+
|
|
195
|
+
const poolVolume = await this._readNumber(`${base}.01_pool_volume_l`);
|
|
196
|
+
const currentSalt = await this._readNumber(`${base}.02_current_salt_ppm`);
|
|
197
|
+
const targetSalt = await this._readNumber(`${base}.03_target_salt_ppm`);
|
|
198
|
+
|
|
199
|
+
if (!Number.isFinite(poolVolume) || poolVolume <= 0) {
|
|
200
|
+
await this._writeInvalidSaltResult(base, I18n.translate('Pool volume must be greater than 0 liters.'));
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (!Number.isFinite(currentSalt) || currentSalt < 0) {
|
|
205
|
+
await this._writeInvalidSaltResult(
|
|
206
|
+
base,
|
|
207
|
+
I18n.translate('Current salt concentration must be 0 ppm or higher.'),
|
|
208
|
+
);
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (!Number.isFinite(targetSalt) || targetSalt <= currentSalt) {
|
|
213
|
+
await this._writeInvalidSaltResult(
|
|
214
|
+
base,
|
|
215
|
+
I18n.translate('Target salt concentration must be higher than the current salt concentration.'),
|
|
216
|
+
);
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const resultKg = ((targetSalt - currentSalt) * poolVolume) / 1000000;
|
|
221
|
+
const roundedKg = Math.round(resultKg * 10) / 10;
|
|
222
|
+
|
|
223
|
+
const resultText =
|
|
224
|
+
`${I18n.translate('Calculated amount')}: ${roundedKg} kg ${I18n.translate('salt')}. ` +
|
|
225
|
+
`${I18n.translate('Reference value for raising the salt concentration in pool water.')} ` +
|
|
226
|
+
`${I18n.translate('Follow the salt system manufacturer instructions and add salt gradually.')}`;
|
|
227
|
+
|
|
228
|
+
await this._writeValidSaltResult(base, roundedKg, resultText);
|
|
229
|
+
},
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* @param {object} input - Calculator input values
|
|
233
|
+
* @param {'plus' | 'minus'} input.type - Calculator type
|
|
234
|
+
* @param {number} input.poolVolume - Pool volume in liters
|
|
235
|
+
* @param {number} input.currentPh - Current pH value
|
|
236
|
+
* @param {number} input.targetPh - Target pH value
|
|
237
|
+
* @param {number} input.dosageFactor - Dosage factor in grams per 10,000 l and 0.1 pH
|
|
238
|
+
* @returns {{ valid: boolean, error: string }} Validation result with an optional translated error message.
|
|
239
|
+
*/
|
|
240
|
+
_validateInputs(input) {
|
|
241
|
+
if (!Number.isFinite(input.poolVolume) || input.poolVolume <= 0) {
|
|
242
|
+
return { valid: false, error: I18n.translate('Pool volume must be greater than 0 liters.') };
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if (!Number.isFinite(input.currentPh) || input.currentPh <= 0 || input.currentPh > 14) {
|
|
246
|
+
return { valid: false, error: I18n.translate('Current pH value must be between 0 and 14.') };
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (!Number.isFinite(input.targetPh) || input.targetPh <= 0 || input.targetPh > 14) {
|
|
250
|
+
return { valid: false, error: I18n.translate('Target pH value must be between 0 and 14.') };
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
if (!Number.isFinite(input.dosageFactor) || input.dosageFactor <= 0) {
|
|
254
|
+
return { valid: false, error: I18n.translate('Dosage factor must be greater than 0 grams.') };
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (input.type === 'plus' && input.targetPh <= input.currentPh) {
|
|
258
|
+
return {
|
|
259
|
+
valid: false,
|
|
260
|
+
error: I18n.translate('For pH Plus, the target pH value must be higher than the current pH value.'),
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
if (input.type === 'minus' && input.targetPh >= input.currentPh) {
|
|
265
|
+
return {
|
|
266
|
+
valid: false,
|
|
267
|
+
error: I18n.translate('For pH Minus, the target pH value must be lower than the current pH value.'),
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
return { valid: true, error: '' };
|
|
272
|
+
},
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* @param {number} currentPh - Current pH value
|
|
276
|
+
* @param {number} targetPh - Target pH value
|
|
277
|
+
* @param {number} poolVolume - Pool volume in liters
|
|
278
|
+
* @param {number} dosageFactor - Dosage factor in grams per 10,000 l and 0.1 pH
|
|
279
|
+
* @returns {number} Calculated amount in grams.
|
|
280
|
+
*/
|
|
281
|
+
_calculateAmountGrams(currentPh, targetPh, poolVolume, dosageFactor) {
|
|
282
|
+
const phDifference = Math.abs(targetPh - currentPh);
|
|
283
|
+
const phSteps = phDifference / PH_STEP;
|
|
284
|
+
const volumeFactor = poolVolume / VOLUME_REFERENCE_L;
|
|
285
|
+
|
|
286
|
+
return phSteps * volumeFactor * dosageFactor;
|
|
287
|
+
},
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* @param {string} base - Base state path of the calculator
|
|
291
|
+
* @param {number} grams - Calculated amount in grams
|
|
292
|
+
* @param {string} resultText - Readable result text
|
|
293
|
+
* @returns {Promise<void>}
|
|
294
|
+
*/
|
|
295
|
+
async _writeValidResult(base, grams, resultText) {
|
|
296
|
+
const now = Date.now();
|
|
297
|
+
|
|
298
|
+
await this._setNumber(`${base}.10_result_grams`, grams);
|
|
299
|
+
await this._setString(`${base}.11_result_text`, resultText);
|
|
300
|
+
await this._setBool(`${base}.12_valid`, true);
|
|
301
|
+
await this._setString(`${base}.13_last_error`, '');
|
|
302
|
+
await this._setNumber(`${base}.14_last_calculated_at`, now);
|
|
303
|
+
},
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* @param {string} base - Base state path of the calculator
|
|
307
|
+
* @param {string} errorText - Validation error text
|
|
308
|
+
* @returns {Promise<void>}
|
|
309
|
+
*/
|
|
310
|
+
async _writeInvalidResult(base, errorText) {
|
|
311
|
+
const now = Date.now();
|
|
312
|
+
|
|
313
|
+
await this._setNumber(`${base}.10_result_grams`, 0);
|
|
314
|
+
await this._setString(`${base}.11_result_text`, errorText);
|
|
315
|
+
await this._setBool(`${base}.12_valid`, false);
|
|
316
|
+
await this._setString(`${base}.13_last_error`, errorText);
|
|
317
|
+
await this._setNumber(`${base}.14_last_calculated_at`, now);
|
|
318
|
+
},
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* @param {string} base - Base state path of the salt calculator
|
|
322
|
+
* @param {number} kg - Calculated salt amount in kilograms
|
|
323
|
+
* @param {string} resultText - Readable result text
|
|
324
|
+
* @returns {Promise<void>} Resolves when the valid salt result states have been updated.
|
|
325
|
+
*/
|
|
326
|
+
async _writeValidSaltResult(base, kg, resultText) {
|
|
327
|
+
const now = Date.now();
|
|
328
|
+
|
|
329
|
+
await this._setNumber(`${base}.10_result_kg`, kg);
|
|
330
|
+
await this._setString(`${base}.11_result_text`, resultText);
|
|
331
|
+
await this._setBool(`${base}.12_valid`, true);
|
|
332
|
+
await this._setString(`${base}.13_last_error`, '');
|
|
333
|
+
await this._setNumber(`${base}.14_last_calculated_at`, now);
|
|
334
|
+
},
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* @param {string} base - Base state path of the salt calculator
|
|
338
|
+
* @param {string} errorText - Validation error text
|
|
339
|
+
* @returns {Promise<void>} Resolves when the invalid salt result states have been updated.
|
|
340
|
+
*/
|
|
341
|
+
async _writeInvalidSaltResult(base, errorText) {
|
|
342
|
+
const now = Date.now();
|
|
343
|
+
|
|
344
|
+
await this._setNumber(`${base}.10_result_kg`, 0);
|
|
345
|
+
await this._setString(`${base}.11_result_text`, errorText);
|
|
346
|
+
await this._setBool(`${base}.12_valid`, false);
|
|
347
|
+
await this._setString(`${base}.13_last_error`, errorText);
|
|
348
|
+
await this._setNumber(`${base}.14_last_calculated_at`, now);
|
|
349
|
+
},
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* @param {string} id - Target state ID
|
|
353
|
+
* @param {number} newValue - Value to write if target is empty
|
|
354
|
+
* @returns {Promise<void>}
|
|
355
|
+
*/
|
|
356
|
+
async _prefillNumberIfEmpty(id, newValue) {
|
|
357
|
+
if (!Number.isFinite(newValue) || newValue <= 0) {
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
const currentValue = await this._readNumber(id);
|
|
362
|
+
|
|
363
|
+
if (currentValue > 0) {
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
await this._setNumber(id, newValue);
|
|
368
|
+
},
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* @param {string} id - State ID
|
|
372
|
+
* @returns {Promise<number>} Numeric state value, or 0 if the state is missing or invalid.
|
|
373
|
+
*/
|
|
374
|
+
async _readNumber(id) {
|
|
375
|
+
const state = await this.adapter.getStateAsync(id);
|
|
376
|
+
const value = Number(state?.val);
|
|
377
|
+
return Number.isFinite(value) ? value : 0;
|
|
378
|
+
},
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* @param {string} id - State ID
|
|
382
|
+
* @param {string} value - Value to write
|
|
383
|
+
* @returns {Promise<void>}
|
|
384
|
+
*/
|
|
385
|
+
async _setString(id, value) {
|
|
386
|
+
await this.adapter.setStateChangedAsync(id, { val: String(value ?? ''), ack: true });
|
|
387
|
+
},
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* @param {string} id - State ID
|
|
391
|
+
* @param {number} value - Value to write
|
|
392
|
+
* @returns {Promise<void>}
|
|
393
|
+
*/
|
|
394
|
+
async _setNumber(id, value) {
|
|
395
|
+
const numberValue = Number(value);
|
|
396
|
+
await this.adapter.setStateChangedAsync(id, { val: Number.isFinite(numberValue) ? numberValue : 0, ack: true });
|
|
397
|
+
},
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* @param {string} id - State ID
|
|
401
|
+
* @param {boolean} value - Value to write
|
|
402
|
+
* @returns {Promise<void>}
|
|
403
|
+
*/
|
|
404
|
+
async _setBool(id, value) {
|
|
405
|
+
await this.adapter.setStateChangedAsync(id, { val: !!value, ack: true });
|
|
406
|
+
},
|
|
407
|
+
|
|
408
|
+
cleanup() {
|
|
409
|
+
this.adapter = null;
|
|
410
|
+
},
|
|
411
|
+
};
|
|
412
|
+
|
|
413
|
+
module.exports = chemistryToolsHelper;
|
package/lib/i18n/de.json
CHANGED
|
@@ -327,5 +327,20 @@
|
|
|
327
327
|
"Current ORP value": "Aktueller ORP-Wert",
|
|
328
328
|
"pH reference": "pH-Referenz",
|
|
329
329
|
"Status": "Status",
|
|
330
|
-
"ORP evaluation is disabled.": "ORP-Auswertung ist deaktiviert."
|
|
330
|
+
"ORP evaluation is disabled.": "ORP-Auswertung ist deaktiviert.",
|
|
331
|
+
|
|
332
|
+
"Calculated amount": "Berechnete Menge",
|
|
333
|
+
"Reference value based on common manufacturer dosage.": "Orientierungswert nach üblicher Herstellerdosierung.",
|
|
334
|
+
"Follow the manufacturer instructions and re-measure afterwards.": "Bitte Herstellerangaben beachten und anschließend erneut messen.",
|
|
335
|
+
"Pool volume must be greater than 0 liters.": "Das Poolvolumen muss größer als 0 Liter sein.",
|
|
336
|
+
"Current pH value must be between 0 and 14.": "Der aktuelle pH-Wert muss zwischen 0 und 14 liegen.",
|
|
337
|
+
"Target pH value must be between 0 and 14.": "Der Ziel-pH-Wert muss zwischen 0 und 14 liegen.",
|
|
338
|
+
"Dosage factor must be greater than 0 grams.": "Der Dosierfaktor muss größer als 0 Gramm sein.",
|
|
339
|
+
"For pH Plus, the target pH value must be higher than the current pH value.": "Für pH Plus muss der Ziel-pH-Wert höher als der aktuelle pH-Wert sein.",
|
|
340
|
+
"For pH Minus, the target pH value must be lower than the current pH value.": "Für pH Minus muss der Ziel-pH-Wert niedriger als der aktuelle pH-Wert sein.",
|
|
341
|
+
"Current salt concentration must be 0 ppm or higher.": "Die aktuelle Salzkonzentration muss 0 ppm oder höher sein.",
|
|
342
|
+
"Target salt concentration must be higher than the current salt concentration.": "Die Ziel-Salzkonzentration muss höher als die aktuelle Salzkonzentration sein.",
|
|
343
|
+
"Reference value for raising the salt concentration in pool water.": "Referenzwert für die Erhöhung der Salzkonzentration im Poolwasser.",
|
|
344
|
+
"Follow the salt system manufacturer instructions and add salt gradually.": "Bitte die Anweisungen des Salzsystem-Herstellers befolgen und das Salz allmählich hinzufügen.",
|
|
345
|
+
"salt": "Salz"
|
|
331
346
|
}
|
package/lib/i18n/en.json
CHANGED
|
@@ -351,5 +351,23 @@
|
|
|
351
351
|
"pH reference": "pH reference",
|
|
352
352
|
"Status": "Status",
|
|
353
353
|
"Recommendation": "Recommendation",
|
|
354
|
-
"ORP evaluation is disabled.": "ORP evaluation is disabled."
|
|
354
|
+
"ORP evaluation is disabled.": "ORP evaluation is disabled.",
|
|
355
|
+
|
|
356
|
+
"Calculated amount": "Calculated amount",
|
|
357
|
+
"Reference value based on common manufacturer dosage.": "Reference value based on common manufacturer dosage.",
|
|
358
|
+
"Follow the manufacturer instructions and re-measure afterwards.": "Follow the manufacturer instructions and re-measure afterwards.",
|
|
359
|
+
|
|
360
|
+
"Pool volume must be greater than 0 liters.": "Pool volume must be greater than 0 liters.",
|
|
361
|
+
"Current pH value must be between 0 and 14.": "Current pH value must be between 0 and 14.",
|
|
362
|
+
"Target pH value must be between 0 and 14.": "Target pH value must be between 0 and 14.",
|
|
363
|
+
"Dosage factor must be greater than 0 grams.": "Dosage factor must be greater than 0 grams.",
|
|
364
|
+
|
|
365
|
+
"For pH Plus, the target pH value must be higher than the current pH value.": "For pH Plus, the target pH value must be higher than the current pH value.",
|
|
366
|
+
"For pH Minus, the target pH value must be lower than the current pH value.": "For pH Minus, the target pH value must be lower than the current pH value.",
|
|
367
|
+
"Current salt concentration must be 0 ppm or higher.": "Current salt concentration must be 0 ppm or higher.",
|
|
368
|
+
|
|
369
|
+
"Target salt concentration must be higher than the current salt concentration.": "Target salt concentration must be higher than the current salt concentration.",
|
|
370
|
+
"Reference value for raising the salt concentration in pool water.": "Reference value for raising the salt concentration in pool water.",
|
|
371
|
+
"Follow the salt system manufacturer instructions and add salt gradually.": "Follow the salt system manufacturer instructions and add salt gradually.",
|
|
372
|
+
"salt": "salt"
|
|
355
373
|
}
|
package/lib/i18n/es.json
CHANGED
|
@@ -347,5 +347,23 @@
|
|
|
347
347
|
"Current ORP value": "Valor actual de ORP",
|
|
348
348
|
"pH reference": "Referencia de pH",
|
|
349
349
|
"Status": "Estado",
|
|
350
|
-
"ORP evaluation is disabled.": "La evaluación de ORP está desactivada."
|
|
350
|
+
"ORP evaluation is disabled.": "La evaluación de ORP está desactivada.",
|
|
351
|
+
|
|
352
|
+
"Calculated amount": "Cantidad calculada",
|
|
353
|
+
"Reference value based on common manufacturer dosage.": "Valor de referencia basado en la dosificación habitual del fabricante.",
|
|
354
|
+
"Follow the manufacturer instructions and re-measure afterwards.": "Siga las instrucciones del fabricante y vuelva a medir después.",
|
|
355
|
+
|
|
356
|
+
"Pool volume must be greater than 0 liters.": "El volumen de la piscina debe ser superior a 0 litros.",
|
|
357
|
+
"Current pH value must be between 0 and 14.": "El valor actual de pH debe estar entre 0 y 14.",
|
|
358
|
+
"Target pH value must be between 0 and 14.": "El valor objetivo de pH debe estar entre 0 y 14.",
|
|
359
|
+
"Dosage factor must be greater than 0 grams.": "El factor de dosificación debe ser superior a 0 gramos.",
|
|
360
|
+
|
|
361
|
+
"For pH Plus, the target pH value must be higher than the current pH value.": "Para pH Plus, el valor objetivo de pH debe ser superior al valor actual de pH.",
|
|
362
|
+
"For pH Minus, the target pH value must be lower than the current pH value.": "Para pH Minus, el valor objetivo de pH debe ser inferior al valor actual de pH.",
|
|
363
|
+
"Current salt concentration must be 0 ppm or higher.": "La concentración actual de sal debe ser de 0 ppm o superior.",
|
|
364
|
+
|
|
365
|
+
"Target salt concentration must be higher than the current salt concentration.": "La concentración objetivo de sal debe ser superior a la concentración actual de sal.",
|
|
366
|
+
"Reference value for raising the salt concentration in pool water.": "Valor de referencia para aumentar la concentración de sal en el agua de la piscina.",
|
|
367
|
+
"Follow the salt system manufacturer instructions and add salt gradually.": "Siga las instrucciones del fabricante del sistema de sal y añada sal gradualmente.",
|
|
368
|
+
"salt": "sal"
|
|
351
369
|
}
|
package/lib/i18n/fr.json
CHANGED
|
@@ -347,5 +347,23 @@
|
|
|
347
347
|
"Current ORP value": "Valeur ORP actuelle",
|
|
348
348
|
"pH reference": "Référence pH",
|
|
349
349
|
"Status": "État",
|
|
350
|
-
"ORP evaluation is disabled.": "L'évaluation ORP est désactivée."
|
|
350
|
+
"ORP evaluation is disabled.": "L'évaluation ORP est désactivée.",
|
|
351
|
+
|
|
352
|
+
"Calculated amount": "Quantité calculée",
|
|
353
|
+
"Reference value based on common manufacturer dosage.": "Valeur de référence basée sur le dosage habituel du fabricant.",
|
|
354
|
+
"Follow the manufacturer instructions and re-measure afterwards.": "Veuillez suivre les instructions du fabricant et mesurer à nouveau ensuite.",
|
|
355
|
+
|
|
356
|
+
"Pool volume must be greater than 0 liters.": "Le volume de la piscine doit être supérieur à 0 litre.",
|
|
357
|
+
"Current pH value must be between 0 and 14.": "La valeur actuelle du pH doit être comprise entre 0 et 14.",
|
|
358
|
+
"Target pH value must be between 0 and 14.": "La valeur cible du pH doit être comprise entre 0 et 14.",
|
|
359
|
+
"Dosage factor must be greater than 0 grams.": "Le facteur de dosage doit être supérieur à 0 gramme.",
|
|
360
|
+
|
|
361
|
+
"For pH Plus, the target pH value must be higher than the current pH value.": "Pour pH Plus, la valeur cible du pH doit être supérieure à la valeur actuelle du pH.",
|
|
362
|
+
"For pH Minus, the target pH value must be lower than the current pH value.": "Pour pH Minus, la valeur cible du pH doit être inférieure à la valeur actuelle du pH.",
|
|
363
|
+
"Current salt concentration must be 0 ppm or higher.": "La concentration actuelle en sel doit être de 0 ppm ou plus.",
|
|
364
|
+
|
|
365
|
+
"Target salt concentration must be higher than the current salt concentration.": "La concentration cible en sel doit être supérieure à la concentration actuelle en sel.",
|
|
366
|
+
"Reference value for raising the salt concentration in pool water.": "Valeur de référence pour augmenter la concentration en sel dans l’eau de la piscine.",
|
|
367
|
+
"Follow the salt system manufacturer instructions and add salt gradually.": "Respectez les instructions du fabricant du système au sel et ajoutez le sel progressivement.",
|
|
368
|
+
"salt": "sel"
|
|
351
369
|
}
|
package/lib/i18n/it.json
CHANGED
|
@@ -347,5 +347,23 @@
|
|
|
347
347
|
"Current ORP value": "Valore ORP attuale",
|
|
348
348
|
"pH reference": "Riferimento pH",
|
|
349
349
|
"Status": "Stato",
|
|
350
|
-
"ORP evaluation is disabled.": "La valutazione ORP è disattivata."
|
|
350
|
+
"ORP evaluation is disabled.": "La valutazione ORP è disattivata.",
|
|
351
|
+
|
|
352
|
+
"Calculated amount": "Quantità calcolata",
|
|
353
|
+
"Reference value based on common manufacturer dosage.": "Valore di riferimento basato sul dosaggio standard del produttore.",
|
|
354
|
+
"Follow the manufacturer instructions and re-measure afterwards.": "Seguire le istruzioni del produttore ed effettuare una nuova misurazione successivamente.",
|
|
355
|
+
|
|
356
|
+
"Pool volume must be greater than 0 liters.": "Il volume della piscina deve essere maggiore di 0 litri.",
|
|
357
|
+
"Current pH value must be between 0 and 14.": "Il valore attuale del pH deve essere compreso tra 0 e 14.",
|
|
358
|
+
"Target pH value must be between 0 and 14.": "Il valore target del pH deve essere compreso tra 0 e 14.",
|
|
359
|
+
"Dosage factor must be greater than 0 grams.": "Il fattore di dosaggio deve essere maggiore di 0 grammi.",
|
|
360
|
+
|
|
361
|
+
"For pH Plus, the target pH value must be higher than the current pH value.": "Per pH Plus, il valore target del pH deve essere superiore al valore attuale del pH.",
|
|
362
|
+
"For pH Minus, the target pH value must be lower than the current pH value.": "Per pH Minus, il valore target del pH deve essere inferiore al valore attuale del pH.",
|
|
363
|
+
"Current salt concentration must be 0 ppm or higher.": "La concentrazione attuale di sale deve essere pari o superiore a 0 ppm.",
|
|
364
|
+
|
|
365
|
+
"Target salt concentration must be higher than the current salt concentration.": "La concentrazione target di sale deve essere superiore alla concentrazione attuale di sale.",
|
|
366
|
+
"Reference value for raising the salt concentration in pool water.": "Valore di riferimento per aumentare la concentrazione di sale nell’acqua della piscina.",
|
|
367
|
+
"Follow the salt system manufacturer instructions and add salt gradually.": "Seguire le istruzioni del produttore del sistema a sale e aggiungere il sale gradualmente.",
|
|
368
|
+
"salt": "sale"
|
|
351
369
|
}
|