iobroker.sprinklecontrol 1.0.1 → 1.0.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/lib/tools.js CHANGED
@@ -1,295 +1,253 @@
1
1
  'use strict';
2
2
 
3
- /**
4
- * func addTime (02:12:24 + 00:15) || (807) => 02:12:39
5
- *
6
- * @param time1 {string|number} z.B. 02:12:24 || 807 => 02:12:39
7
- * @param time2 {string|number|undefined} z.B. 02:12:24 || 807 => 02:12:39 || undef.
8
- * @returns {string} z.B. mm:ss || hh:mm:ss
9
- */
10
- function addTime(time1, time2){
11
- const wert = string2seconds(time1) + string2seconds(time2);
12
- return seconds2string(wert);
13
-
14
- // private functions
15
- function seconds2string(n){
16
- n = Math.abs(n);
17
- const h = Math.trunc(n / 3600);
18
- const m = Math.trunc((n / 60 ) % 60);
19
- const sec = Math.trunc(n % 60);
20
- return (h === 0)?(`${frmt(m)}:${frmt(sec)}`):(`${frmt(h)}:${m}:${frmt(sec)}`);
21
- } // end function seconds2string
22
-
23
- function string2seconds(n) {
24
- if(!n || (n === '--:--')) return 0;
25
- if(Number.isInteger(n)) return n;
26
- const tmp = n.split(':').reverse();
27
- if(!tmp.length) tmp[0] = 0; // Sekunden
28
- if(tmp.length < 2) tmp[1] = 0; // Minuten
29
- if(tmp.length < 3) tmp[2] = 0; // Stunden
30
- while(tmp[0] > 59) {
31
- tmp[0] -= 60;
32
- ++tmp[1];
33
- }
34
- while(tmp[1] > 59) {
35
- tmp[1] -= 60;
36
- ++tmp[2];
37
- }
38
- return (tmp[2] * 3600 + tmp[1] * 60 + 1 * tmp[0]);
39
- } // string2seconds
40
-
41
- function frmt(n) {
42
- return n < 10 ? `0${ n }` : n;
43
- }
44
-
45
- } // end - function addTime
46
-
47
-
48
- /**
49
- * func Format Time
50
- * hier wird der übergebene Zeitstempel, myDate, in das angegebene Format, timeFormat, umgewandelt.
51
- * Ist myDate nicht angegeben, so wird die aktuelle Zeit verwendet.
52
- *
53
- * @param {Date=} myDate - wenn nicht angegeben; dann wird aktuelles Datum verwendet
54
- * @returns {{dayNr: number; kW: number; day: number; dayTime: string; past: boolean}}
55
- * - kW: (number) Rückgabe der KW;
56
- * - dayNr: (number) Tag des Jahres (Tagesnummer)
57
- * - day: (number) Wochentag
58
- * - dd.mm. hh:mm: (string) Rückgabe Datum und Zeit
59
- * - past: true => (boolean) Heute schon vorbei
60
- */
61
- function formatTime(myDate) { // 'kW' 'dd.mm. hh:mm'
62
- function zweiStellen (s) {
63
- while (s.toString().length < 2) {
64
- s = `0${ s }`;
3
+ const tools = {
4
+ /**
5
+ * laterThanTime Funktion
6
+ *
7
+ * @param {string} time - Zeit im Format "HH:MM"
8
+ * @returns {boolean} true, wenn die angegebene Zeit noch in der Zukunft liegt, andernfalls false die Zeitliegt in der Vergangenheit
9
+ */
10
+ laterThanTime: function (time) {
11
+ const now = new Date();
12
+ const [hours, minutes] = time.split(':').map(Number);
13
+ const targetTime = new Date();
14
+ targetTime.setHours(hours, minutes, 0, 0);
15
+ return now < targetTime;
16
+ },
17
+
18
+ /**
19
+ * TREND - Zwischenwert ermitteln
20
+ *
21
+ * @param {number} a1 - Istwert a1 der Zeitachse
22
+ * @param {number} a2 - Istwert a2 der Zeitachse
23
+ * @param {number} b1 - Sollwert b1 der Wertachse
24
+ * @param {number} b2 - Sollwert b2 der Wertachse
25
+ * @param {number} sollA3 - Sollwert soll_A3 der Zeitachse
26
+ * @returns {number} Zwischenwert
27
+ */
28
+ trend: function (a1,a2,b1,b2,sollA3) {
29
+ return (sollA3-a1)*(b2-b1)/(a2-a1)+b1;
30
+ },
31
+
32
+ // Signature of the callback
33
+ // type CallBackFind<T> = (
34
+ // value: T,
35
+ // index?: number,
36
+ // collection?: T[]
37
+ // ) => Promise<boolean>;
38
+
39
+ /**
40
+ * Async Find function
41
+ *
42
+ * You can use as follows
43
+ * const array = [1, 2, 3, 4];
44
+ * const output = await findAsync<number>(array, async (i) => {
45
+ * return Promise.resolve(i === 2);
46
+ * });
47
+ *
48
+ * @template T
49
+ * @param {T[]} elements
50
+ * @param {any} cb
51
+ * @returns {Promise<T | undefined>}
52
+ */
53
+ findAsync: async function ( elements, cb) {
54
+ for (const [index, element] of elements.entries()) {
55
+ if (await cb(element, index, elements)) {
56
+ return element;
57
+ }
65
58
  }
66
- return s;
67
- }
68
- const d = (myDate)? new Date(myDate):new Date();
69
- const tag = zweiStellen(d.getDate());
70
- const monat = zweiStellen(d.getMonth() + 1);
71
- const stunde = zweiStellen(d.getHours());
72
- const minute = zweiStellen(d.getMinutes());
73
- const currentThursday = new Date(d.getTime() +(3-((d.getDay()+6) % 7)) * 86400000);
74
- // At the beginning or end of a year the thursday could be in another year.
75
- const yearOfThursday = currentThursday.getFullYear();
76
- // Get first Thursday of the year
77
- const firstThursday = new Date(new Date(yearOfThursday,0,4).getTime() +(3-((new Date(yearOfThursday,0,4).getDay()+6) % 7)) * 86400000);
78
-
79
- const start = new Date(d.getFullYear(), 0, 0);
80
- const diff = (+d - +start) + ((start.getTimezoneOffset() - d.getTimezoneOffset()) * 60 * 1000);
81
- const oneDay = 1000 * 60 * 60 * 24;
82
- const dayNr = Math.floor(diff / oneDay);
83
-
84
- // +1 we start with week number 1
85
- // +0.5 an easy and dirty way to round result (in combination with Math.floor)
86
- const kW = Math.floor(1 + 0.5 + (currentThursday.getTime() - firstThursday.getTime()) / 86400000/7);
87
-
88
- // Wochentag 0:So;1:Mo;...6:Sa
89
- const day = d.getDay();
90
-
91
- // 'dd.mm. hh:mm':
92
- const dayTime = `${tag}.${monat} ${stunde}:${minute}`;
93
59
 
94
- // true → Heute schon vorbei
95
- const cd = new Date();
96
- const cStunde = zweiStellen(cd.getHours());
97
- const cMinute = zweiStellen(cd.getMinutes());
98
- const past = ((stunde > cStunde) || ((stunde === cStunde) && (minute > cMinute)));
99
-
100
- return {
101
- dayNr: dayNr,
102
- kW: kW,
103
- day: day,
104
- dayTime: dayTime,
105
- past: past
106
- };
107
- }
108
-
109
- /**
110
- * TREND - Zwischenwert ermitteln
111
- *
112
- * @param {number} a1 - Istwert a1 der Zeitachse
113
- * @param {number} a2 - Istwert a2 der Zeitachse
114
- * @param {number} b1 - Sollwert b1 der Wertachse
115
- * @param {number} b2 - Sollwert b2 der Wertachse
116
- * @param {number} sollA3 - Sollwert soll_A3 der Zeitachse
117
- * @returns {number} Zwischenwert
118
- */
119
- function trend (a1,a2,b1,b2,sollA3) {
120
- return (sollA3-a1)*(b2-b1)/(a2-a1)+b1;
121
- }
122
-
123
- /**
124
- * ID Homematic
125
- * Hiermit kann die ID-Adresse State, ON_TIME, WORKING, PROCESS eines Homematic-Schaltaktors
126
- * ermittelt werden, wenn die ID des Geräts bekannt ist.
127
- *
128
- * @param {object} adapter - Der ioBroker-Adapter, der die Funktion aufruft
129
- * @param {string} id - ID des Geräts
130
- * @returns {Promise} Promise, die die ID-Adresse zurückgibt
131
- */
132
- async function idStateControl(adapter, id) {
133
- // "hm-rpc.0.MEQ1234567.3.STATE" => "hm-rpc.0.MEQ1234567.3"
134
- const pfad = id.substring(0, id.lastIndexOf('.'));
135
-
136
- switch (adapter.config.switchingBehavior) {
137
-
138
- case "standard": {
139
- // standard => "hm-rpc.0.MEQ1234567.3.STATE"
140
- return {
141
- idState: id,
142
- idON_TIME: null,
143
- idACK: id,
144
- maker: "standard"
145
- };
146
- }
60
+ return undefined;
61
+ },
62
+
63
+ /**
64
+ * ID Homematic
65
+ * Hiermit kann die ID-Adresse State, ON_TIME, WORKING, PROCESS eines Homematic-Schaltaktors
66
+ * ermittelt werden, wenn die ID des Geräts bekannt ist.
67
+ *
68
+ * @param {object} adapter - Der ioBroker-Adapter, der die Funktion aufruft
69
+ * @param {string} id - ID des Geräts
70
+ * @returns {Promise} Promise, die die ID-Adresse zurückgibt
71
+ */
72
+ idStateControl: async function (adapter, id) {
73
+ // "hm-rpc.0.MEQ1234567.3.STATE" => "hm-rpc.0.MEQ1234567.3"
74
+ const pfad = id.substring(0, id.lastIndexOf('.'));
75
+
76
+ switch (adapter.config.switchingBehavior) {
77
+
78
+ case "standard": {
79
+ // standard => "hm-rpc.0.MEQ1234567.3.STATE"
80
+ return {
81
+ idState: id,
82
+ idON_TIME: null,
83
+ idACK: id,
84
+ maker: "standard"
85
+ };
86
+ }
147
87
 
148
- case "homematic": {
149
- try {
150
- const _state = await adapter.getForeignStateAsync(`${pfad}.STATE`);
151
- const _ON_TIME = await adapter.getForeignStateAsync(`${pfad}.ON_TIME`);
152
- const _WORKING = await adapter.getForeignStateAsync(`${pfad}.WORKING`);
153
- const _PROCESS = await adapter.getForeignStateAsync(`${pfad}.PROCESS`);
154
- if (typeof _state?.val !== 'boolean') throw new Error(`idStateControl: State ${pfad}.STATE nicht gefunden`);
155
-
156
- if (_WORKING) {
88
+ case "homematic": {
89
+ try {
90
+ const _state = await adapter.getForeignStateAsync(`${pfad}.STATE`);
91
+ const _ON_TIME = await adapter.getForeignStateAsync(`${pfad}.ON_TIME`);
92
+ const _WORKING = await adapter.getForeignStateAsync(`${pfad}.WORKING`);
93
+ const _PROCESS = await adapter.getForeignStateAsync(`${pfad}.PROCESS`);
94
+ if (typeof _state?.val !== 'boolean') throw new Error(`idStateControl: State ${pfad}.STATE nicht gefunden`);
95
+
96
+ if (_WORKING) {
97
+ return {
98
+ idState: _state ? `${pfad}.STATE` : null,
99
+ idON_TIME: _ON_TIME ? `${pfad}.ON_TIME` : null,
100
+ idACK: _WORKING ? `${pfad}.WORKING` : null,
101
+ maker: 'HM'
102
+ };
103
+ } else if (_PROCESS) {
104
+ return {
105
+ idState: _state ? `${pfad}.STATE` : null,
106
+ idON_TIME: _ON_TIME ? `${pfad}.ON_TIME` : null,
107
+ idACK: _PROCESS ? `${pfad}.PROCESS` : null,
108
+ maker: 'HmIP'
109
+ };
110
+ } else {
111
+ return {
112
+ idState: _state ? `${pfad}.STATE` : null,
113
+ idON_TIME: null,
114
+ idACK: _state ? `${pfad}.STATE` : null,
115
+ maker: 'standard'
116
+ };
117
+ }
118
+ } catch (error) {
119
+ adapter.log.error(`idStateControl: Fehler bei der Ermittlung der ID-Adresse für ${id}: ${error.message}`);
157
120
  return {
158
- idState: _state ? `${pfad}.STATE` : null,
159
- idON_TIME: _ON_TIME ? `${pfad}.ON_TIME` : null,
160
- idACK: _WORKING ? `${pfad}.WORKING` : null,
161
- maker: 'HM'
162
- };
163
- } else if (_PROCESS) {
164
- return {
165
- idState: _state ? `${pfad}.STATE` : null,
166
- idON_TIME: _ON_TIME ? `${pfad}.ON_TIME` : null,
167
- idACK: _PROCESS ? `${pfad}.PROCESS` : null,
168
- maker: 'HmIP'
169
- };
170
- } else {
171
- return {
172
- idState: _state ? `${pfad}.STATE` : null,
121
+ idState: id,
173
122
  idON_TIME: null,
174
- idACK: _state ? `${pfad}.STATE` : null,
175
- maker: 'standard'
123
+ idACK: id,
124
+ maker: 'unknown'
176
125
  };
177
126
  }
178
- } catch (error) {
179
- adapter.log.error(`idStateControl: Fehler bei der Ermittlung der ID-Adresse für ${id}: ${error.message}`);
127
+ }
128
+
129
+ case "noResponse": {
130
+ // standard => "hm-rpc.0.MEQ1234567.3.STATE"
180
131
  return {
181
132
  idState: id,
182
133
  idON_TIME: null,
183
- idACK: id,
184
- maker: 'unknown'
185
- };
134
+ idACK: null,
135
+ maker: "noResponse"
136
+ };
137
+ }
138
+
139
+ default: {
140
+ adapter.log.error(`No switching behavior was selected for the "${id}" watering circuit.`);
186
141
  }
187
142
  }
188
-
189
- case "noResponse": {
190
- // standard => "hm-rpc.0.MEQ1234567.3.STATE"
191
- return {
192
- idState: id,
193
- idON_TIME: null,
194
- idACK: null,
195
- maker: "noResponse"
196
- };
197
- }
198
-
199
- default: {
200
- adapter.log.error(`No switching behavior was selected for the "${id}" watering circuit.`);
143
+ },
144
+
145
+ /**
146
+ * func Format Time
147
+ * → hier wird der übergebene Zeitstempel, myDate, in das angegebene Format, timeFormat, umgewandelt.
148
+ * Ist myDate nicht angegeben, so wird die aktuelle Zeit verwendet.
149
+ *
150
+ * @param {Date=} myDate - wenn nicht angegeben; dann wird aktuelles Datum verwendet
151
+ * @returns {{dayNr: number; kW: number; day: number; dayTime: string; past: boolean}}
152
+ * - kW: (number) Rückgabe der KW;
153
+ * - dayNr: (number) Tag des Jahres (Tagesnummer)
154
+ * - day: (number) Wochentag
155
+ * - dd.mm. hh:mm: (string) Rückgabe Datum und Zeit
156
+ * - past: true => (boolean) Heute schon vorbei
157
+ */
158
+ formatTime: function (myDate) { // 'kW' 'dd.mm. hh:mm'
159
+ function zweiStellen (s) {
160
+ while (s.toString().length < 2) {
161
+ s = `0${ s }`;
162
+ }
163
+ return s;
201
164
  }
202
- }
203
- }
204
-
205
-
206
- // Signature of the callback
207
- // type CallBackFind<T> = (
208
- // value: T,
209
- // index?: number,
210
- // collection?: T[]
211
- // ) => Promise<boolean>;
212
-
213
- /**
214
- * Async Find function
215
- *
216
- * You can use as follows
217
- * const array = [1, 2, 3, 4];
218
- * const output = await findAsync<number>(array, async (i) => {
219
- * return Promise.resolve(i === 2);
220
- * });
221
- *
222
- * @template T
223
- * @param {T[]} elements
224
- * @param {any} cb
225
- * @returns {Promise<T | undefined>}
226
- */
165
+ const d = (myDate)? new Date(myDate):new Date();
166
+ const tag = zweiStellen(d.getDate());
167
+ const monat = zweiStellen(d.getMonth() + 1);
168
+ const stunde = zweiStellen(d.getHours());
169
+ const minute = zweiStellen(d.getMinutes());
170
+ const currentThursday = new Date(d.getTime() +(3-((d.getDay()+6) % 7)) * 86400000);
171
+ // At the beginning or end of a year the thursday could be in another year.
172
+ const yearOfThursday = currentThursday.getFullYear();
173
+ // Get first Thursday of the year
174
+ const firstThursday = new Date(new Date(yearOfThursday,0,4).getTime() +(3-((new Date(yearOfThursday,0,4).getDay()+6) % 7)) * 86400000);
175
+
176
+ const start = new Date(d.getFullYear(), 0, 0);
177
+ const diff = (+d - +start) + ((start.getTimezoneOffset() - d.getTimezoneOffset()) * 60 * 1000);
178
+ const oneDay = 1000 * 60 * 60 * 24;
179
+ const dayNr = Math.floor(diff / oneDay);
180
+
181
+ // +1 we start with week number 1
182
+ // +0.5 an easy and dirty way to round result (in combination with Math.floor)
183
+ const kW = Math.floor(1 + 0.5 + (currentThursday.getTime() - firstThursday.getTime()) / 86400000/7);
184
+
185
+ // Wochentag 0:So;1:Mo;...6:Sa
186
+ const day = d.getDay();
187
+
188
+ // 'dd.mm. hh:mm':
189
+ const dayTime = `${tag}.${monat} ${stunde}:${minute}`;
190
+
191
+ // true → Heute schon vorbei
192
+ const cd = new Date();
193
+ const cStunde = zweiStellen(cd.getHours());
194
+ const cMinute = zweiStellen(cd.getMinutes());
195
+ const past = ((stunde > cStunde) || ((stunde === cStunde) && (minute > cMinute)));
196
+
197
+ return {
198
+ dayNr: dayNr,
199
+ kW: kW,
200
+ day: day,
201
+ dayTime: dayTime,
202
+ past: past
203
+ };
204
+ },
205
+
206
+ /**
207
+ * func addTime (02:12:24 + 00:15) || (807) => 02:12:39
208
+ *
209
+ * @param time1 {string|number} z.B. 02:12:24 || 807 => 02:12:39
210
+ * @param time2 {string|number|undefined} z.B. 02:12:24 || 807 => 02:12:39 || undef.
211
+ * @returns {string} z.B. mm:ss || hh:mm:ss
212
+ */
213
+ addTime: function (time1, time2){
214
+ const wert = string2seconds(time1) + string2seconds(time2);
215
+ return seconds2string(wert);
216
+
217
+ // private functions
218
+ function seconds2string(n){
219
+ n = Math.abs(n);
220
+ const h = Math.trunc(n / 3600);
221
+ const m = Math.trunc((n / 60 ) % 60);
222
+ const sec = Math.trunc(n % 60);
223
+ return (h === 0)?(`${frmt(m)}:${frmt(sec)}`):(`${frmt(h)}:${m}:${frmt(sec)}`);
224
+ } // end function seconds2string
225
+
226
+ function string2seconds(n) {
227
+ if(!n || (n === '--:--')) return 0;
228
+ if(Number.isInteger(n)) return n;
229
+ const tmp = n.split(':').reverse();
230
+ if(!tmp.length) tmp[0] = 0; // Sekunden
231
+ if(tmp.length < 2) tmp[1] = 0; // Minuten
232
+ if(tmp.length < 3) tmp[2] = 0; // Stunden
233
+ while(tmp[0] > 59) {
234
+ tmp[0] -= 60;
235
+ ++tmp[1];
236
+ }
237
+ while(tmp[1] > 59) {
238
+ tmp[1] -= 60;
239
+ ++tmp[2];
240
+ }
241
+ return (tmp[2] * 3600 + tmp[1] * 60 + 1 * tmp[0]);
242
+ } // string2seconds
227
243
 
228
- async function findAsync( elements, cb) {
229
- for (const [index, element] of elements.entries()) {
230
- if (await cb(element, index, elements)) {
231
- return element;
244
+ function frmt(n) {
245
+ return n < 10 ? `0${ n }` : n;
232
246
  }
233
- }
234
-
235
- return undefined;
236
- }
237
247
 
238
- // You can use as follows
239
- // const array = [1, 2, 3, 4];
240
-
241
- // const output = await findAsync<number>(array, async (i) => {
242
- // return Promise.resolve(i === 2);
243
- // });
244
-
245
-
246
- /**
247
- * sleep Funktion mit .cancel bzw .continues Token
248
- *
249
- * @param {number} ms - Zeit in Millisekunden
250
- * @param {object} cancellationToken Objekt zur ansteuerung der inneren Funktion
251
- * @returns {Promise <string>}
252
- */
253
- function sleep(ms, cancellationToken) {
254
- return new Promise((resolve) => {
255
- cancellationToken.clearEntireList = function() {
256
- clearTimeout(timeout);
257
- resolve('clearEntireList');
258
- };
259
- cancellationToken.boostKill = function() {
260
- clearTimeout(timeout);
261
- resolve('boostKill');
262
- };
263
- cancellationToken.ack = function() {
264
- clearTimeout(timeout);
265
- resolve('ack');
266
- };
267
- const timeout = setTimeout(() => {
268
- resolve('resolved');
269
- }, ms);
270
- });
248
+ } // end - function addTime
271
249
  }
272
- // async function beginTest() {
273
- // try {
274
- // const token = {};
275
- // const promise = sleep(5000, token);
276
- // await promise;
277
- // // ... test code ...
278
- // // ... return whatever;
279
- // }
280
- // catch(error) {
281
- // console.log(error.message);
282
- // // If button was clicked before the 5000 ms has expired,
283
- // // and no other error has been thrown,
284
- // // then the log will show "sleep() cancelled".
285
- // throw error; // rethrow error to keep beginTest's caller informed.
286
- // }
287
250
 
288
251
  module.exports = {
289
- addTime,
290
- formatTime,
291
- idStateControl,
292
- trend,
293
- findAsync,
294
- sleep
252
+ tools
295
253
  };