homebridge-flume 0.7.0 → 1.2.1
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/CHANGELOG.md +29 -0
- package/README.md +17 -13
- package/config.schema.json +2 -8
- package/lib/connection/http.js +30 -3
- package/lib/device/{valve.js → leak-sensor.js} +45 -15
- package/lib/homebridge-ui/public/index.html +11 -0
- package/lib/index.js +15 -25
- package/lib/utils/constants.js +2 -5
- package/lib/utils/custom-chars.js +50 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,35 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to homebridge-flume will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## 1.2.1 (2021-12-08)
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
|
|
9
|
+
- Bump `homebridge` recommended version to v1.3.8
|
|
10
|
+
- Bump `node` recommended versions to v14.18.2 or v16.13.1
|
|
11
|
+
|
|
12
|
+
## 1.2.0 (2021-12-01)
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- Previous month usage custom characteristic (viewable in HomeKit apps like Eve)
|
|
17
|
+
|
|
18
|
+
## 1.1.0 (2021-11-30)
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
|
|
22
|
+
- Daily and monthly usage custom characteristics (viewable in HomeKit apps like Eve)
|
|
23
|
+
|
|
24
|
+
### Removed
|
|
25
|
+
|
|
26
|
+
- `threshold` configuration option as unused
|
|
27
|
+
|
|
28
|
+
## 1.0.0 (2021-11-29)
|
|
29
|
+
|
|
30
|
+
### Added
|
|
31
|
+
|
|
32
|
+
- Plugin logo
|
|
33
|
+
|
|
5
34
|
## 0.7.0 (2021-11-24)
|
|
6
35
|
|
|
7
36
|
### Added
|
package/README.md
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://github.com/bwp91/homebridge-flume"><img src="https://user-images.githubusercontent.com/43026681/143831753-ed67cad2-909a-4337-9b18-dd8e65dfdf5e.png" width="600px"></a>
|
|
3
|
+
</p>
|
|
1
4
|
<span align="center">
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
5
|
+
|
|
6
|
+
# homebridge-flume
|
|
7
|
+
|
|
8
|
+
Homebridge plugin to integrate Flume devices into HomeKit
|
|
9
|
+
|
|
10
|
+
[](https://github.com/homebridge/homebridge/wiki/Verified-Plugins)
|
|
11
|
+
[](https://www.npmjs.com/package/homebridge-flume)
|
|
12
|
+
[](https://github.com/bwp91/homebridge-flume/wiki/Beta-Version)
|
|
13
|
+
[](https://www.npmjs.com/package/homebridge-flume)
|
|
14
|
+
[](https://standardjs.com)
|
|
15
|
+
[](https://discord.com/channels/784827113378676736/784827113378676739)
|
|
16
|
+
[](https://discord.com/channels/432663330281226270/742733745743855627)
|
|
17
|
+
|
|
15
18
|
</span>
|
|
16
19
|
|
|
17
20
|
### Plugin Information
|
|
@@ -41,6 +44,7 @@
|
|
|
41
44
|
### Credits
|
|
42
45
|
|
|
43
46
|
- This is a forked rewrite of the [homebridge-flume-water-sensor](https://www.npmjs.com/package/homebridge-flume-water-sensor) plugin by @weallknowwhoisatfaulthere.
|
|
47
|
+
- To the creator of the awesome plugin header logo: [Keryan Belahcene](https://www.instagram.com/keryan.me).
|
|
44
48
|
- To the creators/contributors of [Homebridge](https://homebridge.io) who make this plugin possible.
|
|
45
49
|
|
|
46
50
|
### Disclaimer
|
package/config.schema.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"singular": true,
|
|
5
5
|
"customUi": true,
|
|
6
6
|
"customUiPath": "./lib/homebridge-ui",
|
|
7
|
-
"headerDisplay": "<p align=\"center\">For help and support please visit our <a href=\"https://github.com/bwp91/homebridge-
|
|
7
|
+
"headerDisplay": "<p align=\"center\"><img width=\"60%\" src=\"https://user-images.githubusercontent.com/43026681/143831753-ed67cad2-909a-4337-9b18-dd8e65dfdf5e.png\"></p><p align=\"center\">For help and support please visit our <a href=\"https://github.com/bwp91/homebridge-thermobit/wiki\">GitHub Wiki</a>. We hope you find this plugin useful!</p>",
|
|
8
8
|
"schema": {
|
|
9
9
|
"type": "object",
|
|
10
10
|
"properties": {
|
|
@@ -45,12 +45,6 @@
|
|
|
45
45
|
"placeholder": 2,
|
|
46
46
|
"description": "Number of minutes between updates. Must be 2 or more."
|
|
47
47
|
},
|
|
48
|
-
"threshold": {
|
|
49
|
-
"title": "Threshold",
|
|
50
|
-
"type": "number",
|
|
51
|
-
"placeholder": 0,
|
|
52
|
-
"description": "Ignore a steady water draw below this value in gallons per refresh interval. Must be 0 or more."
|
|
53
|
-
},
|
|
54
48
|
"disableDeviceLogging": {
|
|
55
49
|
"type": "boolean",
|
|
56
50
|
"title": "Disable Device Logging",
|
|
@@ -79,7 +73,7 @@
|
|
|
79
73
|
"title": "Optional Settings",
|
|
80
74
|
"description": "Optional settings for the plugin, including global logging settings.",
|
|
81
75
|
"expandable": true,
|
|
82
|
-
"items": ["refreshInterval", "
|
|
76
|
+
"items": ["refreshInterval", "disableDeviceLogging", "debug", "disablePlugin"]
|
|
83
77
|
}
|
|
84
78
|
]
|
|
85
79
|
}
|
package/lib/connection/http.js
CHANGED
|
@@ -238,13 +238,40 @@ module.exports = class connectionHTTP {
|
|
|
238
238
|
await this.renewToken()
|
|
239
239
|
}
|
|
240
240
|
|
|
241
|
+
// Generate dates for the query data
|
|
242
|
+
const date = new Date()
|
|
243
|
+
const startOfToday = date.toISOString().substring(0, 10) + ' 00:00:00'
|
|
244
|
+
|
|
245
|
+
// Set the date to the first of the current month
|
|
246
|
+
date.setDate(1)
|
|
247
|
+
const startOfCurrMonth = date.toISOString().substring(0, 10) + ' 00:00:00'
|
|
248
|
+
|
|
249
|
+
// Set the month to the previous month
|
|
250
|
+
date.setMonth(date.getMonth() - 1)
|
|
251
|
+
const startOfPrevMonth = date.toISOString().substring(0, 10) + ' 00:00:00'
|
|
252
|
+
|
|
241
253
|
// Generate the JSON data to send
|
|
242
254
|
const body = {
|
|
243
255
|
queries: [
|
|
244
256
|
{
|
|
245
|
-
request_id: '
|
|
246
|
-
bucket: '
|
|
247
|
-
since_datetime:
|
|
257
|
+
request_id: 'today',
|
|
258
|
+
bucket: 'DAY',
|
|
259
|
+
since_datetime: startOfToday,
|
|
260
|
+
operation: 'SUM',
|
|
261
|
+
units: 'GALLONS'
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
request_id: 'month',
|
|
265
|
+
bucket: 'MON',
|
|
266
|
+
since_datetime: startOfCurrMonth,
|
|
267
|
+
operation: 'SUM',
|
|
268
|
+
units: 'GALLONS'
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
request_id: 'prevMonth',
|
|
272
|
+
bucket: 'MON',
|
|
273
|
+
since_datetime: startOfPrevMonth,
|
|
274
|
+
until_datetime: startOfCurrMonth,
|
|
248
275
|
operation: 'SUM',
|
|
249
276
|
units: 'GALLONS'
|
|
250
277
|
}
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
/* eslint-disable new-cap */
|
|
3
3
|
'use strict'
|
|
4
4
|
|
|
5
|
-
module.exports = class
|
|
5
|
+
module.exports = class deviceLeakSensor {
|
|
6
6
|
constructor (platform, accessory) {
|
|
7
7
|
// Set up variables from the platform
|
|
8
8
|
this.accessory = accessory
|
|
9
|
+
this.cusChar = platform.cusChar
|
|
9
10
|
this.funcs = platform.funcs
|
|
10
|
-
this.threshold = platform.config.threshold
|
|
11
11
|
this.hapChar = platform.api.hap.Characteristic
|
|
12
12
|
this.hapErr = platform.api.hap.HapStatusError
|
|
13
13
|
this.hapServ = platform.api.hap.Service
|
|
@@ -25,6 +25,17 @@ module.exports = class deviceValve {
|
|
|
25
25
|
this.cacheLeak = !!this.leakService.getCharacteristic(this.hapChar.LeakDetected).value
|
|
26
26
|
this.cacheBatt = !this.leakService.getCharacteristic(this.hapChar.StatusLowBattery).value
|
|
27
27
|
this.cacheStatus = !this.leakService.getCharacteristic(this.hapChar.StatusFault).value
|
|
28
|
+
|
|
29
|
+
// Add the custom characteristics if they haven't been already
|
|
30
|
+
if (!this.leakService.testCharacteristic(this.cusChar.TodayUsage)) {
|
|
31
|
+
this.leakService.addCharacteristic(this.cusChar.TodayUsage)
|
|
32
|
+
}
|
|
33
|
+
if (!this.leakService.testCharacteristic(this.cusChar.MonthUsage)) {
|
|
34
|
+
this.leakService.addCharacteristic(this.cusChar.MonthUsage)
|
|
35
|
+
}
|
|
36
|
+
if (!this.leakService.testCharacteristic(this.cusChar.PrevMonthUsage)) {
|
|
37
|
+
this.leakService.addCharacteristic(this.cusChar.PrevMonthUsage)
|
|
38
|
+
}
|
|
28
39
|
}
|
|
29
40
|
|
|
30
41
|
externalUpdate (params) {
|
|
@@ -58,19 +69,38 @@ module.exports = class deviceValve {
|
|
|
58
69
|
this.log('[%s] current status [%sconnected].', this.name, this.cacheStatus ? '' : 'not ')
|
|
59
70
|
}
|
|
60
71
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
// Water info
|
|
73
|
+
if (params.waterInfo) {
|
|
74
|
+
if (
|
|
75
|
+
params.waterInfo.today &&
|
|
76
|
+
params.waterInfo.today[0] &&
|
|
77
|
+
this.funcs.hasProperty(params.waterInfo.today[0], 'value')
|
|
78
|
+
) {
|
|
79
|
+
this.leakService.updateCharacteristic(
|
|
80
|
+
this.cusChar.TodayUsage,
|
|
81
|
+
params.waterInfo.today[0].value
|
|
82
|
+
)
|
|
83
|
+
}
|
|
84
|
+
if (
|
|
85
|
+
params.waterInfo.month &&
|
|
86
|
+
params.waterInfo.month[0] &&
|
|
87
|
+
this.funcs.hasProperty(params.waterInfo.month[0], 'value')
|
|
88
|
+
) {
|
|
89
|
+
this.leakService.updateCharacteristic(
|
|
90
|
+
this.cusChar.MonthUsage,
|
|
91
|
+
params.waterInfo.month[0].value
|
|
92
|
+
)
|
|
93
|
+
}
|
|
94
|
+
if (
|
|
95
|
+
params.waterInfo.prevMonth &&
|
|
96
|
+
params.waterInfo.prevMonth[0] &&
|
|
97
|
+
this.funcs.hasProperty(params.waterInfo.prevMonth[0], 'value')
|
|
98
|
+
) {
|
|
99
|
+
this.leakService.updateCharacteristic(
|
|
100
|
+
this.cusChar.PrevMonthUsage,
|
|
101
|
+
params.waterInfo.prevMonth[0].value
|
|
102
|
+
)
|
|
103
|
+
}
|
|
74
104
|
}
|
|
75
105
|
}
|
|
76
106
|
}
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
<p class="text-center">
|
|
2
|
+
<img
|
|
3
|
+
src="https://user-images.githubusercontent.com/43026681/143831753-ed67cad2-909a-4337-9b18-dd8e65dfdf5e.png"
|
|
4
|
+
alt="homebridge-flume logo"
|
|
5
|
+
style="width: 60%;"
|
|
6
|
+
/>
|
|
7
|
+
</p>
|
|
1
8
|
<div id="pageIntro" class="text-center" style="display: none;">
|
|
2
9
|
<p class="lead">Thank you for installing <strong>homebridge-flume</strong></p>
|
|
3
10
|
<p>
|
|
@@ -83,6 +90,10 @@
|
|
|
83
90
|
>
|
|
84
91
|
plugin by @weallknowwhoisatfaulthere
|
|
85
92
|
</li>
|
|
93
|
+
<li>
|
|
94
|
+
To the creator of the awesome plugin header logo:
|
|
95
|
+
<a href="https://www.instagram.com/keryan.me" target="_blank">Keryan Belahcene</a>.
|
|
96
|
+
</li>
|
|
86
97
|
<li>
|
|
87
98
|
To the creators/contributors of
|
|
88
99
|
<a href="https://homebridge.io" target="_blank">Homebridge</a> who make this plugin possible.
|
package/lib/index.js
CHANGED
|
@@ -106,18 +106,6 @@ class FlumePlatform {
|
|
|
106
106
|
}
|
|
107
107
|
this.config[key] = val === 'false' ? false : !!val
|
|
108
108
|
break
|
|
109
|
-
case 'threshold': {
|
|
110
|
-
if (typeof v === 'string') {
|
|
111
|
-
logQuotes(key)
|
|
112
|
-
}
|
|
113
|
-
const numVal = Number(val)
|
|
114
|
-
if (isNaN(numVal)) {
|
|
115
|
-
logIgnore(key)
|
|
116
|
-
} else {
|
|
117
|
-
this.config[key] = numVal
|
|
118
|
-
}
|
|
119
|
-
break
|
|
120
|
-
}
|
|
121
109
|
case 'name':
|
|
122
110
|
case 'platform':
|
|
123
111
|
case 'plugin_map':
|
|
@@ -167,6 +155,9 @@ class FlumePlatform {
|
|
|
167
155
|
throw new Error(this.lang.noCreds)
|
|
168
156
|
}
|
|
169
157
|
|
|
158
|
+
// Require any libraries that the accessory instances use
|
|
159
|
+
this.cusChar = new (require('./utils/custom-chars'))(this.api)
|
|
160
|
+
|
|
170
161
|
// Setup the HTTP client if Thermobit username and password have been provided
|
|
171
162
|
this.httpClient = new (require('./connection/http'))(this)
|
|
172
163
|
await this.httpClient.obtainToken()
|
|
@@ -193,10 +184,8 @@ class FlumePlatform {
|
|
|
193
184
|
}
|
|
194
185
|
})
|
|
195
186
|
|
|
196
|
-
// Set up an initial last sync time
|
|
197
|
-
this.lastSync = new Date(Date.now() - this.config.refreshInterval * 60000)
|
|
198
|
-
|
|
199
187
|
// Perform a first sync and setup the refresh interval
|
|
188
|
+
this.counter = 0
|
|
200
189
|
this.flumeSync()
|
|
201
190
|
this.refreshInterval = setInterval(
|
|
202
191
|
() => this.flumeSync(),
|
|
@@ -233,17 +222,19 @@ class FlumePlatform {
|
|
|
233
222
|
|
|
234
223
|
async flumeSync () {
|
|
235
224
|
try {
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
.
|
|
239
|
-
|
|
225
|
+
// Reset the counter for water info once we reach 10
|
|
226
|
+
if (this.counter === 10) {
|
|
227
|
+
this.counter = 0
|
|
228
|
+
}
|
|
240
229
|
this.devicesInHB.forEach(async accessory => {
|
|
241
230
|
try {
|
|
242
|
-
const toReturn = {
|
|
231
|
+
const toReturn = {}
|
|
243
232
|
const devInfo = await this.httpClient.getDeviceInfo(accessory.context.deviceId)
|
|
244
233
|
toReturn.devInfo = devInfo
|
|
245
|
-
|
|
246
|
-
|
|
234
|
+
if (this.counter === 0) {
|
|
235
|
+
const waterInfo = await this.httpClient.getWaterInfo(accessory.context.deviceId)
|
|
236
|
+
toReturn.waterInfo = waterInfo
|
|
237
|
+
}
|
|
247
238
|
const leakInfo = await this.httpClient.getLeakInfo(accessory.context.deviceId)
|
|
248
239
|
toReturn.leakInfo = leakInfo
|
|
249
240
|
accessory.control.externalUpdate(toReturn)
|
|
@@ -251,9 +242,8 @@ class FlumePlatform {
|
|
|
251
242
|
const eText = this.funcs.parseError(err)
|
|
252
243
|
this.log.warn('[%s] %s %s.', accessory.displayName, this.lang.devNotRef, eText)
|
|
253
244
|
}
|
|
245
|
+
this.counter++
|
|
254
246
|
})
|
|
255
|
-
|
|
256
|
-
this.lastSync = new Date()
|
|
257
247
|
} catch (err) {
|
|
258
248
|
// Catch any errors performing the sync
|
|
259
249
|
const eText = this.funcs.parseError(err, [])
|
|
@@ -289,7 +279,7 @@ class FlumePlatform {
|
|
|
289
279
|
}
|
|
290
280
|
|
|
291
281
|
// Create the instance for this device type
|
|
292
|
-
accessory.control = new (require('./device/
|
|
282
|
+
accessory.control = new (require('./device/leak-sensor'))(this, accessory)
|
|
293
283
|
|
|
294
284
|
// Log the device initialisation
|
|
295
285
|
this.log('[%s] %s [%s].', accessory.displayName, this.lang.devInit, device.id)
|
package/lib/utils/constants.js
CHANGED
|
@@ -10,7 +10,6 @@ module.exports = {
|
|
|
10
10
|
clientId: '',
|
|
11
11
|
clientSecret: '',
|
|
12
12
|
refreshInterval: 1,
|
|
13
|
-
threshold: 0,
|
|
14
13
|
disableDeviceLogging: false,
|
|
15
14
|
debug: false,
|
|
16
15
|
disablePlugin: false,
|
|
@@ -18,13 +17,11 @@ module.exports = {
|
|
|
18
17
|
},
|
|
19
18
|
|
|
20
19
|
defaultValues: {
|
|
21
|
-
refreshInterval: 2
|
|
22
|
-
threshold: 0
|
|
20
|
+
refreshInterval: 2
|
|
23
21
|
},
|
|
24
22
|
|
|
25
23
|
minValues: {
|
|
26
|
-
refreshInterval: 2
|
|
27
|
-
threshold: 0
|
|
24
|
+
refreshInterval: 2
|
|
28
25
|
},
|
|
29
26
|
|
|
30
27
|
httpRetryCodes: ['ENOTFOUND', 'ETIMEDOUT', 'EAI_AGAIN', 'ECONNABORTED']
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/* jshint node: true, esversion: 10, -W014, -W033 */
|
|
2
|
+
/* eslint-disable new-cap */
|
|
3
|
+
'use strict'
|
|
4
|
+
|
|
5
|
+
module.exports = class customCharacteristics {
|
|
6
|
+
constructor (api) {
|
|
7
|
+
this.hapServ = api.hap.Service
|
|
8
|
+
this.hapChar = api.hap.Characteristic
|
|
9
|
+
this.uuids = {
|
|
10
|
+
todayUsage: 'E966F001-079E-48FF-8F27-9C2605A29F52',
|
|
11
|
+
monthUsage: 'E966F002-079E-48FF-8F27-9C2605A29F52',
|
|
12
|
+
prevMonthUsage: 'E966F003-079E-48FF-8F27-9C2605A29F52'
|
|
13
|
+
}
|
|
14
|
+
const self = this
|
|
15
|
+
this.TodayUsage = function () {
|
|
16
|
+
self.hapChar.call(this, 'Today Usage', self.uuids.todayUsage)
|
|
17
|
+
this.setProps({
|
|
18
|
+
format: self.hapChar.Formats.UINT32,
|
|
19
|
+
perms: [self.hapChar.Perms.READ, self.hapChar.Perms.NOTIFY],
|
|
20
|
+
unit: 'Gallons'
|
|
21
|
+
})
|
|
22
|
+
this.value = this.getDefaultValue()
|
|
23
|
+
}
|
|
24
|
+
this.MonthUsage = function () {
|
|
25
|
+
self.hapChar.call(this, 'Month Usage', self.uuids.monthUsage)
|
|
26
|
+
this.setProps({
|
|
27
|
+
format: self.hapChar.Formats.UINT32,
|
|
28
|
+
perms: [self.hapChar.Perms.READ, self.hapChar.Perms.NOTIFY],
|
|
29
|
+
unit: 'Gallons'
|
|
30
|
+
})
|
|
31
|
+
this.value = this.getDefaultValue()
|
|
32
|
+
}
|
|
33
|
+
this.PrevMonthUsage = function () {
|
|
34
|
+
self.hapChar.call(this, 'Previous Month', self.uuids.prevMonthUsage)
|
|
35
|
+
this.setProps({
|
|
36
|
+
format: self.hapChar.Formats.UINT32,
|
|
37
|
+
perms: [self.hapChar.Perms.READ, self.hapChar.Perms.NOTIFY],
|
|
38
|
+
unit: 'Gallons'
|
|
39
|
+
})
|
|
40
|
+
this.value = this.getDefaultValue()
|
|
41
|
+
}
|
|
42
|
+
const inherits = require('util').inherits
|
|
43
|
+
inherits(this.TodayUsage, this.hapChar)
|
|
44
|
+
inherits(this.MonthUsage, this.hapChar)
|
|
45
|
+
inherits(this.PrevMonthUsage, this.hapChar)
|
|
46
|
+
this.TodayUsage.UUID = this.uuids.todayUsage
|
|
47
|
+
this.MonthUsage.UUID = this.uuids.monthUsage
|
|
48
|
+
this.PrevMonthUsage.UUID = this.uuids.prevMonthUsage
|
|
49
|
+
}
|
|
50
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "homebridge-flume",
|
|
3
3
|
"alias": "Flume",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "1.2.1",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Ben Potter",
|
|
7
7
|
"email": "bwp91@icloud.com"
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
],
|
|
25
25
|
"engines": {
|
|
26
26
|
"homebridge": "^1.3.8",
|
|
27
|
-
"node": "^14.18.
|
|
27
|
+
"node": "^14.18.2 || ^16.13.1"
|
|
28
28
|
},
|
|
29
29
|
"repository": {
|
|
30
30
|
"type": "git",
|