iobroker.device-watcher 0.0.6
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/LICENSE +21 -0
- package/README.md +87 -0
- package/admin/device-watcher.png +0 -0
- package/admin/i18n/de/translations.json +41 -0
- package/admin/i18n/en/translations.json +43 -0
- package/admin/i18n/es/translations.json +49 -0
- package/admin/i18n/fr/translations.json +49 -0
- package/admin/i18n/it/translations.json +49 -0
- package/admin/i18n/nl/translations.json +49 -0
- package/admin/i18n/pl/translations.json +49 -0
- package/admin/i18n/pt/translations.json +49 -0
- package/admin/i18n/ru/translations.json +49 -0
- package/admin/i18n/zh-cn/translations.json +49 -0
- package/admin/images/add_blacklist.png +0 -0
- package/admin/images/list1.png +0 -0
- package/admin/images/list2.png +0 -0
- package/admin/images/list3.png +0 -0
- package/admin/index_m.html +95 -0
- package/admin/jsonConfig.json +310 -0
- package/admin/style.css +32 -0
- package/admin/words.js +47 -0
- package/io-package.json +311 -0
- package/lib/adapter-config.d.ts +19 -0
- package/main.js +582 -0
- package/package.json +69 -0
package/main.js
ADDED
|
@@ -0,0 +1,582 @@
|
|
|
1
|
+
/* jshint -W097 */
|
|
2
|
+
/* jshint strict: false */
|
|
3
|
+
/* jslint node: true */
|
|
4
|
+
|
|
5
|
+
'use strict';
|
|
6
|
+
|
|
7
|
+
const utils = require('@iobroker/adapter-core');
|
|
8
|
+
const adapterName = require('./package.json').name.split('.').pop();
|
|
9
|
+
|
|
10
|
+
class DeviceWatcher extends utils.Adapter {
|
|
11
|
+
|
|
12
|
+
constructor(options) {
|
|
13
|
+
super({
|
|
14
|
+
...options,
|
|
15
|
+
name: adapterName,
|
|
16
|
+
useFormatDate: true,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
this.refreshEverythingTimeout = null;
|
|
20
|
+
|
|
21
|
+
this.on('ready', this.onReady.bind(this));
|
|
22
|
+
//this.on('stateChange', this.onStateChange.bind(this));
|
|
23
|
+
// this.on('objectChange', this.onObjectChange.bind(this));
|
|
24
|
+
// this.on('message', this.onMessage.bind(this));
|
|
25
|
+
this.on('unload', this.onUnload.bind(this));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async onReady() {
|
|
29
|
+
this.log.debug('Adapter Device-Watcher was started');
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
await this.main();
|
|
33
|
+
this.log.debug('all done, exiting');
|
|
34
|
+
this.terminate ? this.terminate('Everything done. Going to terminate till next schedule', 11) : process.exit(0);
|
|
35
|
+
} catch (e) {
|
|
36
|
+
this.log.error('Error while running Device-Watcher. Error Message:' + e);
|
|
37
|
+
this.terminate ? this.terminate(15) : process.exit(15);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async main() {
|
|
45
|
+
|
|
46
|
+
//Helperfunctions
|
|
47
|
+
//capitalize the first letter
|
|
48
|
+
/*
|
|
49
|
+
async function capitalize(sentence)
|
|
50
|
+
{
|
|
51
|
+
return sentence && sentence[0].toUpperCase() + sentence.slice(1);
|
|
52
|
+
}*/
|
|
53
|
+
|
|
54
|
+
const pushover = {
|
|
55
|
+
instance: this.config.instancePushover,
|
|
56
|
+
title: this.config.titlePushover,
|
|
57
|
+
device: this.config.devicePushover
|
|
58
|
+
|
|
59
|
+
};
|
|
60
|
+
const telegram = {
|
|
61
|
+
instance: this.config.instanceTelegram,
|
|
62
|
+
user: this.config.deviceTelegram
|
|
63
|
+
};
|
|
64
|
+
const email = {
|
|
65
|
+
instance: this.config.instanceEmail,
|
|
66
|
+
subject: this.config.subjectEmail,
|
|
67
|
+
sendTo: this.config.sendToEmail
|
|
68
|
+
|
|
69
|
+
};
|
|
70
|
+
const jarvis = {
|
|
71
|
+
instance: this.config.instanceJarvis,
|
|
72
|
+
title: this.config.titleJarvis
|
|
73
|
+
|
|
74
|
+
};
|
|
75
|
+
const choosedDays = {
|
|
76
|
+
monday: this.config.checkMonday,
|
|
77
|
+
tuesday: this.config.checkTuesday,
|
|
78
|
+
wednesday: this.config.checkWednesday,
|
|
79
|
+
thursday: this.config.checkThursday,
|
|
80
|
+
friday: this.config.checkFriday,
|
|
81
|
+
saturday: this.config.checkSaturday,
|
|
82
|
+
sunday: this.config.checkSunday,
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const sendPushover = async (text) => {
|
|
86
|
+
await this.sendToAsync(pushover.instance, 'send', {
|
|
87
|
+
message: text,
|
|
88
|
+
title: pushover.title,
|
|
89
|
+
device: pushover.device
|
|
90
|
+
});
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const sendTelegram = async (text) => {
|
|
94
|
+
await this.sendToAsync(telegram.instance, 'send', {
|
|
95
|
+
text: text,
|
|
96
|
+
user: telegram.user
|
|
97
|
+
});
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const sendEmail = async (text) => {
|
|
101
|
+
await this.sendToAsync(email.instance, 'send', {
|
|
102
|
+
sendTo: email.sendTo,
|
|
103
|
+
text: text,
|
|
104
|
+
subject: email.subject
|
|
105
|
+
});
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const sendJarvis = async (text) => {
|
|
109
|
+
await this.setForeignStateAsync('jarvis.0.addNotification', text);
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
this.log.debug('Function started: ' + this.main.name);
|
|
113
|
+
|
|
114
|
+
let arrOfflineDevices = []; //JSON-Info of all offline-devices
|
|
115
|
+
let jsonLinkQualityDevices = []; //JSON-Info of all devices with linkquality
|
|
116
|
+
let arrBatteryPowered = []; //JSON-Info of all devices with battery
|
|
117
|
+
let arrBatteryLowPowered = [];
|
|
118
|
+
let arrListAllDevices = []; //JSON-Info total list with info of all devices
|
|
119
|
+
let offlineDevicesCount = 0;
|
|
120
|
+
let deviceCounter = 0;
|
|
121
|
+
let batteryPoweredCount = 0;
|
|
122
|
+
let lowBatteryPoweredCount = 0;
|
|
123
|
+
let lastContactString;
|
|
124
|
+
const testMe = true;
|
|
125
|
+
|
|
126
|
+
if (!this.config.zigbeeDevices && !this.config.bleDevices && !this.config.sonoffDevices && !this.config.shellyDevices && !this.config.homematicDevices && !this.config.deconzDevices && !this.config.zwaveDevices) {
|
|
127
|
+
this.log.warn('No devices selected. Pleased check the instance configuration');
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const myArrDev = []; //JSON mit Gesamtliste aller Geräte
|
|
131
|
+
|
|
132
|
+
if (testMe) { //Only for Developer to test the functions!!
|
|
133
|
+
myArrDev.push({'Selektor':'0_userdata.*.UNREACH', 'adapter':'Homematic', 'battery':'.OPERATING_VOLTAGE', 'reach':'.UNREACH'});
|
|
134
|
+
myArrDev.push({'Selektor':'0_userdata.*.link_quality', 'adapter':'Zigbee', 'battery':'.battery', 'reach':'.available'});
|
|
135
|
+
myArrDev.push({'Selektor':'0_userdata.*.reachable', 'adapter':'Test', 'battery':'.battery'});
|
|
136
|
+
myArrDev.push({'Selektor':'0_userdata.*.rssi', 'adapter':'Test', 'battery':'.sensor.battery'});
|
|
137
|
+
this.log.warn('Teststates wurden ausgewählt. Lade Daten...');
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (this.config.bleDevices) {
|
|
141
|
+
myArrDev.push({'Selektor':'ble.*.rssi', 'adapter':'Ble', 'battery':'.battery', 'reach':'none', 'isLowBat':'none'});
|
|
142
|
+
this.log.info('Ble Devices wurden ausgewählt (Xiaomi Plant Sensor). Lade Daten...');
|
|
143
|
+
}
|
|
144
|
+
if (this.config.zigbeeDevices) {
|
|
145
|
+
myArrDev.push({'Selektor':'zigbee.*.link_quality', 'adapter':'Zigbee', 'battery':'.battery', 'reach':'.available', 'isLowBat':'none'});
|
|
146
|
+
this.log.info('Zigbee Devices wurden ausgewählt. Lade Daten...');
|
|
147
|
+
}
|
|
148
|
+
if (this.config.sonoffDevices) {
|
|
149
|
+
myArrDev.push({'Selektor':'sonoff.*.Wifi_RSSI', 'adapter':'Sonoff', 'battery':'.battery', 'reach':'none', 'isLowBat':'none'});
|
|
150
|
+
myArrDev.push({'Selektor':'sonoff.*.Wifi_Signal', 'adapter':'Sonoff', 'battery':'.battery', 'reach':'none', 'isLowBat':'none'});
|
|
151
|
+
myArrDev.push({'Selektor':'sonoff.*.RSSI', 'adapter':'Sonoff', 'battery':'.battery', 'reach':'none', 'isLowBat':'none'});
|
|
152
|
+
this.log.info('Sonoff Devices wurden ausgewählt. Lade Daten...');
|
|
153
|
+
}
|
|
154
|
+
if (this.config.shellyDevices) {
|
|
155
|
+
myArrDev.push({'Selektor':'shelly.*.rssi', 'adapter':'Shelly', 'battery':'.sensor.battery', 'reach':'none', 'isLowBat':'none'});
|
|
156
|
+
this.log.info('Shelly Devices wurden ausgewählt. Lade Daten...');
|
|
157
|
+
}
|
|
158
|
+
if (this.config.homematicDevices) {
|
|
159
|
+
myArrDev.push({'Selektor':'hm-rpc.*.RSSI_DEVICE', 'adapter':'Homematic', 'battery':'.OPERATING_VOLTAGE', 'reach':'.UNREACH', 'isLowBat':'none'});
|
|
160
|
+
this.log.info('Homematic Devices wurden ausgewählt. Lade Daten...');
|
|
161
|
+
}
|
|
162
|
+
if (this.config.deconzDevices) {
|
|
163
|
+
myArrDev.push({'Selektor':'deconz.*.reachable', 'adapter':'Deconz', 'battery':'.battery', 'reach':'.reachable', 'isLowBat':'none'});
|
|
164
|
+
this.log.info('Deconz Devices wurden ausgewählt. Lade Daten...');
|
|
165
|
+
}
|
|
166
|
+
if (this.config.zwaveDevices) {
|
|
167
|
+
myArrDev.push({'Selektor':'zwave.*.ready', 'adapter':'Zwave', 'battery':'.battery.level', 'reach':'.ready', 'isLowBat':'.battery.isLow'});
|
|
168
|
+
this.log.info('Zwave Devices wurden ausgewählt. Lade Daten...');
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
this.log.debug(JSON.stringify(myArrDev));
|
|
172
|
+
|
|
173
|
+
/*=============================================
|
|
174
|
+
= Start of main loop =
|
|
175
|
+
=============================================*/
|
|
176
|
+
for (let i = 0; i < myArrDev.length; i++) {
|
|
177
|
+
const devices = await this.getForeignStatesAsync(myArrDev[i].Selektor);
|
|
178
|
+
const deviceAdapterName = myArrDev[i].adapter;
|
|
179
|
+
|
|
180
|
+
this.log.debug(JSON.stringify(devices));
|
|
181
|
+
|
|
182
|
+
const myBlacklist = this.config.tableBlacklist;
|
|
183
|
+
const myBlacklistArr = [];
|
|
184
|
+
|
|
185
|
+
/*---------- Loop for blacklist ----------*/
|
|
186
|
+
for(const i in myBlacklist){
|
|
187
|
+
myBlacklistArr.push(myBlacklist[i].device);
|
|
188
|
+
this.log.debug('Found items on the blacklist: ' + myBlacklistArr);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/*---------- Start of second main loop ----------*/
|
|
192
|
+
for(const [id] of Object.entries(devices)) {
|
|
193
|
+
if (!myBlacklistArr.includes(id)) {
|
|
194
|
+
|
|
195
|
+
const currDeviceString = id.slice(0, (id.lastIndexOf('.') + 1) - 1);
|
|
196
|
+
|
|
197
|
+
//Get device name
|
|
198
|
+
const deviceObject = await this.getForeignObjectAsync(currDeviceString);
|
|
199
|
+
let deviceName;
|
|
200
|
+
|
|
201
|
+
if (deviceObject && typeof deviceObject === 'object') {
|
|
202
|
+
deviceName = deviceObject.common.name;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
//Get room name (not implement yet)
|
|
207
|
+
//const getRoomName = await this.getEnumAsync('rooms');
|
|
208
|
+
//let currRoom;
|
|
209
|
+
//this.log.warn(JSON.stringify(getRoomName));
|
|
210
|
+
|
|
211
|
+
/*for(const [id] of Object.entries(getRoomName.result)) {
|
|
212
|
+
currRoom = await capitalize(id.substring(id.lastIndexOf('.') + 1)) ;
|
|
213
|
+
this.log.warn(currRoom);
|
|
214
|
+
}*/
|
|
215
|
+
|
|
216
|
+
// 1. Get link quality
|
|
217
|
+
const deviceQualityState = await this.getForeignStateAsync(id);
|
|
218
|
+
let linkQuality;
|
|
219
|
+
|
|
220
|
+
if (deviceQualityState){
|
|
221
|
+
if (this.config.trueState) {
|
|
222
|
+
linkQuality = deviceQualityState.val;
|
|
223
|
+
} else if ((deviceQualityState.val != null) && (typeof deviceQualityState.val === 'number')) {
|
|
224
|
+
if (deviceQualityState.val < 0) {
|
|
225
|
+
linkQuality = Math.min(Math.max(2 * (deviceQualityState.val + 100), 0), 100) + '%';
|
|
226
|
+
} else if ((deviceQualityState.val) >= 0) {
|
|
227
|
+
linkQuality = parseFloat((100/255 * deviceQualityState.val).toFixed(0)) + '%';
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
jsonLinkQualityDevices.push(
|
|
232
|
+
{
|
|
233
|
+
Device: deviceName,
|
|
234
|
+
Adapter: deviceAdapterName,
|
|
235
|
+
Link_quality: linkQuality
|
|
236
|
+
}
|
|
237
|
+
);
|
|
238
|
+
|
|
239
|
+
// 1b. Count how many devices are exists
|
|
240
|
+
deviceCounter = jsonLinkQualityDevices.length;
|
|
241
|
+
|
|
242
|
+
// 2. When was the last contact to the device?
|
|
243
|
+
if (deviceQualityState) {
|
|
244
|
+
try {
|
|
245
|
+
const time = new Date();
|
|
246
|
+
const lastContact = Math.round((time.getTime() - deviceQualityState.ts) / 1000 / 60);
|
|
247
|
+
const currDeviceUnreachString = currDeviceString + myArrDev[i].reach;
|
|
248
|
+
const deviceUnreachState = await this.getForeignStateAsync(currDeviceUnreachString);
|
|
249
|
+
|
|
250
|
+
// 2b. wenn seit X Minuten kein Kontakt mehr besteht, nimm Gerät in Liste auf
|
|
251
|
+
//Rechne auf Tage um, wenn mehr als 48 Stunden seit letztem Kontakt vergangen sind
|
|
252
|
+
//lastContactString = Math.round(lastContact) + ' Minuten';
|
|
253
|
+
lastContactString = this.formatDate(new Date((deviceQualityState.ts)), 'hh:mm') + ' Uhr';
|
|
254
|
+
if (Math.round(lastContact) > 100) {
|
|
255
|
+
lastContactString = Math.round(lastContact/60) + ' Stunden';
|
|
256
|
+
}
|
|
257
|
+
if (Math.round(lastContact/60) > 48) {
|
|
258
|
+
lastContactString = Math.round(lastContact/60/24) + ' Tagen';
|
|
259
|
+
}
|
|
260
|
+
if (myArrDev[i].reach === 'none') {
|
|
261
|
+
if (lastContact > this.config.maxMinutes) {
|
|
262
|
+
arrOfflineDevices.push(
|
|
263
|
+
{
|
|
264
|
+
Device: deviceName,
|
|
265
|
+
Adapter: deviceAdapterName,
|
|
266
|
+
Last_contact: lastContactString
|
|
267
|
+
}
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
} else {
|
|
271
|
+
if (deviceUnreachState) {
|
|
272
|
+
if ((deviceUnreachState.val === true) && (myArrDev[i].adapter === 'Homematic')) {
|
|
273
|
+
arrOfflineDevices.push(
|
|
274
|
+
{
|
|
275
|
+
Device: deviceName,
|
|
276
|
+
Adapter: deviceAdapterName,
|
|
277
|
+
Last_contact: lastContactString
|
|
278
|
+
}
|
|
279
|
+
);
|
|
280
|
+
} else if ((deviceUnreachState.val === false) && (myArrDev[i].adapter != 'Homematic')) {
|
|
281
|
+
arrOfflineDevices.push(
|
|
282
|
+
{
|
|
283
|
+
Device: deviceName,
|
|
284
|
+
Adapter: deviceAdapterName,
|
|
285
|
+
Last_contact: lastContactString
|
|
286
|
+
}
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
} catch (e) {
|
|
292
|
+
this.log.error('(03) Error while getting timestate ' + e);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
// 2c. Count how many devcies are offline
|
|
298
|
+
offlineDevicesCount = arrOfflineDevices.length;
|
|
299
|
+
|
|
300
|
+
// 3. Get battery states
|
|
301
|
+
const currDeviceBatteryString = currDeviceString + myArrDev[i].battery;
|
|
302
|
+
const deviceBatteryState = await this.getForeignStateAsync(currDeviceBatteryString);
|
|
303
|
+
let batteryHealth;
|
|
304
|
+
|
|
305
|
+
if (!deviceBatteryState) {
|
|
306
|
+
batteryHealth = ' - ';
|
|
307
|
+
} else if ((myArrDev[i].adapter === 'Homematic') && (deviceBatteryState).val === 0) {
|
|
308
|
+
batteryHealth = ' - ';
|
|
309
|
+
} else if ((deviceBatteryState) && (myArrDev[i].adapter != 'Homematic')) {
|
|
310
|
+
batteryHealth = (deviceBatteryState).val + '%';
|
|
311
|
+
arrBatteryPowered.push(
|
|
312
|
+
{
|
|
313
|
+
Device: deviceName,
|
|
314
|
+
Adapter: deviceAdapterName,
|
|
315
|
+
Battery: batteryHealth
|
|
316
|
+
}
|
|
317
|
+
);
|
|
318
|
+
} else if ((deviceBatteryState) && (deviceBatteryState).val != 0 && myArrDev[i].adapter === 'Homematic') {
|
|
319
|
+
batteryHealth = (deviceBatteryState).val + 'V';
|
|
320
|
+
arrBatteryPowered.push(
|
|
321
|
+
{
|
|
322
|
+
Device: deviceName,
|
|
323
|
+
Adapter: deviceAdapterName,
|
|
324
|
+
Battery: batteryHealth
|
|
325
|
+
}
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
// 3b. Count how many devices are with battery
|
|
329
|
+
batteryPoweredCount = arrBatteryPowered.length;
|
|
330
|
+
|
|
331
|
+
// 3c. Count how many devices are with low battery
|
|
332
|
+
if (deviceBatteryState && deviceBatteryState.val) {
|
|
333
|
+
const batteryWarningMin = this.config.minWarnBatterie;
|
|
334
|
+
if ((deviceBatteryState.val < batteryWarningMin) && (myArrDev[i].adapter != 'Homematic')) {
|
|
335
|
+
arrBatteryLowPowered.push(
|
|
336
|
+
{
|
|
337
|
+
Device: deviceName,
|
|
338
|
+
Adapter: deviceAdapterName,
|
|
339
|
+
Battery: batteryHealth
|
|
340
|
+
}
|
|
341
|
+
);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
}
|
|
345
|
+
// 3d. Count how many devices are with low battery
|
|
346
|
+
lowBatteryPoweredCount = arrBatteryLowPowered.length;
|
|
347
|
+
|
|
348
|
+
// 4. Add all devices in the list
|
|
349
|
+
arrListAllDevices.push(
|
|
350
|
+
{
|
|
351
|
+
Device: deviceName,
|
|
352
|
+
Adapter: deviceAdapterName,
|
|
353
|
+
Battery: batteryHealth,
|
|
354
|
+
Last_contact: lastContactString,
|
|
355
|
+
Link_quality: linkQuality
|
|
356
|
+
}
|
|
357
|
+
);
|
|
358
|
+
}
|
|
359
|
+
} //<--End of second loop
|
|
360
|
+
} //<---End of main loop
|
|
361
|
+
|
|
362
|
+
/*=============================================
|
|
363
|
+
= Notifications =
|
|
364
|
+
=============================================*/
|
|
365
|
+
|
|
366
|
+
/*---------- oflline notification ----------*/
|
|
367
|
+
if(this.config.checkSendOfflineMsg) {
|
|
368
|
+
try {
|
|
369
|
+
let msg = '';
|
|
370
|
+
const offlineDevicesCountOld = await this.getStateAsync('offlineCount');
|
|
371
|
+
|
|
372
|
+
if ((offlineDevicesCountOld != undefined) && (offlineDevicesCountOld != null)) {
|
|
373
|
+
if ((offlineDevicesCount != offlineDevicesCountOld.val) && (offlineDevicesCount != 0)) {
|
|
374
|
+
if (offlineDevicesCount == 1) {
|
|
375
|
+
msg = 'Folgendes Gerät ist seit einiger Zeit nicht erreichbar: \n';
|
|
376
|
+
} else if (offlineDevicesCount >= 2) {
|
|
377
|
+
msg = 'Folgende ' + offlineDevicesCount + ' Geräte sind seit einiger Zeit nicht erreichbar: \n';
|
|
378
|
+
}
|
|
379
|
+
for (const id of arrOfflineDevices) {
|
|
380
|
+
msg = msg + '\n' + id['Device'] + ' ' + /*id['room'] +*/ ' (' + id['Last_contact'] + ')';
|
|
381
|
+
}
|
|
382
|
+
this.log.info(msg);
|
|
383
|
+
await this.setStateAsync('lastNotification', msg, true);
|
|
384
|
+
if (pushover.instance) {
|
|
385
|
+
try {
|
|
386
|
+
await sendPushover(msg);
|
|
387
|
+
} catch (e) {
|
|
388
|
+
this.log.warn ('Getting error at sending notification' + (e));
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
if (telegram.instance) {
|
|
392
|
+
try {
|
|
393
|
+
await sendTelegram(msg);
|
|
394
|
+
} catch (e) {
|
|
395
|
+
this.log.warn ('Getting error at sending notification' + (e));
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
if (email.instance) {
|
|
399
|
+
try {
|
|
400
|
+
await sendEmail(msg);
|
|
401
|
+
} catch (e) {
|
|
402
|
+
this.log.warn ('Getting error at sending notification' + (e));
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
if (jarvis.instance) {
|
|
406
|
+
try {
|
|
407
|
+
await sendJarvis('{"title":"'+ jarvis.title +' (' + this.formatDate(new Date(), 'DD.MM.YYYY - hh:mm:ss') + ')","message":" ' + offlineDevicesCount + ' Geräte sind nicht erreichbar","display": "drawer"}');
|
|
408
|
+
} catch (e) {
|
|
409
|
+
this.log.warn ('Getting error at sending notification' + (e));
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
} catch (e) {
|
|
418
|
+
this.log.debug('Getting error at sending offline notification ' + e);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/*---------- Low battery Notification ----------*/
|
|
424
|
+
const now = new Date();
|
|
425
|
+
const today = now.getDay();
|
|
426
|
+
const checkDays = [];
|
|
427
|
+
let checkToday;
|
|
428
|
+
|
|
429
|
+
if (choosedDays.monday) checkDays.push(1);
|
|
430
|
+
if (choosedDays.tuesday) checkDays.push(2);
|
|
431
|
+
if (choosedDays.wednesday) checkDays.push(3);
|
|
432
|
+
if (choosedDays.thursday) checkDays.push(4);
|
|
433
|
+
if (choosedDays.friday) checkDays.push(5);
|
|
434
|
+
if (choosedDays.saturday) checkDays.push(6);
|
|
435
|
+
if (choosedDays.sunday) checkDays.push(0);
|
|
436
|
+
|
|
437
|
+
if (this.config.checkSendBatteryMsg) this.log.debug(JSON.stringify(checkDays));
|
|
438
|
+
|
|
439
|
+
checkDays.forEach(object => {
|
|
440
|
+
if((object >= 0) && today == object){
|
|
441
|
+
checkToday = true;
|
|
442
|
+
}
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
if (this.config.checkSendBatteryMsg) {
|
|
446
|
+
try {
|
|
447
|
+
//Nur einmal abfragen
|
|
448
|
+
const lastBatteryNotifyIndicator = await this.getStateAsync('info.lastBatteryNotification');
|
|
449
|
+
|
|
450
|
+
if ((lastBatteryNotifyIndicator != undefined) && (lastBatteryNotifyIndicator != null)) {
|
|
451
|
+
if (now.getHours() < 11) {await this.setStateAsync('info.lastBatteryNotification', false, true);}
|
|
452
|
+
if ((now.getHours() > 11) && (lastBatteryNotifyIndicator.val == false) && (checkToday != undefined)){
|
|
453
|
+
let batteryMinCount = 0;
|
|
454
|
+
const batteryWarningMin = this.config.minWarnBatterie;
|
|
455
|
+
|
|
456
|
+
let infotext = '';
|
|
457
|
+
for (const id of arrBatteryPowered) {
|
|
458
|
+
if (id['Battery']) {
|
|
459
|
+
const batteryValue = parseFloat(id['Battery'].replace('%', ''));
|
|
460
|
+
if ((batteryValue < batteryWarningMin) && (id['Adapter'] != 'Homematic')) {
|
|
461
|
+
infotext = infotext + '\n' + id['Device'] + ' ' + /*id['room'] +*/ ' (' + id['Battery'] + ')'.split(', ');
|
|
462
|
+
++batteryMinCount;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
if (batteryMinCount > 0) {
|
|
467
|
+
this.log.info('Batteriezustände: ' + infotext);
|
|
468
|
+
await this.setStateAsync('lastNotification', infotext, true);
|
|
469
|
+
if (jarvis.instance) {
|
|
470
|
+
try {
|
|
471
|
+
await sendJarvis('{"title":"'+ jarvis.title +' (' + this.formatDate(new Date(), 'DD.MM.YYYY - hh:mm:ss') + ')","message":" ' + batteryMinCount + ' Geräte mit schwacher Batterie","display": "drawer"}');
|
|
472
|
+
} catch (e) {
|
|
473
|
+
this.log.warn ('Getting error at sending notification' + (e));
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
if (pushover.instance) {
|
|
477
|
+
try {
|
|
478
|
+
await sendPushover('Batteriezustände: ' + infotext);
|
|
479
|
+
} catch (e) {
|
|
480
|
+
this.log.warn ('Getting error at sending notification' + (e));
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
if (telegram.instance) {
|
|
484
|
+
try {
|
|
485
|
+
await sendTelegram('Batteriezuständ: ' + infotext);
|
|
486
|
+
} catch (e) {
|
|
487
|
+
this.log.warn ('Getting error at sending notification' + (e));
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
await this.setStateAsync('info.lastBatteryNotification', true, true);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
} catch (e) {
|
|
495
|
+
this.log.debug('Getting error at batterynotification ' + e);
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
|
|
500
|
+
/*===== End of Section notifications ======*/
|
|
501
|
+
|
|
502
|
+
|
|
503
|
+
/*=============================================
|
|
504
|
+
= Write Datapoints =
|
|
505
|
+
=============================================*/
|
|
506
|
+
this.log.debug('write the datapoints ' + this.main.name);
|
|
507
|
+
|
|
508
|
+
try {
|
|
509
|
+
await this.setStateAsync('offlineCount', {val: offlineDevicesCount, ack: true});
|
|
510
|
+
await this.setStateAsync('countAll', {val: deviceCounter, ack: true});
|
|
511
|
+
await this.setStateAsync('batteryCount', {val: batteryPoweredCount, ack: true});
|
|
512
|
+
await this.setStateAsync('lowBatteryCount', {val: lowBatteryPoweredCount, ack: true});
|
|
513
|
+
|
|
514
|
+
if (deviceCounter == 0) {
|
|
515
|
+
jsonLinkQualityDevices = [{Device: '--keine--', Adapter: '', Link_quality: ''}]; //JSON-Info alle mit LinkQuality
|
|
516
|
+
arrListAllDevices = [{Device: '--keine--', Adapter: '', Battery: '', Last_contact: '', Link_quality: ''}]; //JSON-Info Gesamtliste mit Info je Gerät
|
|
517
|
+
|
|
518
|
+
await this.setStateAsync('linkQualityList', {val: JSON.stringify(jsonLinkQualityDevices), ack: true});
|
|
519
|
+
await this.setStateAsync('listAll', {val: JSON.stringify(arrListAllDevices), ack: true});
|
|
520
|
+
} else {
|
|
521
|
+
await this.setStateAsync('linkQualityList', {val: JSON.stringify(jsonLinkQualityDevices), ack: true});
|
|
522
|
+
await this.setStateAsync('listAll', {val: JSON.stringify(arrListAllDevices), ack: true});
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
if (offlineDevicesCount == 0) {
|
|
526
|
+
arrOfflineDevices = [{Device: '--keine--', Adapter: '', Last_contact: ''}]; //JSON-Info alle offline-Geräte = 0
|
|
527
|
+
|
|
528
|
+
await this.setStateAsync('offlineList', {val: JSON.stringify(arrOfflineDevices), ack: true});
|
|
529
|
+
} else {
|
|
530
|
+
await this.setStateAsync('offlineList', {val: JSON.stringify(arrOfflineDevices), ack: true});
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
if (batteryPoweredCount == 0) {
|
|
534
|
+
arrBatteryPowered = [{Device: '--keine--', Adapter: '', Battery: ''}]; //JSON-Info alle batteriebetriebenen Geräte
|
|
535
|
+
|
|
536
|
+
await this.setStateAsync('batteryList', {val: JSON.stringify(arrBatteryPowered), ack: true});
|
|
537
|
+
} else {
|
|
538
|
+
await this.setStateAsync('batteryList', {val: JSON.stringify(arrBatteryPowered), ack: true});
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
if (lowBatteryPoweredCount == 0) {
|
|
542
|
+
arrBatteryLowPowered = [{Device: '--keine--', Adapter: '', Battery: ''}]; //JSON-Info alle batteriebetriebenen Geräte
|
|
543
|
+
|
|
544
|
+
await this.setStateAsync('lowBatteryList', {val: JSON.stringify(arrBatteryLowPowered), ack: true});
|
|
545
|
+
} else {
|
|
546
|
+
await this.setStateAsync('lowBatteryList', {val: JSON.stringify(arrBatteryLowPowered), ack: true});
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
//Zeitstempel wann die Datenpunkte zuletzt gecheckt wurden
|
|
550
|
+
const lastCheck = this.formatDate(new Date(), 'DD.MM.YYYY') + ' - ' + this.formatDate(new Date(), 'hh:mm:ss');
|
|
551
|
+
await this.setStateAsync('lastCheck', lastCheck, true);
|
|
552
|
+
|
|
553
|
+
this.log.debug('write the datapoints finished ' + this.main.name);
|
|
554
|
+
}
|
|
555
|
+
catch (e) {
|
|
556
|
+
this.log.error('(05) Error while writing the states ' + e);
|
|
557
|
+
}
|
|
558
|
+
/*===== End of writing Datapoints ======*/
|
|
559
|
+
|
|
560
|
+
this.log.debug('Function finished: ' + this.main.name);
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
onUnload(callback) {
|
|
564
|
+
try {
|
|
565
|
+
this.log.info('cleaned everything up...');
|
|
566
|
+
callback();
|
|
567
|
+
} catch (e) {
|
|
568
|
+
callback();
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
if (require.main !== module) {
|
|
574
|
+
// Export the constructor in compact mode
|
|
575
|
+
/**
|
|
576
|
+
* @param {Partial<utils.AdapterOptions>} [options={}]
|
|
577
|
+
*/
|
|
578
|
+
module.exports = (options) => new DeviceWatcher(options);
|
|
579
|
+
} else {
|
|
580
|
+
// otherwise start the instance directly
|
|
581
|
+
new DeviceWatcher();
|
|
582
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "iobroker.device-watcher",
|
|
3
|
+
"version": "0.0.6",
|
|
4
|
+
"description": "Watchdog for wireless devices",
|
|
5
|
+
"author": "Christian Behrends <mail@christian-behrends.de>",
|
|
6
|
+
"homepage": "https://github.com/ciddi89/ioBroker.device-watcher",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"keywords": [
|
|
9
|
+
"watchdog",
|
|
10
|
+
"devices",
|
|
11
|
+
"wireless",
|
|
12
|
+
"watcher"
|
|
13
|
+
],
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "git+ssh://git@github.com/ciddi89/ioBroker.device-watcher.git"
|
|
17
|
+
},
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@iobroker/adapter-core": "^2.6.0"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@alcalzone/release-script": "^3.5.9",
|
|
23
|
+
"@iobroker/adapter-dev": "^1.0.0",
|
|
24
|
+
"@iobroker/testing": "^3.0.2",
|
|
25
|
+
"@types/chai": "^4.3.1",
|
|
26
|
+
"@types/chai-as-promised": "^7.1.5",
|
|
27
|
+
"@types/mocha": "^9.1.1",
|
|
28
|
+
"@types/node": "^17.0.38",
|
|
29
|
+
"@types/proxyquire": "^1.3.28",
|
|
30
|
+
"@types/sinon": "^10.0.11",
|
|
31
|
+
"@types/sinon-chai": "^3.2.8",
|
|
32
|
+
"chai": "^4.3.6",
|
|
33
|
+
"chai-as-promised": "^7.1.1",
|
|
34
|
+
"eslint": "^8.16.0",
|
|
35
|
+
"mocha": "^10.0.0",
|
|
36
|
+
"proxyquire": "^2.1.3",
|
|
37
|
+
"sinon": "^14.0.0",
|
|
38
|
+
"sinon-chai": "^3.7.0",
|
|
39
|
+
"typescript": "~4.7.2"
|
|
40
|
+
},
|
|
41
|
+
"main": "main.js",
|
|
42
|
+
"files": [
|
|
43
|
+
"admin{,/!(src)/**}/!(tsconfig|tsconfig.*).json",
|
|
44
|
+
"admin{,/!(src)/**}/*.{html,css,png,svg,jpg,js}",
|
|
45
|
+
"lib/",
|
|
46
|
+
"www/",
|
|
47
|
+
"io-package.json",
|
|
48
|
+
"LICENSE",
|
|
49
|
+
"main.js"
|
|
50
|
+
],
|
|
51
|
+
"scripts": {
|
|
52
|
+
"test:js": "mocha --config test/mocharc.custom.json \"{!(node_modules|test)/**/*.test.js,*.test.js,test/**/test!(PackageFiles|Startup).js}\"",
|
|
53
|
+
"test:package": "mocha test/package --exit",
|
|
54
|
+
"test:unit": "mocha test/unit --exit",
|
|
55
|
+
"test:integration": "mocha test/integration --exit",
|
|
56
|
+
"test": "npm run test:js && npm run test:package",
|
|
57
|
+
"check": "tsc --noEmit -p tsconfig.check.json",
|
|
58
|
+
"lint": "eslint",
|
|
59
|
+
"translate": "translate-adapter",
|
|
60
|
+
"release": "release-script"
|
|
61
|
+
},
|
|
62
|
+
"bugs": {
|
|
63
|
+
"url": "https://github.com/ciddi89/ioBroker.device-watcher/issues"
|
|
64
|
+
},
|
|
65
|
+
"directories": {
|
|
66
|
+
"lib": "lib",
|
|
67
|
+
"test": "test"
|
|
68
|
+
}
|
|
69
|
+
}
|