homebridge-flume 1.2.6 → 2.0.0
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 +23 -0
- package/CHANGELOG.md +18 -0
- package/README.md +2 -2
- package/lib/connection/http.js +106 -111
- package/lib/device/leak-sensor.js +51 -56
- package/lib/homebridge-ui/server.js +5 -9
- package/lib/index.js +5 -338
- package/lib/platform.js +330 -0
- package/lib/utils/constants.js +6 -10
- package/lib/utils/custom-chars.js +32 -35
- package/lib/utils/functions.js +16 -22
- package/lib/utils/lang-en.js +7 -10
- package/package.json +12 -4
package/.eslintrc.cjs
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
env: {
|
|
3
|
+
es2022: true,
|
|
4
|
+
node: true,
|
|
5
|
+
},
|
|
6
|
+
extends: ['airbnb'],
|
|
7
|
+
parserOptions: {
|
|
8
|
+
ecmaVersion: 'latest',
|
|
9
|
+
sourceType: 'module',
|
|
10
|
+
},
|
|
11
|
+
plugins: ['import', 'sort-exports'],
|
|
12
|
+
rules: {
|
|
13
|
+
camelcase: 'off',
|
|
14
|
+
'import/extensions': ['error', { js: 'always', json: 'always' }],
|
|
15
|
+
'import/order': ['warn', { alphabetize: { order: 'asc' } }],
|
|
16
|
+
'max-len': 'off',
|
|
17
|
+
'new-cap': 0,
|
|
18
|
+
quotes: ['error', 'single'],
|
|
19
|
+
'no-multiple-empty-lines': ['error', { max: 1, maxBOF: 1, maxEOF: 0 }],
|
|
20
|
+
'no-param-reassign': 0,
|
|
21
|
+
'sort-exports/sort-exports': ['warn', { sortDir: 'asc' }],
|
|
22
|
+
},
|
|
23
|
+
};
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to homebridge-flume will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## 2.0.0 (2022-04-23)
|
|
6
|
+
|
|
7
|
+
### Potentially Breaking Changes
|
|
8
|
+
|
|
9
|
+
⚠️ The minimum required version of Homebridge is now v1.4.0
|
|
10
|
+
⚠️ The minimum required version of Node is now v14
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- Changed to ESM package
|
|
15
|
+
|
|
16
|
+
## 1.2.7 (2022-04-03)
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- Bump `axios` to v0.26.1
|
|
21
|
+
- Updated dependencies
|
|
22
|
+
|
|
5
23
|
## 1.2.6 (2022-02-27)
|
|
6
24
|
|
|
7
25
|
### Changed
|
package/README.md
CHANGED
|
@@ -24,8 +24,8 @@ Homebridge plugin to integrate Flume devices into HomeKit
|
|
|
24
24
|
|
|
25
25
|
### Prerequisites
|
|
26
26
|
|
|
27
|
-
- To use this plugin, you will need to already have [Homebridge](https://homebridge.io) (at least v1.
|
|
28
|
-
- Whilst it is recommended to use [Node](https://nodejs.org/en/) v16, the plugin supports
|
|
27
|
+
- To use this plugin, you will need to already have [Homebridge](https://homebridge.io) (at least v1.4) or [HOOBS](https://hoobs.org) (at least v4.2) installed. Refer to the links for more information and installation instructions.
|
|
28
|
+
- Whilst it is recommended to use [Node](https://nodejs.org/en/) v16, the plugin supports v14 as per the [Homebridge guidelines](https://github.com/homebridge/homebridge/wiki/How-To-Update-Node.js).
|
|
29
29
|
|
|
30
30
|
### Setup
|
|
31
31
|
|
package/lib/connection/http.js
CHANGED
|
@@ -1,25 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
constructor (platform) {
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import jwtDecode from 'jwt-decode';
|
|
3
|
+
import platformConsts from '../utils/constants.js';
|
|
4
|
+
import platformFuncs from '../utils/functions.js';
|
|
5
|
+
import platformLang from '../utils/lang-en.js';
|
|
6
|
+
|
|
7
|
+
export default class {
|
|
8
|
+
constructor(platform) {
|
|
10
9
|
// Create variables usable by the class
|
|
11
|
-
this.
|
|
12
|
-
this.
|
|
13
|
-
this.
|
|
14
|
-
this.
|
|
15
|
-
this.
|
|
16
|
-
this.
|
|
17
|
-
this.password = platform.config.password
|
|
18
|
-
this.clientId = platform.config.clientId
|
|
19
|
-
this.clientSecret = platform.config.clientSecret
|
|
10
|
+
this.debug = platform.config.debug;
|
|
11
|
+
this.log = platform.log;
|
|
12
|
+
this.username = platform.config.username;
|
|
13
|
+
this.password = platform.config.password;
|
|
14
|
+
this.clientId = platform.config.clientId;
|
|
15
|
+
this.clientSecret = platform.config.clientSecret;
|
|
20
16
|
}
|
|
21
17
|
|
|
22
|
-
async obtainToken
|
|
18
|
+
async obtainToken() {
|
|
23
19
|
try {
|
|
24
20
|
// Generate the JSON data to send
|
|
25
21
|
const body = {
|
|
@@ -27,18 +23,18 @@ module.exports = class connectionHTTP {
|
|
|
27
23
|
client_id: this.clientId,
|
|
28
24
|
client_secret: this.clientSecret,
|
|
29
25
|
username: this.username,
|
|
30
|
-
password: this.password
|
|
31
|
-
}
|
|
32
|
-
const now = Date.now()
|
|
26
|
+
password: this.password,
|
|
27
|
+
};
|
|
28
|
+
const now = Date.now();
|
|
33
29
|
|
|
34
30
|
// Perform the HTTP request
|
|
35
31
|
const res = await axios.post('https://api.flumetech.com/oauth/token', body, {
|
|
36
|
-
timeout: 10000
|
|
37
|
-
})
|
|
32
|
+
timeout: 10000,
|
|
33
|
+
});
|
|
38
34
|
|
|
39
35
|
// Check to see we got a response
|
|
40
36
|
if (!res.data) {
|
|
41
|
-
throw new Error(
|
|
37
|
+
throw new Error(platformLang.noDataReceived);
|
|
42
38
|
}
|
|
43
39
|
|
|
44
40
|
/*
|
|
@@ -64,16 +60,16 @@ module.exports = class connectionHTTP {
|
|
|
64
60
|
|
|
65
61
|
// Log the response if in debug mode
|
|
66
62
|
if (this.debug) {
|
|
67
|
-
this.log('[HTTP obtainToken()] %s.', JSON.stringify(res.data))
|
|
63
|
+
this.log('[HTTP obtainToken()] %s.', JSON.stringify(res.data));
|
|
68
64
|
}
|
|
69
65
|
|
|
70
66
|
// Make the token available in other functions
|
|
71
|
-
this.accessToken = res.data.data[0].access_token
|
|
72
|
-
this.refreshToken = res.data.data[0].refresh_token
|
|
73
|
-
this.expiresIn = now + res.data.data[0].expires_in
|
|
67
|
+
this.accessToken = res.data.data[0].access_token;
|
|
68
|
+
this.refreshToken = res.data.data[0].refresh_token;
|
|
69
|
+
this.expiresIn = now + res.data.data[0].expires_in;
|
|
74
70
|
|
|
75
71
|
// Obtain the user ID
|
|
76
|
-
this.userId = jwtDecode(this.accessToken).user_id
|
|
72
|
+
this.userId = jwtDecode(this.accessToken).user_id;
|
|
77
73
|
|
|
78
74
|
/*
|
|
79
75
|
{
|
|
@@ -86,23 +82,23 @@ module.exports = class connectionHTTP {
|
|
|
86
82
|
sub: ''
|
|
87
83
|
}
|
|
88
84
|
*/
|
|
85
|
+
return true;
|
|
89
86
|
} catch (err) {
|
|
90
|
-
if (err.code &&
|
|
87
|
+
if (err.code && platformConsts.httpRetryCodes.includes(err.code)) {
|
|
91
88
|
// Retry if another attempt could be successful
|
|
92
|
-
this.log.warn('[HTTP obtainToken()] %s [%s].',
|
|
93
|
-
await
|
|
94
|
-
return
|
|
95
|
-
} else {
|
|
96
|
-
throw new Error('[HTTP obtainToken()] ' + err.message)
|
|
89
|
+
this.log.warn('[HTTP obtainToken()] %s [%s].', platformLang.httpRetry, err.code);
|
|
90
|
+
await platformFuncs.sleep(30000);
|
|
91
|
+
return this.obtainToken();
|
|
97
92
|
}
|
|
93
|
+
throw new Error(`[HTTP obtainToken()] ${err.message}`);
|
|
98
94
|
}
|
|
99
95
|
}
|
|
100
96
|
|
|
101
|
-
async renewToken
|
|
97
|
+
async renewToken() {
|
|
102
98
|
try {
|
|
103
99
|
// Check we have a refresh token
|
|
104
100
|
if (!this.refreshToken) {
|
|
105
|
-
throw new Error(
|
|
101
|
+
throw new Error(platformLang.noRefreshToken);
|
|
106
102
|
}
|
|
107
103
|
|
|
108
104
|
// Generate the JSON data to send
|
|
@@ -110,23 +106,23 @@ module.exports = class connectionHTTP {
|
|
|
110
106
|
grant_type: 'refresh_token',
|
|
111
107
|
client_id: this.clientId,
|
|
112
108
|
client_secret: this.clientSecret,
|
|
113
|
-
refresh_token: this.refreshToken
|
|
114
|
-
}
|
|
115
|
-
const now = Date.now()
|
|
109
|
+
refresh_token: this.refreshToken,
|
|
110
|
+
};
|
|
111
|
+
const now = Date.now();
|
|
116
112
|
|
|
117
113
|
// Perform the HTTP request
|
|
118
114
|
const res = await axios.post('https://api.flumetech.com/oauth/token', body, {
|
|
119
|
-
timeout: 10000
|
|
120
|
-
})
|
|
115
|
+
timeout: 10000,
|
|
116
|
+
});
|
|
121
117
|
|
|
122
118
|
// Check to see we got a response
|
|
123
119
|
if (!res.data) {
|
|
124
|
-
throw new Error(
|
|
120
|
+
throw new Error(platformLang.noDataReceived);
|
|
125
121
|
}
|
|
126
122
|
|
|
127
123
|
// Log the response if in debug mode
|
|
128
124
|
if (this.debug) {
|
|
129
|
-
this.log('[HTTP renewToken()] %s.', JSON.stringify(res.data))
|
|
125
|
+
this.log('[HTTP renewToken()] %s.', JSON.stringify(res.data));
|
|
130
126
|
}
|
|
131
127
|
|
|
132
128
|
/*
|
|
@@ -151,104 +147,103 @@ module.exports = class connectionHTTP {
|
|
|
151
147
|
*/
|
|
152
148
|
|
|
153
149
|
// Make the token available in other functions
|
|
154
|
-
this.accessToken = res.data.data[0].access_token
|
|
155
|
-
this.refreshToken = res.data.data[0].refresh_token
|
|
156
|
-
this.expiresIn = now + res.data.data[0].expires_in
|
|
150
|
+
this.accessToken = res.data.data[0].access_token;
|
|
151
|
+
this.refreshToken = res.data.data[0].refresh_token;
|
|
152
|
+
this.expiresIn = now + res.data.data[0].expires_in;
|
|
153
|
+
return true;
|
|
157
154
|
} catch (err) {
|
|
158
|
-
if (err.code &&
|
|
155
|
+
if (err.code && platformConsts.httpRetryCodes.includes(err.code)) {
|
|
159
156
|
// Retry if another attempt could be successful
|
|
160
|
-
this.log.warn('[HTTP renewToken()] %s [%s].',
|
|
161
|
-
await
|
|
162
|
-
return
|
|
163
|
-
} else {
|
|
164
|
-
throw new Error('[HTTP renewToken()] ' + err.message)
|
|
157
|
+
this.log.warn('[HTTP renewToken()] %s [%s].', platformLang.httpRetry, err.code);
|
|
158
|
+
await platformFuncs.sleep(30000);
|
|
159
|
+
return this.renewToken();
|
|
165
160
|
}
|
|
161
|
+
throw new Error(`[HTTP renewToken()] ${err.message}`);
|
|
166
162
|
}
|
|
167
163
|
}
|
|
168
164
|
|
|
169
|
-
async getDevices
|
|
165
|
+
async getDevices() {
|
|
170
166
|
try {
|
|
171
167
|
// Check we have a user id
|
|
172
168
|
if (!this.userId || !this.accessToken) {
|
|
173
|
-
throw new Error(
|
|
169
|
+
throw new Error(platformLang.noUserId);
|
|
174
170
|
}
|
|
175
171
|
|
|
176
172
|
// Perform the HTTP request
|
|
177
|
-
const res = await axios.get(
|
|
178
|
-
headers: { Authorization:
|
|
179
|
-
timeout: 10000
|
|
180
|
-
})
|
|
173
|
+
const res = await axios.get(`https://api.flumetech.com/users/${this.userId}/devices`, {
|
|
174
|
+
headers: { Authorization: `Bearer ${this.accessToken}` },
|
|
175
|
+
timeout: 10000,
|
|
176
|
+
});
|
|
181
177
|
|
|
182
178
|
// Check to see we got a response
|
|
183
179
|
if (!res.data) {
|
|
184
|
-
throw new Error(
|
|
180
|
+
throw new Error(platformLang.noDataReceived);
|
|
185
181
|
}
|
|
186
182
|
|
|
187
183
|
// Log the response if in debug mode
|
|
188
184
|
if (this.debug) {
|
|
189
|
-
this.log('[HTTP getDevices()] %s.', JSON.stringify(res.data))
|
|
185
|
+
this.log('[HTTP getDevices()] %s.', JSON.stringify(res.data));
|
|
190
186
|
}
|
|
191
187
|
|
|
192
|
-
return res.data.data
|
|
188
|
+
return res.data.data;
|
|
193
189
|
} catch (err) {
|
|
194
|
-
if (err.code &&
|
|
190
|
+
if (err.code && platformConsts.httpRetryCodes.includes(err.code)) {
|
|
195
191
|
// Retry if another attempt could be successful
|
|
196
|
-
this.log.warn('[HTTP getDevices()] %s [%s].',
|
|
197
|
-
await
|
|
198
|
-
return
|
|
199
|
-
} else {
|
|
200
|
-
throw new Error('[HTTP getDevices()] ' + err.message)
|
|
192
|
+
this.log.warn('[HTTP getDevices()] %s [%s].', platformLang.httpRetry, err.code);
|
|
193
|
+
await platformFuncs.sleep(30000);
|
|
194
|
+
return this.getDevices();
|
|
201
195
|
}
|
|
196
|
+
throw new Error(`[HTTP getDevices()] ${err.message}`);
|
|
202
197
|
}
|
|
203
198
|
}
|
|
204
199
|
|
|
205
|
-
async getDeviceInfo
|
|
200
|
+
async getDeviceInfo(deviceId) {
|
|
206
201
|
// Refresh the access token if it has expired already
|
|
207
202
|
if (Date.now() > this.expiresIn) {
|
|
208
|
-
await this.renewToken()
|
|
203
|
+
await this.renewToken();
|
|
209
204
|
}
|
|
210
205
|
|
|
211
206
|
// Send the request
|
|
212
207
|
const res = await axios.get(
|
|
213
|
-
|
|
208
|
+
`https://api.flumetech.com/users/${this.userId}/devices/${deviceId}`,
|
|
214
209
|
{
|
|
215
210
|
headers: {
|
|
216
|
-
Authorization:
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
)
|
|
211
|
+
Authorization: `Bearer ${this.accessToken}`,
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
);
|
|
220
215
|
|
|
221
216
|
// Check to see we got a response
|
|
222
217
|
if (!res.data) {
|
|
223
|
-
throw new Error(
|
|
218
|
+
throw new Error(platformLang.noDataReceived);
|
|
224
219
|
}
|
|
225
220
|
|
|
226
221
|
// Log the response if in debug mode
|
|
227
222
|
if (this.debug) {
|
|
228
|
-
this.log('[HTTP getDeviceInfo()] %s.', JSON.stringify(res.data))
|
|
223
|
+
this.log('[HTTP getDeviceInfo()] %s.', JSON.stringify(res.data));
|
|
229
224
|
}
|
|
230
225
|
|
|
231
226
|
// Parse the response
|
|
232
|
-
return res.data.data[0]
|
|
227
|
+
return res.data.data[0];
|
|
233
228
|
}
|
|
234
229
|
|
|
235
|
-
async getWaterInfo
|
|
230
|
+
async getWaterInfo(deviceId) {
|
|
236
231
|
// Refresh the access token if it has expired already
|
|
237
232
|
if (Date.now() > this.expiresIn) {
|
|
238
|
-
await this.renewToken()
|
|
233
|
+
await this.renewToken();
|
|
239
234
|
}
|
|
240
235
|
|
|
241
236
|
// Generate dates for the query data
|
|
242
|
-
const date = new Date()
|
|
243
|
-
const startOfToday = date.toISOString().substring(0, 10)
|
|
237
|
+
const date = new Date();
|
|
238
|
+
const startOfToday = `${date.toISOString().substring(0, 10)} 00:00:00`;
|
|
244
239
|
|
|
245
240
|
// Set the date to the first of the current month
|
|
246
|
-
date.setDate(1)
|
|
247
|
-
const startOfCurrMonth = date.toISOString().substring(0, 10)
|
|
241
|
+
date.setDate(1);
|
|
242
|
+
const startOfCurrMonth = `${date.toISOString().substring(0, 10)} 00:00:00`;
|
|
248
243
|
|
|
249
244
|
// Set the month to the previous month
|
|
250
|
-
date.setMonth(date.getMonth() - 1)
|
|
251
|
-
const startOfPrevMonth = date.toISOString().substring(0, 10)
|
|
245
|
+
date.setMonth(date.getMonth() - 1);
|
|
246
|
+
const startOfPrevMonth = `${date.toISOString().substring(0, 10)} 00:00:00`;
|
|
252
247
|
|
|
253
248
|
// Generate the JSON data to send
|
|
254
249
|
const body = {
|
|
@@ -258,14 +253,14 @@ module.exports = class connectionHTTP {
|
|
|
258
253
|
bucket: 'DAY',
|
|
259
254
|
since_datetime: startOfToday,
|
|
260
255
|
operation: 'SUM',
|
|
261
|
-
units: 'GALLONS'
|
|
256
|
+
units: 'GALLONS',
|
|
262
257
|
},
|
|
263
258
|
{
|
|
264
259
|
request_id: 'month',
|
|
265
260
|
bucket: 'MON',
|
|
266
261
|
since_datetime: startOfCurrMonth,
|
|
267
262
|
operation: 'SUM',
|
|
268
|
-
units: 'GALLONS'
|
|
263
|
+
units: 'GALLONS',
|
|
269
264
|
},
|
|
270
265
|
{
|
|
271
266
|
request_id: 'prevMonth',
|
|
@@ -273,63 +268,63 @@ module.exports = class connectionHTTP {
|
|
|
273
268
|
since_datetime: startOfPrevMonth,
|
|
274
269
|
until_datetime: startOfCurrMonth,
|
|
275
270
|
operation: 'SUM',
|
|
276
|
-
units: 'GALLONS'
|
|
277
|
-
}
|
|
278
|
-
]
|
|
279
|
-
}
|
|
271
|
+
units: 'GALLONS',
|
|
272
|
+
},
|
|
273
|
+
],
|
|
274
|
+
};
|
|
280
275
|
|
|
281
276
|
// Send the request
|
|
282
277
|
const res = await axios.post(
|
|
283
|
-
|
|
278
|
+
`https://api.flumetech.com/users/${this.userId}/devices/${deviceId}/query`,
|
|
284
279
|
body,
|
|
285
280
|
{
|
|
286
281
|
headers: {
|
|
287
|
-
Authorization:
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
)
|
|
282
|
+
Authorization: `Bearer ${this.accessToken}`,
|
|
283
|
+
},
|
|
284
|
+
},
|
|
285
|
+
);
|
|
291
286
|
|
|
292
287
|
// Check to see we got a response
|
|
293
288
|
if (!res.data) {
|
|
294
|
-
throw new Error(
|
|
289
|
+
throw new Error(platformLang.noDataReceived);
|
|
295
290
|
}
|
|
296
291
|
|
|
297
292
|
// Log the response if in debug mode
|
|
298
293
|
if (this.debug) {
|
|
299
|
-
this.log('[HTTP getWaterInfo()] %s.', JSON.stringify(res.data))
|
|
294
|
+
this.log('[HTTP getWaterInfo()] %s.', JSON.stringify(res.data));
|
|
300
295
|
}
|
|
301
296
|
|
|
302
297
|
// Parse the response
|
|
303
|
-
return res.data.data[0]
|
|
298
|
+
return res.data.data[0];
|
|
304
299
|
}
|
|
305
300
|
|
|
306
|
-
async getLeakInfo
|
|
301
|
+
async getLeakInfo(deviceId) {
|
|
307
302
|
// Refresh the access token if it has expired already
|
|
308
303
|
if (Date.now() > this.expiresIn) {
|
|
309
|
-
await this.renewToken()
|
|
304
|
+
await this.renewToken();
|
|
310
305
|
}
|
|
311
306
|
|
|
312
307
|
// Send the request
|
|
313
308
|
const res = await axios.get(
|
|
314
|
-
|
|
309
|
+
`https://api.flumetech.com/users/${this.userId}/devices/${deviceId}/leaks/active`,
|
|
315
310
|
{
|
|
316
311
|
headers: {
|
|
317
|
-
Authorization:
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
)
|
|
312
|
+
Authorization: `Bearer ${this.accessToken}`,
|
|
313
|
+
},
|
|
314
|
+
},
|
|
315
|
+
);
|
|
321
316
|
|
|
322
317
|
// Check to see we got a response
|
|
323
318
|
if (!res.data) {
|
|
324
|
-
throw new Error(
|
|
319
|
+
throw new Error(platformLang.noDataReceived);
|
|
325
320
|
}
|
|
326
321
|
|
|
327
322
|
// Log the response if in debug mode
|
|
328
323
|
if (this.debug) {
|
|
329
|
-
this.log('[HTTP getLeakInfo()] %s.', JSON.stringify(res.data))
|
|
324
|
+
this.log('[HTTP getLeakInfo()] %s.', JSON.stringify(res.data));
|
|
330
325
|
}
|
|
331
326
|
|
|
332
327
|
// Parse the response
|
|
333
|
-
return res.data.data[0]
|
|
328
|
+
return res.data.data[0];
|
|
334
329
|
}
|
|
335
330
|
}
|
|
@@ -1,105 +1,100 @@
|
|
|
1
|
-
|
|
2
|
-
/* eslint-disable new-cap */
|
|
3
|
-
'use strict'
|
|
1
|
+
import platformFuncs from '../utils/functions.js';
|
|
4
2
|
|
|
5
|
-
|
|
6
|
-
constructor
|
|
3
|
+
export default class {
|
|
4
|
+
constructor(platform, accessory) {
|
|
7
5
|
// Set up variables from the platform
|
|
8
|
-
this.accessory = accessory
|
|
9
|
-
this.cusChar = platform.cusChar
|
|
10
|
-
this.
|
|
11
|
-
this.
|
|
12
|
-
this.
|
|
13
|
-
this.
|
|
14
|
-
this.
|
|
15
|
-
this.
|
|
16
|
-
this.
|
|
17
|
-
this.platform = platform
|
|
18
|
-
this.refreshInterval = platform.config.refreshInterval
|
|
6
|
+
this.accessory = accessory;
|
|
7
|
+
this.cusChar = platform.cusChar;
|
|
8
|
+
this.hapChar = platform.api.hap.Characteristic;
|
|
9
|
+
this.hapErr = platform.api.hap.HapStatusError;
|
|
10
|
+
this.hapServ = platform.api.hap.Service;
|
|
11
|
+
this.log = platform.config.disableDeviceLogging ? () => {} : platform.log;
|
|
12
|
+
this.name = accessory.displayName;
|
|
13
|
+
this.platform = platform;
|
|
14
|
+
this.refreshInterval = platform.config.refreshInterval;
|
|
19
15
|
|
|
20
16
|
// Add the leak sensor service if it doesn't exist already
|
|
21
|
-
this.leakService =
|
|
22
|
-
this.accessory.
|
|
23
|
-
this.accessory.addService(this.hapServ.LeakSensor)
|
|
17
|
+
this.leakService = this.accessory.getService(this.hapServ.LeakSensor)
|
|
18
|
+
|| this.accessory.addService(this.hapServ.LeakSensor);
|
|
24
19
|
|
|
25
|
-
this.cacheLeak = !!this.leakService.getCharacteristic(this.hapChar.LeakDetected).value
|
|
26
|
-
this.cacheBatt = !this.leakService.getCharacteristic(this.hapChar.StatusLowBattery).value
|
|
27
|
-
this.cacheStatus = !this.leakService.getCharacteristic(this.hapChar.StatusFault).value
|
|
20
|
+
this.cacheLeak = !!this.leakService.getCharacteristic(this.hapChar.LeakDetected).value;
|
|
21
|
+
this.cacheBatt = !this.leakService.getCharacteristic(this.hapChar.StatusLowBattery).value;
|
|
22
|
+
this.cacheStatus = !this.leakService.getCharacteristic(this.hapChar.StatusFault).value;
|
|
28
23
|
|
|
29
24
|
// Add the custom characteristics if they haven't been already
|
|
30
25
|
if (!this.leakService.testCharacteristic(this.cusChar.TodayUsage)) {
|
|
31
|
-
this.leakService.addCharacteristic(this.cusChar.TodayUsage)
|
|
26
|
+
this.leakService.addCharacteristic(this.cusChar.TodayUsage);
|
|
32
27
|
}
|
|
33
28
|
if (!this.leakService.testCharacteristic(this.cusChar.MonthUsage)) {
|
|
34
|
-
this.leakService.addCharacteristic(this.cusChar.MonthUsage)
|
|
29
|
+
this.leakService.addCharacteristic(this.cusChar.MonthUsage);
|
|
35
30
|
}
|
|
36
31
|
if (!this.leakService.testCharacteristic(this.cusChar.PrevMonthUsage)) {
|
|
37
|
-
this.leakService.addCharacteristic(this.cusChar.PrevMonthUsage)
|
|
32
|
+
this.leakService.addCharacteristic(this.cusChar.PrevMonthUsage);
|
|
38
33
|
}
|
|
39
34
|
}
|
|
40
35
|
|
|
41
|
-
externalUpdate
|
|
36
|
+
externalUpdate(params) {
|
|
42
37
|
// Check the data for leak detection
|
|
43
38
|
if (
|
|
44
|
-
|
|
45
|
-
params.leakInfo.active !== this.cacheLeak
|
|
39
|
+
platformFuncs.hasProperty(params.leakInfo, 'active')
|
|
40
|
+
&& params.leakInfo.active !== this.cacheLeak
|
|
46
41
|
) {
|
|
47
|
-
this.cacheLeak = params.leakInfo.active
|
|
48
|
-
this.leakService.updateCharacteristic(this.hapChar.LeakDetected, this.cacheLeak ? 1 : 0)
|
|
49
|
-
this.log('[%s] current leak status [%sdetected].', this.name, this.cacheLeak ? '' : 'not ')
|
|
42
|
+
this.cacheLeak = params.leakInfo.active;
|
|
43
|
+
this.leakService.updateCharacteristic(this.hapChar.LeakDetected, this.cacheLeak ? 1 : 0);
|
|
44
|
+
this.log('[%s] current leak status [%sdetected].', this.name, this.cacheLeak ? '' : 'not ');
|
|
50
45
|
}
|
|
51
46
|
|
|
52
47
|
// Check the data for battery level, cacheBatt is true for OK and false for LOW
|
|
53
48
|
if (
|
|
54
|
-
|
|
55
|
-
(params.devInfo.battery_level !== 'low') !== this.cacheBatt
|
|
49
|
+
platformFuncs.hasProperty(params.devInfo, 'battery_level')
|
|
50
|
+
&& (params.devInfo.battery_level !== 'low') !== this.cacheBatt
|
|
56
51
|
) {
|
|
57
|
-
this.cacheBatt = params.devInfo.battery_level !== 'low'
|
|
58
|
-
this.leakService.updateCharacteristic(this.hapChar.StatusLowBattery, this.cacheBatt ? 0 : 1)
|
|
59
|
-
this.log('[%s] current battery [%s].', this.name, this.cacheBatt ? 'ok' : 'low')
|
|
52
|
+
this.cacheBatt = params.devInfo.battery_level !== 'low';
|
|
53
|
+
this.leakService.updateCharacteristic(this.hapChar.StatusLowBattery, this.cacheBatt ? 0 : 1);
|
|
54
|
+
this.log('[%s] current battery [%s].', this.name, this.cacheBatt ? 'ok' : 'low');
|
|
60
55
|
}
|
|
61
56
|
|
|
62
57
|
// Check the data for connectivity, cacheStatus is true for OK and false for NOT CONNECTED
|
|
63
58
|
if (
|
|
64
|
-
|
|
65
|
-
params.devInfo.connected !== this.cacheStatus
|
|
59
|
+
platformFuncs.hasProperty(params.devInfo, 'connected')
|
|
60
|
+
&& params.devInfo.connected !== this.cacheStatus
|
|
66
61
|
) {
|
|
67
|
-
this.cacheStatus = params.devInfo.connected
|
|
68
|
-
this.leakService.updateCharacteristic(this.hapChar.StatusFault, this.cacheStatus ? 0 : 1)
|
|
69
|
-
this.log('[%s] current status [%sconnected].', this.name, this.cacheStatus ? '' : 'not ')
|
|
62
|
+
this.cacheStatus = params.devInfo.connected;
|
|
63
|
+
this.leakService.updateCharacteristic(this.hapChar.StatusFault, this.cacheStatus ? 0 : 1);
|
|
64
|
+
this.log('[%s] current status [%sconnected].', this.name, this.cacheStatus ? '' : 'not ');
|
|
70
65
|
}
|
|
71
66
|
|
|
72
67
|
// Water info
|
|
73
68
|
if (params.waterInfo) {
|
|
74
69
|
if (
|
|
75
|
-
params.waterInfo.today
|
|
76
|
-
params.waterInfo.today[0]
|
|
77
|
-
|
|
70
|
+
params.waterInfo.today
|
|
71
|
+
&& params.waterInfo.today[0]
|
|
72
|
+
&& platformFuncs.hasProperty(params.waterInfo.today[0], 'value')
|
|
78
73
|
) {
|
|
79
74
|
this.leakService.updateCharacteristic(
|
|
80
75
|
this.cusChar.TodayUsage,
|
|
81
|
-
params.waterInfo.today[0].value
|
|
82
|
-
)
|
|
76
|
+
params.waterInfo.today[0].value,
|
|
77
|
+
);
|
|
83
78
|
}
|
|
84
79
|
if (
|
|
85
|
-
params.waterInfo.month
|
|
86
|
-
params.waterInfo.month[0]
|
|
87
|
-
|
|
80
|
+
params.waterInfo.month
|
|
81
|
+
&& params.waterInfo.month[0]
|
|
82
|
+
&& platformFuncs.hasProperty(params.waterInfo.month[0], 'value')
|
|
88
83
|
) {
|
|
89
84
|
this.leakService.updateCharacteristic(
|
|
90
85
|
this.cusChar.MonthUsage,
|
|
91
|
-
params.waterInfo.month[0].value
|
|
92
|
-
)
|
|
86
|
+
params.waterInfo.month[0].value,
|
|
87
|
+
);
|
|
93
88
|
}
|
|
94
89
|
if (
|
|
95
|
-
params.waterInfo.prevMonth
|
|
96
|
-
params.waterInfo.prevMonth[0]
|
|
97
|
-
|
|
90
|
+
params.waterInfo.prevMonth
|
|
91
|
+
&& params.waterInfo.prevMonth[0]
|
|
92
|
+
&& platformFuncs.hasProperty(params.waterInfo.prevMonth[0], 'value')
|
|
98
93
|
) {
|
|
99
94
|
this.leakService.updateCharacteristic(
|
|
100
95
|
this.cusChar.PrevMonthUsage,
|
|
101
|
-
params.waterInfo.prevMonth[0].value
|
|
102
|
-
)
|
|
96
|
+
params.waterInfo.prevMonth[0].value,
|
|
97
|
+
);
|
|
103
98
|
}
|
|
104
99
|
}
|
|
105
100
|
}
|
|
@@ -1,14 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
/* eslint-disable new-cap */
|
|
3
|
-
'use strict'
|
|
4
|
-
|
|
5
|
-
const { HomebridgePluginUiServer } = require('@homebridge/plugin-ui-utils')
|
|
1
|
+
import { HomebridgePluginUiServer } from '@homebridge/plugin-ui-utils';
|
|
6
2
|
|
|
7
3
|
class PluginUiServer extends HomebridgePluginUiServer {
|
|
8
|
-
constructor
|
|
9
|
-
super()
|
|
10
|
-
this.ready()
|
|
4
|
+
constructor() {
|
|
5
|
+
super();
|
|
6
|
+
this.ready();
|
|
11
7
|
}
|
|
12
8
|
}
|
|
13
9
|
|
|
14
|
-
|
|
10
|
+
(() => new PluginUiServer())();
|