iobroker.poolcontrol 1.3.14 → 1.3.17

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.
@@ -651,6 +651,220 @@ async function createChemistryPhStates(adapter) {
651
651
  persist: true,
652
652
  });
653
653
 
654
+ // -------------------------------------------------------------
655
+ // History
656
+ // -------------------------------------------------------------
657
+ await createChannel(adapter, 'chemistry.ph.history', {
658
+ en: 'History',
659
+ de: 'Historie',
660
+ });
661
+
662
+ await createState(adapter, 'chemistry.ph.history.samples_json', {
663
+ name: {
664
+ en: 'Samples JSON',
665
+ de: 'Messwerte JSON',
666
+ },
667
+ desc: {
668
+ en: 'Internal JSON list of valid pH samples for up to 30 days.',
669
+ de: 'Interne JSON-Liste gültiger pH-Messpunkte für bis zu 30 Tage.',
670
+ },
671
+ type: 'string',
672
+ role: 'json',
673
+ read: true,
674
+ write: false,
675
+ def: '[]',
676
+ persist: true,
677
+ });
678
+
679
+ await createState(adapter, 'chemistry.ph.history.samples_count', {
680
+ name: {
681
+ en: 'Samples count',
682
+ de: 'Anzahl Messwerte',
683
+ },
684
+ desc: {
685
+ en: 'Number of stored valid pH samples.',
686
+ de: 'Anzahl gespeicherter gültiger pH-Messpunkte.',
687
+ },
688
+ type: 'number',
689
+ role: 'value',
690
+ read: true,
691
+ write: false,
692
+ def: 0,
693
+ persist: true,
694
+ });
695
+
696
+ await createState(adapter, 'chemistry.ph.history.oldest_sample_at', {
697
+ name: {
698
+ en: 'Oldest sample time',
699
+ de: 'Ältester Messwert',
700
+ },
701
+ type: 'string',
702
+ role: 'value.time',
703
+ read: true,
704
+ write: false,
705
+ def: '',
706
+ persist: true,
707
+ });
708
+
709
+ await createState(adapter, 'chemistry.ph.history.newest_sample_at', {
710
+ name: {
711
+ en: 'Newest sample time',
712
+ de: 'Neuester Messwert',
713
+ },
714
+ type: 'string',
715
+ role: 'value.time',
716
+ read: true,
717
+ write: false,
718
+ def: '',
719
+ persist: true,
720
+ });
721
+
722
+ // -------------------------------------------------------------
723
+ // Trend
724
+ // -------------------------------------------------------------
725
+ await createChannel(adapter, 'chemistry.ph.trend', {
726
+ en: 'Trend',
727
+ de: 'Trend',
728
+ });
729
+
730
+ const phTrendStates = [
731
+ ['reference_24h_value', '24h reference value', '24h-Referenzwert'],
732
+ ['reference_7d_value', '7 day reference value', '7-Tage-Referenzwert'],
733
+ ['reference_30d_value', '30 day reference value', '30-Tage-Referenzwert'],
734
+ ['delta_24h', '24h delta', '24h-Differenz'],
735
+ ['delta_7d', '7 day delta', '7-Tage-Differenz'],
736
+ ['delta_30d', '30 day delta', '30-Tage-Differenz'],
737
+ ];
738
+
739
+ for (const [stateId, enName, deName] of phTrendStates) {
740
+ await createState(adapter, `chemistry.ph.trend.${stateId}`, {
741
+ name: {
742
+ en: enName,
743
+ de: deName,
744
+ },
745
+ type: 'number',
746
+ role: 'value',
747
+ read: true,
748
+ write: false,
749
+ def: 0,
750
+ persist: true,
751
+ });
752
+ }
753
+
754
+ const phTrendTimeStates = [
755
+ ['reference_24h_at', '24h reference time', 'Zeitpunkt des 24h-Referenzwerts'],
756
+ ['reference_7d_at', '7 day reference time', 'Zeitpunkt des 7-Tage-Referenzwerts'],
757
+ ['reference_30d_at', '30 day reference time', 'Zeitpunkt des 30-Tage-Referenzwerts'],
758
+ ];
759
+
760
+ for (const [stateId, enName, deName] of phTrendTimeStates) {
761
+ await createState(adapter, `chemistry.ph.trend.${stateId}`, {
762
+ name: {
763
+ en: enName,
764
+ de: deName,
765
+ },
766
+ type: 'string',
767
+ role: 'value.time',
768
+ read: true,
769
+ write: false,
770
+ def: '',
771
+ persist: true,
772
+ });
773
+ }
774
+
775
+ await createState(adapter, 'chemistry.ph.trend.direction', {
776
+ name: {
777
+ en: 'Trend direction',
778
+ de: 'Trendrichtung',
779
+ },
780
+ desc: {
781
+ en: 'Overall trend direction: stable, rising, falling or not enough data.',
782
+ de: 'Gesamte Trendrichtung: stabil, steigend, fallend oder noch nicht genug Daten.',
783
+ },
784
+ type: 'string',
785
+ role: 'text',
786
+ read: true,
787
+ write: false,
788
+ def: 'not_enough_data',
789
+ persist: true,
790
+ });
791
+
792
+ await createState(adapter, 'chemistry.ph.trend.status', {
793
+ name: {
794
+ en: 'Trend status',
795
+ de: 'Trendstatus',
796
+ },
797
+ desc: {
798
+ en: 'Readable status of the pH trend development.',
799
+ de: 'Lesbarer Status der pH-Trendentwicklung.',
800
+ },
801
+ type: 'string',
802
+ role: 'text',
803
+ read: true,
804
+ write: false,
805
+ def: 'not_enough_data',
806
+ persist: true,
807
+ });
808
+
809
+ // -------------------------------------------------------------
810
+ // Outputs
811
+ // -------------------------------------------------------------
812
+ await createChannel(adapter, 'chemistry.ph.outputs', {
813
+ en: 'Outputs',
814
+ de: 'Ausgaben',
815
+ });
816
+
817
+ await createState(adapter, 'chemistry.ph.outputs.summary_text', {
818
+ name: {
819
+ en: 'Summary text',
820
+ de: 'Zusammenfassung Text',
821
+ },
822
+ desc: {
823
+ en: 'Readable pH summary text.',
824
+ de: 'Lesbare pH-Zusammenfassung.',
825
+ },
826
+ type: 'string',
827
+ role: 'text',
828
+ read: true,
829
+ write: false,
830
+ def: '',
831
+ persist: true,
832
+ });
833
+
834
+ await createState(adapter, 'chemistry.ph.outputs.summary_html', {
835
+ name: {
836
+ en: 'Summary HTML',
837
+ de: 'Zusammenfassung HTML',
838
+ },
839
+ desc: {
840
+ en: 'HTML summary for VIS or widgets.',
841
+ de: 'HTML-Zusammenfassung für VIS oder Widgets.',
842
+ },
843
+ type: 'string',
844
+ role: 'html',
845
+ read: true,
846
+ write: false,
847
+ def: '',
848
+ persist: true,
849
+ });
850
+
851
+ await createState(adapter, 'chemistry.ph.outputs.summary_json', {
852
+ name: {
853
+ en: 'Summary JSON',
854
+ de: 'Zusammenfassung JSON',
855
+ },
856
+ desc: {
857
+ en: 'Structured pH summary as JSON.',
858
+ de: 'Strukturierte pH-Zusammenfassung als JSON.',
859
+ },
860
+ type: 'string',
861
+ role: 'json',
862
+ read: true,
863
+ write: false,
864
+ def: '',
865
+ persist: true,
866
+ });
867
+
654
868
  // -------------------------------------------------------------
