iobroker.sprinklecontrol 1.0.0 → 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/README.md +8 -6
- package/admin/i18n/de/translations.json +11 -0
- package/admin/i18n/en/translations.json +11 -0
- package/admin/i18n/es/translations.json +11 -0
- package/admin/i18n/fr/translations.json +11 -0
- package/admin/i18n/it/translations.json +11 -0
- package/admin/i18n/nl/translations.json +11 -0
- package/admin/i18n/pl/translations.json +11 -0
- package/admin/i18n/pt/translations.json +11 -0
- package/admin/i18n/ru/translations.json +11 -0
- package/admin/i18n/uk/translations.json +11 -0
- package/admin/i18n/zh-cn/translations.json +11 -0
- package/admin/index_m.html +515 -455
- package/admin/index_m.js +35 -18
- package/admin/words.js +20 -9
- package/io-package.json +31 -29
- package/lib/evaporation.js +9 -10
- package/lib/myConfig.js +46 -24
- package/lib/sendMessageText.js +5 -5
- package/lib/tools.js +242 -200
- package/lib/valveControl.js +239 -87
- package/main.js +84 -42
- package/package.json +1 -1
package/lib/myConfig.js
CHANGED
|
@@ -4,8 +4,7 @@
|
|
|
4
4
|
/*
|
|
5
5
|
info: log aufbau myConfig.js: #1.*
|
|
6
6
|
*/
|
|
7
|
-
const
|
|
8
|
-
const formatTime = require('./tools').formatTime; // tools => laden von Hilfsfunktionen
|
|
7
|
+
const tools = require('./tools').tools; // tools => laden von Hilfsfunktionen
|
|
9
8
|
|
|
10
9
|
/**
|
|
11
10
|
* The adapter instance
|
|
@@ -39,27 +38,44 @@ const myConfig = {
|
|
|
39
38
|
const objectName = (res.sprinkleName !== '') ? res.sprinkleName.replace(/[.;, ]/g, '_') : res.name.replace(/[.;, ]/g, '_');
|
|
40
39
|
|
|
41
40
|
const newEntry = {
|
|
42
|
-
|
|
41
|
+
// Schaltzustand des Ventils
|
|
42
|
+
enabled: res.enabled || false,
|
|
43
43
|
booster: res.booster,
|
|
44
44
|
autoOn: true,
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
45
|
+
// sprinklecontrol.0.sprinkle.Rasenumrandung.autoOnID
|
|
46
|
+
autoOnID: `${ adapter.namespace }.sprinkle.${ objectName }.autoOn`,
|
|
47
|
+
// extern break single (unterbrechung eines Kanals)
|
|
48
|
+
extBreak: false,
|
|
49
|
+
// sprinklecontrol.0.sprinkle.Rasenumrandung.breakID
|
|
50
|
+
extBreakID: `${ adapter.namespace }.sprinkle.${ objectName }.extBreak`,
|
|
51
|
+
// z.B. Rasenumrandung
|
|
52
|
+
objectName: objectName,
|
|
53
|
+
// sprinklecontrol.0.sprinkle.Rasenumrandung.runningTime
|
|
54
|
+
objectID: `${ adapter.namespace }.sprinkle.${ objectName }.runningTime`,
|
|
55
|
+
// Sensor für die Bodenfeuchte
|
|
56
|
+
triggerSM: res.triggerSM,
|
|
57
|
+
// Timer wird gelöscht wenn Rückmeldung erfolgte
|
|
58
|
+
updateStateTimerID: null,
|
|
59
|
+
// Array[0...]
|
|
60
|
+
sprinkleID: myConfig.config.length,
|
|
61
|
+
// ...min
|
|
62
|
+
wateringTime: parseInt(res.wateringTime),
|
|
63
|
+
// 0 ... 200%
|
|
64
|
+
wateringAdd: parseInt(res.wateringAdd),
|
|
65
|
+
// 5,10,15min Ausschaltzeit
|
|
66
|
+
wateringIntervalOff: ((60 * parseInt(res.wateringIntervalOff)) || 0),
|
|
67
|
+
// 5,10,15min Einschaltzeit
|
|
68
|
+
wateringIntervalOn: ((60 * parseInt(res.wateringIntervalOn)) || 0),
|
|
69
|
+
// ...min Zusatzbewässerung bei hohen Temperaturen
|
|
70
|
+
addWateringTime: (parseInt(res.addWateringTime) || 0),
|
|
71
|
+
// Wasserverbrauch des sprinkler-Kreises
|
|
72
|
+
pipeFlow: parseInt(res.pipeFlow),
|
|
73
|
+
// Art der Kontrolle der Bodenfeuchte ('calculation'; 'bistable'; 'analog'; fixDay)
|
|
74
|
+
methodControlSM: res.methodControlSM,
|
|
75
|
+
// keine Wettervorhersage verwenden (Gewächshaus)
|
|
76
|
+
inGreenhouse: res.inGreenhouse || false
|
|
62
77
|
};
|
|
78
|
+
|
|
63
79
|
switch (res.methodControlSM) {
|
|
64
80
|
case 'calculation': {
|
|
65
81
|
newEntry.calculation = {
|
|
@@ -115,6 +131,13 @@ const myConfig = {
|
|
|
115
131
|
default: {adapter.log.error(`No watering type was selected in the "${objectName}" watering circuit.`);}
|
|
116
132
|
}
|
|
117
133
|
|
|
134
|
+
// abonnieren der Statusänderungen des Objekts (reagiert auf Änderung des 'Ventils' der einzelnen Bewässerungskreise zur Fehlerkontrolle bzw. Verbrauchsermittlung)
|
|
135
|
+
newEntry.control = await tools.idStateControl(adapter, res.name);
|
|
136
|
+
|
|
137
|
+
/* Abonnieren der Statusänderungen des Objekts (reagieren auf Änderung des 'Ventils'
|
|
138
|
+
der einzelnen Bewässerungskreise zur Fehlerkontrolle bzw. Verbrauchsermittlung) */
|
|
139
|
+
adapter.subscribeForeignStates(newEntry.control.idACK);
|
|
140
|
+
|
|
118
141
|
// @ts-ignore
|
|
119
142
|
myConfig.config.push(newEntry);
|
|
120
143
|
|
|
@@ -122,8 +145,7 @@ const myConfig = {
|
|
|
122
145
|
// Report a change in the status of the trigger IDs (.runningTime; .name) => Melden einer Änderung des Status der Trigger-IDs
|
|
123
146
|
adapter.subscribeStates(newEntry.objectID); // abonnieren der Statusänderungen des Objekts (reagieren auf 'runningTime' der einzelnen Bewässerungskreise)
|
|
124
147
|
adapter.subscribeStates(newEntry.autoOnID); // abonnieren der Statusänderungen des Objekts (reagieren auf 'autoOn' der einzelnen Bewässerungskreise)
|
|
125
|
-
adapter.subscribeStates(newEntry.extBreakID); // abonnieren der Statusänderungen des Objekts (reagieren auf 'autoOn' der einzelnen Bewässerungskreise)
|
|
126
|
-
adapter.subscribeForeignStates(newEntry.idState); // abonnieren der Statusänderungen des Objekts (reagiert auf Änderung des 'Ventils' der einzelnen Bewässerungskreise zur Fehlerkontrolle bzw. Verbrauchsermittlung)
|
|
148
|
+
adapter.subscribeStates(newEntry.extBreakID); // abonnieren der Statusänderungen des Objekts (reagieren auf 'autoOn' der einzelnen Bewässerungskreise)
|
|
127
149
|
}
|
|
128
150
|
adapter.log.debug(`Config ${objectName} created (${newEntry.sprinkleID}) - ${JSON.stringify(myConfig.config[newEntry.sprinkleID])}`);
|
|
129
151
|
}
|
|
@@ -232,7 +254,7 @@ const myConfig = {
|
|
|
232
254
|
myVal = newVal;
|
|
233
255
|
}
|
|
234
256
|
|
|
235
|
-
myConfig.config[mySprinkleID].analog.pct = Math.round(10 * trend(myConfig.config[mySprinkleID].analog.analogZPct, myConfig.config[mySprinkleID].analog.analogOHPct, 0, 100, myVal)) / 10;
|
|
257
|
+
myConfig.config[mySprinkleID].analog.pct = Math.round(10 * tools.trend(myConfig.config[mySprinkleID].analog.analogZPct, myConfig.config[mySprinkleID].analog.analogOHPct, 0, 100, myVal)) / 10;
|
|
236
258
|
adapter.setState(`sprinkle.${ [myConfig.config[mySprinkleID].objectName] }.actualSoilMoisture`, {
|
|
237
259
|
val: myConfig.config[mySprinkleID].analog.pct,
|
|
238
260
|
ack: true
|
|
@@ -269,7 +291,7 @@ const myConfig = {
|
|
|
269
291
|
if (myConfig.config[mySprinkleID].fixDay.startDay === 'threeRd' || // Next Start in 3 Tagen
|
|
270
292
|
myConfig.config[mySprinkleID].fixDay.startDay === 'twoNd') { // Next Start in 2 Tagen
|
|
271
293
|
try {
|
|
272
|
-
const today = await formatTime().day;
|
|
294
|
+
const today = await tools.formatTime().day;
|
|
273
295
|
const id = `${adapter.namespace}.sprinkle.${myConfig.config[mySprinkleID].objectName}.actualSoilMoisture`;
|
|
274
296
|
let curDay, nextDay;
|
|
275
297
|
/** Wert von actualSoilMoisture auslesen */
|
package/lib/sendMessageText.js
CHANGED
|
@@ -24,7 +24,7 @@ const sendMessageText = {
|
|
|
24
24
|
switch (adapter.config.notificationsType) {
|
|
25
25
|
case 'Telegram':
|
|
26
26
|
ObjMessage = {
|
|
27
|
-
enabled: adapter.config.
|
|
27
|
+
enabled: adapter.config.notificationsType !== 'noNotification' || false,
|
|
28
28
|
notificationsType: adapter.config.notificationsType,
|
|
29
29
|
type: 'message',
|
|
30
30
|
instance: adapter.config.telegramInstance,
|
|
@@ -38,7 +38,7 @@ const sendMessageText = {
|
|
|
38
38
|
|
|
39
39
|
case 'E-Mail':
|
|
40
40
|
ObjMessage = {
|
|
41
|
-
enabled: adapter.config.
|
|
41
|
+
enabled: adapter.config.notificationsType !== 'noNotification' || false,
|
|
42
42
|
notificationsType: adapter.config.notificationsType,
|
|
43
43
|
type: 'message',
|
|
44
44
|
instance: adapter.config.emailInstance,
|
|
@@ -52,7 +52,7 @@ const sendMessageText = {
|
|
|
52
52
|
|
|
53
53
|
case 'Pushover':
|
|
54
54
|
ObjMessage = {
|
|
55
|
-
enabled: adapter.config.
|
|
55
|
+
enabled: adapter.config.notificationsType !== 'noNotification' || false,
|
|
56
56
|
notificationsType: adapter.config.notificationsType,
|
|
57
57
|
type: 'message',
|
|
58
58
|
sound: adapter.config.pushoverSound,
|
|
@@ -67,7 +67,7 @@ const sendMessageText = {
|
|
|
67
67
|
|
|
68
68
|
case 'WhatsApp':
|
|
69
69
|
ObjMessage = {
|
|
70
|
-
enabled: adapter.config.
|
|
70
|
+
enabled: adapter.config.notificationsType !== 'noNotification' || false,
|
|
71
71
|
notificationsType: adapter.config.notificationsType,
|
|
72
72
|
type: 'message',
|
|
73
73
|
instance: adapter.config.whatsappInstance,
|
|
@@ -189,7 +189,7 @@ const sendMessageText = {
|
|
|
189
189
|
* @returns {boolean}
|
|
190
190
|
*/
|
|
191
191
|
onlySendError () {
|
|
192
|
-
return (adapter.config.
|
|
192
|
+
return (adapter.config.notificationsType !== 'noNotification' && adapter.config.notificationsType && ObjMessage.onlyError);
|
|
193
193
|
}
|
|
194
194
|
|
|
195
195
|
};
|
package/lib/tools.js
CHANGED
|
@@ -1,211 +1,253 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
function
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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
|
+
}
|
|
33
58
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
59
|
+
|
|
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
|
+
}
|
|
87
|
+
|
|
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}`);
|
|
120
|
+
return {
|
|
121
|
+
idState: id,
|
|
122
|
+
idON_TIME: null,
|
|
123
|
+
idACK: id,
|
|
124
|
+
maker: 'unknown'
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
case "noResponse": {
|
|
130
|
+
// standard => "hm-rpc.0.MEQ1234567.3.STATE"
|
|
131
|
+
return {
|
|
132
|
+
idState: id,
|
|
133
|
+
idON_TIME: null,
|
|
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.`);
|
|
141
|
+
}
|
|
37
142
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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 }`;
|
|
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;
|
|
65
164
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
function
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
//
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
*
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
if (await cb(element, index, elements)) {
|
|
148
|
-
return element;
|
|
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
|
|
243
|
+
|
|
244
|
+
function frmt(n) {
|
|
245
|
+
return n < 10 ? `0${ n }` : n;
|
|
149
246
|
}
|
|
150
|
-
}
|
|
151
247
|
|
|
152
|
-
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// You can use as follows
|
|
156
|
-
// const array = [1, 2, 3, 4];
|
|
157
|
-
|
|
158
|
-
// const output = await findAsync<number>(array, async (i) => {
|
|
159
|
-
// return Promise.resolve(i === 2);
|
|
160
|
-
// });
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* sleep Funktion mit .cancel bzw .continues Token
|
|
165
|
-
*
|
|
166
|
-
* @param {number} ms - Zeit in Millisekunden
|
|
167
|
-
* @param {object} cancellationToken Objekt zur ansteuerung der inneren Funktion
|
|
168
|
-
* @returns {Promise <string>}
|
|
169
|
-
*/
|
|
170
|
-
function sleep(ms, cancellationToken) {
|
|
171
|
-
return new Promise((resolve) => {
|
|
172
|
-
cancellationToken.clearEntireList = function() {
|
|
173
|
-
clearTimeout(timeout);
|
|
174
|
-
resolve('clearEntireList');
|
|
175
|
-
};
|
|
176
|
-
cancellationToken.boostKill = function() {
|
|
177
|
-
clearTimeout(timeout);
|
|
178
|
-
resolve('boostKill');
|
|
179
|
-
};
|
|
180
|
-
cancellationToken.ack = function() {
|
|
181
|
-
clearTimeout(timeout);
|
|
182
|
-
resolve('ack');
|
|
183
|
-
};
|
|
184
|
-
const timeout = setTimeout(() => {
|
|
185
|
-
resolve('resolved');
|
|
186
|
-
}, ms);
|
|
187
|
-
});
|
|
248
|
+
} // end - function addTime
|
|
188
249
|
}
|
|
189
|
-
// async function beginTest() {
|
|
190
|
-
// try {
|
|
191
|
-
// const token = {};
|
|
192
|
-
// const promise = sleep(5000, token);
|
|
193
|
-
// await promise;
|
|
194
|
-
// // ... test code ...
|
|
195
|
-
// // ... return whatever;
|
|
196
|
-
// }
|
|
197
|
-
// catch(error) {
|
|
198
|
-
// console.log(error.message);
|
|
199
|
-
// // If button was clicked before the 5000 ms has expired,
|
|
200
|
-
// // and no other error has been thrown,
|
|
201
|
-
// // then the log will show "sleep() cancelled".
|
|
202
|
-
// throw error; // rethrow error to keep beginTest's caller informed.
|
|
203
|
-
// }
|
|
204
250
|
|
|
205
251
|
module.exports = {
|
|
206
|
-
|
|
207
|
-
formatTime,
|
|
208
|
-
trend,
|
|
209
|
-
findAsync,
|
|
210
|
-
sleep
|
|
252
|
+
tools
|
|
211
253
|
};
|