homebridge-flume 2.0.1 → 2.0.4
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/.eslintrc.cjs +1 -1
- package/CHANGELOG.md +19 -0
- package/LICENSE +1 -1
- package/lib/connection/http.js +4 -4
- package/lib/device/leak-sensor.js +7 -9
- package/lib/platform.js +13 -17
- package/lib/utils/functions.js +15 -24
- package/package.json +4 -4
package/.eslintrc.cjs
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to homebridge-flume will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## 2.0.4 (2022-06-21)
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
|
|
9
|
+
- Bump `node` recommended versions to v14.19.3 or v16.15.1
|
|
10
|
+
|
|
11
|
+
## 2.0.3 (2022-05-28)
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- More fixes and refactoring
|
|
16
|
+
|
|
17
|
+
## 2.0.2 (2022-05-28)
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- Bump `node` recommended versions to v14.19.3 or v16.15.0
|
|
22
|
+
- Updated dependencies
|
|
23
|
+
|
|
5
24
|
## 2.0.1 (2022-04-30)
|
|
6
25
|
|
|
7
26
|
### Changed
|
package/LICENSE
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c)
|
|
3
|
+
Copyright (c) 2022 Darrin Thomas & Ben Potter
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
package/lib/connection/http.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import axios from 'axios';
|
|
2
2
|
import jwtDecode from 'jwt-decode';
|
|
3
3
|
import platformConsts from '../utils/constants.js';
|
|
4
|
-
import
|
|
4
|
+
import { sleep } from '../utils/functions.js';
|
|
5
5
|
import platformLang from '../utils/lang-en.js';
|
|
6
6
|
|
|
7
7
|
export default class {
|
|
@@ -87,7 +87,7 @@ export default class {
|
|
|
87
87
|
if (err.code && platformConsts.httpRetryCodes.includes(err.code)) {
|
|
88
88
|
// Retry if another attempt could be successful
|
|
89
89
|
this.log.warn('[HTTP obtainToken()] %s [%s].', platformLang.httpRetry, err.code);
|
|
90
|
-
await
|
|
90
|
+
await sleep(30000);
|
|
91
91
|
return this.obtainToken();
|
|
92
92
|
}
|
|
93
93
|
throw new Error(`[HTTP obtainToken()] ${err.message}`);
|
|
@@ -155,7 +155,7 @@ export default class {
|
|
|
155
155
|
if (err.code && platformConsts.httpRetryCodes.includes(err.code)) {
|
|
156
156
|
// Retry if another attempt could be successful
|
|
157
157
|
this.log.warn('[HTTP renewToken()] %s [%s].', platformLang.httpRetry, err.code);
|
|
158
|
-
await
|
|
158
|
+
await sleep(30000);
|
|
159
159
|
return this.renewToken();
|
|
160
160
|
}
|
|
161
161
|
throw new Error(`[HTTP renewToken()] ${err.message}`);
|
|
@@ -190,7 +190,7 @@ export default class {
|
|
|
190
190
|
if (err.code && platformConsts.httpRetryCodes.includes(err.code)) {
|
|
191
191
|
// Retry if another attempt could be successful
|
|
192
192
|
this.log.warn('[HTTP getDevices()] %s [%s].', platformLang.httpRetry, err.code);
|
|
193
|
-
await
|
|
193
|
+
await sleep(30000);
|
|
194
194
|
return this.getDevices();
|
|
195
195
|
}
|
|
196
196
|
throw new Error(`[HTTP getDevices()] ${err.message}`);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { hasProperty } from '../utils/functions.js';
|
|
2
2
|
|
|
3
3
|
export default class {
|
|
4
4
|
constructor(platform, accessory) {
|
|
@@ -6,11 +6,9 @@ export default class {
|
|
|
6
6
|
this.accessory = accessory;
|
|
7
7
|
this.cusChar = platform.cusChar;
|
|
8
8
|
this.hapChar = platform.api.hap.Characteristic;
|
|
9
|
-
this.hapErr = platform.api.hap.HapStatusError;
|
|
10
9
|
this.hapServ = platform.api.hap.Service;
|
|
11
10
|
this.log = platform.config.disableDeviceLogging ? () => {} : platform.log;
|
|
12
11
|
this.name = accessory.displayName;
|
|
13
|
-
this.platform = platform;
|
|
14
12
|
this.refreshInterval = platform.config.refreshInterval;
|
|
15
13
|
|
|
16
14
|
// Add the leak sensor service if it doesn't exist already
|
|
@@ -36,7 +34,7 @@ export default class {
|
|
|
36
34
|
externalUpdate(params) {
|
|
37
35
|
// Check the data for leak detection
|
|
38
36
|
if (
|
|
39
|
-
|
|
37
|
+
hasProperty(params.leakInfo, 'active')
|
|
40
38
|
&& params.leakInfo.active !== this.cacheLeak
|
|
41
39
|
) {
|
|
42
40
|
this.cacheLeak = params.leakInfo.active;
|
|
@@ -46,7 +44,7 @@ export default class {
|
|
|
46
44
|
|
|
47
45
|
// Check the data for battery level, cacheBatt is true for OK and false for LOW
|
|
48
46
|
if (
|
|
49
|
-
|
|
47
|
+
hasProperty(params.devInfo, 'battery_level')
|
|
50
48
|
&& (params.devInfo.battery_level !== 'low') !== this.cacheBatt
|
|
51
49
|
) {
|
|
52
50
|
this.cacheBatt = params.devInfo.battery_level !== 'low';
|
|
@@ -56,7 +54,7 @@ export default class {
|
|
|
56
54
|
|
|
57
55
|
// Check the data for connectivity, cacheStatus is true for OK and false for NOT CONNECTED
|
|
58
56
|
if (
|
|
59
|
-
|
|
57
|
+
hasProperty(params.devInfo, 'connected')
|
|
60
58
|
&& params.devInfo.connected !== this.cacheStatus
|
|
61
59
|
) {
|
|
62
60
|
this.cacheStatus = params.devInfo.connected;
|
|
@@ -69,7 +67,7 @@ export default class {
|
|
|
69
67
|
if (
|
|
70
68
|
params.waterInfo.today
|
|
71
69
|
&& params.waterInfo.today[0]
|
|
72
|
-
&&
|
|
70
|
+
&& hasProperty(params.waterInfo.today[0], 'value')
|
|
73
71
|
) {
|
|
74
72
|
this.leakService.updateCharacteristic(
|
|
75
73
|
this.cusChar.TodayUsage,
|
|
@@ -79,7 +77,7 @@ export default class {
|
|
|
79
77
|
if (
|
|
80
78
|
params.waterInfo.month
|
|
81
79
|
&& params.waterInfo.month[0]
|
|
82
|
-
&&
|
|
80
|
+
&& hasProperty(params.waterInfo.month[0], 'value')
|
|
83
81
|
) {
|
|
84
82
|
this.leakService.updateCharacteristic(
|
|
85
83
|
this.cusChar.MonthUsage,
|
|
@@ -89,7 +87,7 @@ export default class {
|
|
|
89
87
|
if (
|
|
90
88
|
params.waterInfo.prevMonth
|
|
91
89
|
&& params.waterInfo.prevMonth[0]
|
|
92
|
-
&&
|
|
90
|
+
&& hasProperty(params.waterInfo.prevMonth[0], 'value')
|
|
93
91
|
) {
|
|
94
92
|
this.leakService.updateCharacteristic(
|
|
95
93
|
this.cusChar.PrevMonthUsage,
|
package/lib/platform.js
CHANGED
|
@@ -1,19 +1,16 @@
|
|
|
1
|
-
// Packages and constant variables for this class
|
|
2
1
|
import { createRequire } from 'module';
|
|
3
2
|
import httpClient from './connection/http.js';
|
|
4
3
|
import deviceLeakSensor from './device/leak-sensor.js';
|
|
5
4
|
import platformConsts from './utils/constants.js';
|
|
6
5
|
import platformChars from './utils/custom-chars.js';
|
|
7
|
-
import
|
|
6
|
+
import { parseError } from './utils/functions.js';
|
|
8
7
|
import platformLang from './utils/lang-en.js';
|
|
9
8
|
|
|
10
9
|
const require = createRequire(import.meta.url);
|
|
11
10
|
const plugin = require('../package.json');
|
|
12
11
|
|
|
13
|
-
// Create the platform class
|
|
14
12
|
export default class {
|
|
15
13
|
constructor(log, config, api) {
|
|
16
|
-
// Don't load the plugin if these aren't accessible for any reason
|
|
17
14
|
if (!log || !api) {
|
|
18
15
|
return;
|
|
19
16
|
}
|
|
@@ -26,8 +23,8 @@ export default class {
|
|
|
26
23
|
// Configuration objects for accessories
|
|
27
24
|
this.devicesInHB = new Map();
|
|
28
25
|
|
|
29
|
-
// Make sure user is running Homebridge v1.
|
|
30
|
-
if (!api?.versionGreaterOrEqual
|
|
26
|
+
// Make sure user is running Homebridge v1.4 or above
|
|
27
|
+
if (!api?.versionGreaterOrEqual('1.4.0')) {
|
|
31
28
|
throw new Error(platformLang.hbVersionFail);
|
|
32
29
|
}
|
|
33
30
|
|
|
@@ -56,7 +53,7 @@ export default class {
|
|
|
56
53
|
this.api.on('shutdown', () => this.pluginShutdown());
|
|
57
54
|
} catch (err) {
|
|
58
55
|
// Catch any errors during initialisation
|
|
59
|
-
const eText =
|
|
56
|
+
const eText = parseError(err, [platformLang.hbVersionFail, platformLang.pluginNotConf]);
|
|
60
57
|
log.warn('***** %s. *****', platformLang.disabling);
|
|
61
58
|
log.warn('***** %s. *****', eText);
|
|
62
59
|
}
|
|
@@ -104,7 +101,6 @@ export default class {
|
|
|
104
101
|
break;
|
|
105
102
|
case 'name':
|
|
106
103
|
case 'platform':
|
|
107
|
-
case 'plugin_map':
|
|
108
104
|
break;
|
|
109
105
|
case 'refreshInterval': {
|
|
110
106
|
if (typeof val === 'string') {
|
|
@@ -132,15 +128,15 @@ export default class {
|
|
|
132
128
|
async pluginSetup() {
|
|
133
129
|
// Plugin has finished initialising so now onto setup
|
|
134
130
|
try {
|
|
131
|
+
// Log that the plugin initialisation has been successful
|
|
132
|
+
this.log('%s.', platformLang.initialised);
|
|
133
|
+
|
|
135
134
|
// If the user has disabled the plugin then remove all accessories
|
|
136
135
|
if (this.config.disablePlugin) {
|
|
137
136
|
this.devicesInHB.forEach((accessory) => this.removeAccessory(accessory));
|
|
138
137
|
throw new Error(platformLang.disabled);
|
|
139
138
|
}
|
|
140
139
|
|
|
141
|
-
// Log that the plugin initialisation has been successful
|
|
142
|
-
this.log('%s.', platformLang.initialised);
|
|
143
|
-
|
|
144
140
|
// Ensure username and password have been provided
|
|
145
141
|
if (
|
|
146
142
|
!this.config.username
|
|
@@ -193,7 +189,7 @@ export default class {
|
|
|
193
189
|
this.log('%s. %s', platformLang.complete, platformLang.zWelcome[randIndex]);
|
|
194
190
|
} catch (err) {
|
|
195
191
|
// Catch any errors during setup
|
|
196
|
-
const eText =
|
|
192
|
+
const eText = parseError(err, [
|
|
197
193
|
platformLang.noCreds,
|
|
198
194
|
platformLang.noDevices,
|
|
199
195
|
platformLang.disabled,
|
|
@@ -232,14 +228,14 @@ export default class {
|
|
|
232
228
|
toReturn.leakInfo = await this.httpClient.getLeakInfo(accessory.context.deviceId);
|
|
233
229
|
accessory.control.externalUpdate(toReturn);
|
|
234
230
|
} catch (err) {
|
|
235
|
-
const eText =
|
|
231
|
+
const eText = parseError(err);
|
|
236
232
|
this.log.warn('[%s] %s %s.', accessory.displayName, platformLang.devNotRef, eText);
|
|
237
233
|
}
|
|
238
234
|
this.counter += 1;
|
|
239
235
|
});
|
|
240
236
|
} catch (err) {
|
|
241
237
|
// Catch any errors performing the sync
|
|
242
|
-
const eText =
|
|
238
|
+
const eText = parseError(err, []);
|
|
243
239
|
this.log.warn('%s %s.', platformLang.syncFailed, eText);
|
|
244
240
|
}
|
|
245
241
|
}
|
|
@@ -278,7 +274,7 @@ export default class {
|
|
|
278
274
|
this.log('[%s] %s [%s].', accessory.displayName, platformLang.devInit, device.id);
|
|
279
275
|
} catch (err) {
|
|
280
276
|
// Catch any errors during device initialisation
|
|
281
|
-
const eText =
|
|
277
|
+
const eText = parseError(err, [platformLang.accNotFound]);
|
|
282
278
|
this.log.warn('[%s] %s %s.', device.id, platformLang.devNotInit, eText);
|
|
283
279
|
}
|
|
284
280
|
}
|
|
@@ -303,7 +299,7 @@ export default class {
|
|
|
303
299
|
return accessory;
|
|
304
300
|
} catch (err) {
|
|
305
301
|
// Catch any errors during add
|
|
306
|
-
const eText =
|
|
302
|
+
const eText = parseError(err);
|
|
307
303
|
this.log.warn('[%s] %s %s.', platformLang.brand, platformLang.devNotAdd, eText);
|
|
308
304
|
return false;
|
|
309
305
|
}
|
|
@@ -322,7 +318,7 @@ export default class {
|
|
|
322
318
|
this.log('[%s] %s.', accessory.displayName, platformLang.devRemove);
|
|
323
319
|
} catch (err) {
|
|
324
320
|
// Catch any errors during remove
|
|
325
|
-
const eText =
|
|
321
|
+
const eText = parseError(err);
|
|
326
322
|
const name = accessory.displayName;
|
|
327
323
|
this.log.warn('[%s] %s %s.', name, platformLang.devNotRemove, eText);
|
|
328
324
|
}
|
package/lib/utils/functions.js
CHANGED
|
@@ -1,27 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
hasProperty: (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop),
|
|
1
|
+
const hasProperty = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop);
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
if (err.stack && err.stack.length > 0 && !hideStack.includes(err.message)) {
|
|
11
|
-
const stack = err.stack.split('\n');
|
|
12
|
-
if (stack[1]) {
|
|
13
|
-
toReturn += stack[1].replace(' ', '');
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
return toReturn;
|
|
17
|
-
},
|
|
18
|
-
|
|
19
|
-
generateRandomString: (length) => {
|
|
20
|
-
const chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
|
|
21
|
-
let nonce = '';
|
|
22
|
-
while (nonce.length < length) {
|
|
23
|
-
nonce += chars.charAt(Math.floor(Math.random() * chars.length));
|
|
3
|
+
const parseError = (err, hideStack = []) => {
|
|
4
|
+
let toReturn = err.message;
|
|
5
|
+
if (err?.stack?.length > 0 && !hideStack.includes(err.message)) {
|
|
6
|
+
const stack = err.stack.split('\n');
|
|
7
|
+
if (stack[1]) {
|
|
8
|
+
toReturn += stack[1].replace(' ', '');
|
|
24
9
|
}
|
|
25
|
-
|
|
26
|
-
|
|
10
|
+
}
|
|
11
|
+
return toReturn;
|
|
27
12
|
};
|
|
13
|
+
|
|
14
|
+
const sleep = (ms) => new Promise((resolve) => {
|
|
15
|
+
setTimeout(resolve, ms);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
export { hasProperty, parseError, sleep };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "homebridge-flume",
|
|
3
3
|
"alias": "Flume",
|
|
4
|
-
"version": "2.0.
|
|
4
|
+
"version": "2.0.4",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Ben Potter",
|
|
7
7
|
"email": "bwp91@icloud.com"
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
},
|
|
30
30
|
"engines": {
|
|
31
31
|
"homebridge": "^1.4.0",
|
|
32
|
-
"node": "^14.19.
|
|
32
|
+
"node": "^14.19.3 || ^16.15.1"
|
|
33
33
|
},
|
|
34
34
|
"repository": {
|
|
35
35
|
"type": "git",
|
|
@@ -62,9 +62,9 @@
|
|
|
62
62
|
"jwt-decode": "^3.1.2"
|
|
63
63
|
},
|
|
64
64
|
"devDependencies": {
|
|
65
|
-
"eslint-config-airbnb": "^
|
|
65
|
+
"eslint-config-airbnb-base": "^15.0.0",
|
|
66
66
|
"eslint-plugin-import": "^2.26.0",
|
|
67
67
|
"eslint-plugin-sort-exports": "^0.6.0",
|
|
68
|
-
"eslint": "^8.
|
|
68
|
+
"eslint": "^8.18.0"
|
|
69
69
|
}
|
|
70
70
|
}
|