655
869
  // Debug
656
870
  // -------------------------------------------------------------
@@ -285,6 +285,157 @@ async function createSpeechStates(adapter) {
285
285
 
286
286
  adapter.log.debug('[speechStates] Amazon Alexa quiet-time states checked and created.');
287
287
 
288
+ // ------------------------------------------------------------------
289
+ // FIX: Speech sources - user configurable message sources
290
+ // ------------------------------------------------------------------
291
+
292
+ await adapter.setObjectNotExistsAsync('speech.sources', {
293
+ type: 'channel',
294
+ common: {
295
+ name: {
296
+ en: 'Speech sources',
297
+ de: 'Sprachquellen',
298
+ },
299
+ },
300
+ native: {},
301
+ });
302
+
303
+ const speechSources = [
304
+ {
305
+ id: 'solar',
306
+ name: {
307
+ en: 'Solar control messages',
308
+ de: 'Solarsteuerung-Meldungen',
309
+ },
310
+ enabledName: {
311
+ en: 'Enable solar control messages',
312
+ de: 'Solarsteuerung-Meldungen aktivieren',
313
+ },
314
+ enabledDesc: {
315
+ en: 'Allows speech messages when the solar control switches the pump on or off',
316
+ de: 'Erlaubt Sprachmeldungen, wenn die Solarsteuerung die Pumpe ein- oder ausschaltet',
317
+ },
318
+ cooldownName: {
319
+ en: 'Solar message cooldown',
320
+ de: 'Solar-Meldungssperre',
321
+ },
322
+ cooldownDesc: {
323
+ en: 'Minimum time in minutes between solar control speech messages',
324
+ de: 'Mindestzeit in Minuten zwischen Solarsteuerung-Sprachmeldungen',
325
+ },
326
+ cooldownDefault: 30,
327
+ },
328
+ {
329
+ id: 'time',
330
+ name: {
331
+ en: 'Time control messages',
332
+ de: 'Zeitsteuerung-Meldungen',
333
+ },
334
+ enabledName: {
335
+ en: 'Enable time control messages',
336
+ de: 'Zeitsteuerung-Meldungen aktivieren',
337
+ },
338
+ enabledDesc: {
339
+ en: 'Allows speech messages when the time control switches the pump on or off',
340
+ de: 'Erlaubt Sprachmeldungen, wenn die Zeitsteuerung die Pumpe ein- oder ausschaltet',
341
+ },
342
+ cooldownName: {
343
+ en: 'Time control message cooldown',
344
+ de: 'Zeitsteuerung-Meldungssperre',
345
+ },
346
+ cooldownDesc: {
347
+ en: 'Minimum time in minutes between time control speech messages',
348
+ de: 'Mindestzeit in Minuten zwischen Zeitsteuerung-Sprachmeldungen',
349
+ },
350
+ cooldownDefault: 0,
351
+ },
352
+ ];
353
+
354
+ for (const source of speechSources) {
355
+ const baseId = `speech.sources.${source.id}`;
356
+
357
+ await adapter.setObjectNotExistsAsync(baseId, {
358
+ type: 'channel',
359
+ common: {
360
+ name: source.name,
361
+ },
362
+ native: {},
363
+ });
364
+
365
+ await adapter.setObjectNotExistsAsync(`${baseId}.enabled`, {
366
+ type: 'state',
367
+ common: {
368
+ name: source.enabledName,
369
+ desc: source.enabledDesc,
370
+ type: 'boolean',
371
+ role: 'switch',
372
+ read: true,
373
+ write: true,
374
+ def: true,
375
+ persist: true,
376
+ },
377
+ native: {},
378
+ });
379
+
380
+ const enabledState = await adapter.getStateAsync(`${baseId}.enabled`);
381
+ if (!enabledState || enabledState.val === null || enabledState.val === undefined) {
382
+ await adapter.setStateAsync(`${baseId}.enabled`, { val: true, ack: true });
383
+ }
384
+
385
+ await adapter.setObjectNotExistsAsync(`${baseId}.cooldown_minutes`, {
386
+ type: 'state',
387
+ common: {
388
+ name: source.cooldownName,
389
+ desc: source.cooldownDesc,
390
+ type: 'number',
391
+ role: 'level',
392
+ unit: 'min',
393
+ read: true,
394
+ write: true,
395
+ min: 0,
396
+ def: source.cooldownDefault,
397
+ persist: true,
398
+ },
399
+ native: {},
400
+ });
401
+
402
+ const cooldownState = await adapter.getStateAsync(`${baseId}.cooldown_minutes`);
403
+ if (!cooldownState || cooldownState.val === null || cooldownState.val === undefined) {
404
+ await adapter.setStateAsync(`${baseId}.cooldown_minutes`, {
405
+ val: source.cooldownDefault,
406
+ ack: true,
407
+ });
408
+ }
409
+
410
+ await adapter.setObjectNotExistsAsync(`${baseId}.last_sent`, {
411
+ type: 'state',
412
+ common: {
413
+ name: {
414
+ en: 'Last message sent',
415
+ de: 'Letzte gesendete Meldung',
416
+ },
417
+ desc: {
418
+ en: 'Timestamp of the last speech message for this source',
419
+ de: 'Zeitstempel der letzten Sprachmeldung dieser Quelle',
420
+ },
421
+ type: 'string',
422
+ role: 'value.time',
423
+ read: true,
424
+ write: false,
425
+ def: '',
426
+ persist: true,
427
+ },
428
+ native: {},
429
+ });
430
+
431
+ const lastSentState = await adapter.getStateAsync(`${baseId}.last_sent`);
432
+ if (!lastSentState || lastSentState.val === null || lastSentState.val === undefined) {
433
+ await adapter.setStateAsync(`${baseId}.last_sent`, { val: '', ack: true });
434
+ }
435
+ }
436
+
437
+ adapter.log.debug('[speechStates] Speech source states checked and created');
438
+
288
439
  // versteckte Dateien
289
440
 
290
441
  await adapter.setObjectNotExistsAsync('speech.solar_active', {
package/main.js CHANGED
@@ -30,6 +30,7 @@ const aiForecastHelper = require('./lib/helpers/aiForecastHelper');
30
30
  const aiChemistryHelpHelper = require('./lib/helpers/aiChemistryHelpHelper');
31
31
  const chemistryPhHelper = require('./lib/helpers/chemistryPhHelper');
32
32
  const chemistryTdsHelper = require('./lib/helpers/chemistryTdsHelper');
33
+ const chemistryOrpHelper = require('./lib/helpers/chemistryOrpHelper');
33
34
  const controlHelper = require('./lib/helpers/controlHelper');
34
35
  const controlHelper2 = require('./lib/helpers/controlHelper2');
35
36
  const debugLogHelper = require('./lib/helpers/debugLogHelper');
@@ -63,6 +64,7 @@ const { createAiStates } = require('./lib/stateDefinitions/aiStates'); // NEU: K
63
64
  const { createAiChemistryHelpStates } = require('./lib/stateDefinitions/aiChemistryHelpStates'); // NEU: KI-Chemie-Hilfe
64
65
  const { createChemistryPhStates } = require('./lib/stateDefinitions/chemistryPhStates');
65
66
  const { createChemistryTdsStates } = require('./lib/stateDefinitions/chemistryTdsStates');
67
+ const { createChemistryOrpStates } = require('./lib/stateDefinitions/chemistryOrpStates');
66
68
  const { createHeatStates } = require('./lib/stateDefinitions/heatStates');
67
69
  const { createActuatorsStates } = require('./lib/stateDefinitions/actuatorsStates');
68
70
  const { createSolarInsightsStates } = require('./lib/stateDefinitions/solarInsightsStates');
@@ -172,6 +174,9 @@ class Poolcontrol extends utils.Adapter {
172
174
  // --- Chemistry / TDS evaluation ---
173
175
  await createChemistryTdsStates(this);
174
176
 
177
+ // --- Chemistry / ORP evaluation ---
178
+ await createChemistryOrpStates(this);
179
+
175
180
  // --- Zusatz-Aktoren (Beleuchtung & Zusatzpumpen) ---
176
181
  await createActuatorsStates(this);
177
182
 
@@ -202,6 +207,7 @@ class Poolcontrol extends utils.Adapter {
202
207
  aiChemistryHelpHelper.init(this);
203
208
  chemistryPhHelper.init(this);
204
209
  chemistryTdsHelper.init(this);
210
+ chemistryOrpHelper.init(this);
205
211
  frostHelper.init(this);
206
212
  statusHelper.init(this);
207
213
  infoHelper.init(this);
@@ -300,6 +306,9 @@ class Poolcontrol extends utils.Adapter {
300
306
  if (chemistryTdsHelper.cleanup) {
301
307
  chemistryTdsHelper.cleanup();
302
308
  }
309
+ if (chemistryOrpHelper.cleanup) {
310
+ chemistryOrpHelper.cleanup();
311
+ }
303
312
  if (aiChemistryHelpHelper.cleanup) {
304
313
  aiChemistryHelpHelper.cleanup();
305
314
  }
@@ -438,6 +447,11 @@ class Poolcontrol extends utils.Adapter {
438
447
  } catch (e) {
439
448
  this.log.warn(`[chemistryTdsHelper] Error in handleStateChange: ${e.message}`);
440
449
  }
450
+ try {
451
+ await chemistryOrpHelper.handleStateChange(id, state);
452
+ } catch (e) {
453
+ this.log.warn(`[chemistryOrpHelper] Error in handleStateChange: ${e.message}`);
454
+ }
441
455
  try {
442
456
  statusHelper.handleStateChange(id, state);
443
457
  } catch (e) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.poolcontrol",
3
- "version": "1.3.14",
3
+ "version": "1.3.17",
4
4
  "description": "Steuerung & Automatisierung für den Pool (Pumpe, Heizung, Ventile, Sensoren).",
5
5
  "author": "DasBo1975 <dasbo1975@outlook.de>",
6
6
  "homepage": "https://github.com/DasBo1975/ioBroker.poolcontrol",