homebridge-flume 0.6.0 → 1.2.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/CHANGELOG.md +28 -0
- package/README.md +17 -13
- package/config.schema.json +2 -8
- package/lib/connection/http.js +62 -5
- package/lib/device/leak-sensor.js +106 -0
- package/lib/homebridge-ui/public/index.html +11 -0
- package/lib/index.js +16 -24
- package/lib/utils/constants.js +2 -5
- package/lib/utils/custom-chars.js +50 -0
- package/package.json +1 -1
- package/lib/device/valve.js +0 -52
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,34 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to homebridge-flume will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## 1.2.0 (2021-12-01)
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Previous month usage custom characteristic (viewable in HomeKit apps like Eve)
|
|
10
|
+
|
|
11
|
+
## 1.1.0 (2021-11-30)
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- Daily and monthly usage custom characteristics (viewable in HomeKit apps like Eve)
|
|
16
|
+
|
|
17
|
+
### Removed
|
|
18
|
+
|
|
19
|
+
- `threshold` configuration option as unused
|
|
20
|
+
|
|
21
|
+
## 1.0.0 (2021-11-29)
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
|
|
25
|
+
- Plugin logo
|
|
26
|
+
|
|
27
|
+
## 0.7.0 (2021-11-24)
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
|
|
31
|
+
- `StatusFault` and `StatusLowBattery` characteristics to the `LeakSensor` service
|
|
32
|
+
|
|
5
33
|
## 0.6.0 (2021-11-24)
|
|
6
34
|
|
|
7
35
|
### 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
|
@@ -202,19 +202,76 @@ module.exports = class connectionHTTP {
|
|
|
202
202
|
}
|
|
203
203
|
}
|
|
204
204
|
|
|
205
|
-
async getDeviceInfo (deviceId
|
|
205
|
+
async getDeviceInfo (deviceId) {
|
|
206
206
|
// Refresh the access token if it has expired already
|
|
207
207
|
if (Date.now() > this.expiresIn) {
|
|
208
208
|
await this.renewToken()
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
+
// Send the request
|
|
212
|
+
const res = await axios.get(
|
|
213
|
+
'https://api.flumetech.com/users/' + this.userId + '/devices/' + deviceId,
|
|
214
|
+
{
|
|
215
|
+
headers: {
|
|
216
|
+
Authorization: 'Bearer ' + this.accessToken
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
// Check to see we got a response
|
|
222
|
+
if (!res.data) {
|
|
223
|
+
throw new Error(this.lang.noDataReceived)
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Log the response if in debug mode
|
|
227
|
+
if (this.debug) {
|
|
228
|
+
this.log('[HTTP getDeviceInfo()] %s.', JSON.stringify(res.data))
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Parse the response
|
|
232
|
+
return res.data.data[0]
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
async getWaterInfo (deviceId, fromWhen) {
|
|
236
|
+
// Refresh the access token if it has expired already
|
|
237
|
+
if (Date.now() > this.expiresIn) {
|
|
238
|
+
await this.renewToken()
|
|
239
|
+
}
|
|
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
|
+
|
|
211
253
|
// Generate the JSON data to send
|
|
212
254
|
const body = {
|
|
213
255
|
queries: [
|
|
214
256
|
{
|
|
215
|
-
request_id: '
|
|
216
|
-
bucket: '
|
|
217
|
-
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,
|
|
218
275
|
operation: 'SUM',
|
|
219
276
|
units: 'GALLONS'
|
|
220
277
|
}
|
|
@@ -239,7 +296,7 @@ module.exports = class connectionHTTP {
|
|
|
239
296
|
|
|
240
297
|
// Log the response if in debug mode
|
|
241
298
|
if (this.debug) {
|
|
242
|
-
this.log('[HTTP
|
|
299
|
+
this.log('[HTTP getWaterInfo()] %s.', JSON.stringify(res.data))
|
|
243
300
|
}
|
|
244
301
|
|
|
245
302
|
// Parse the response
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/* jshint node: true, esversion: 10, -W014, -W033 */
|
|
2
|
+
/* eslint-disable new-cap */
|
|
3
|
+
'use strict'
|
|
4
|
+
|
|
5
|
+
module.exports = class deviceLeakSensor {
|
|
6
|
+
constructor (platform, accessory) {
|
|
7
|
+
// Set up variables from the platform
|
|
8
|
+
this.accessory = accessory
|
|
9
|
+
this.cusChar = platform.cusChar
|
|
10
|
+
this.funcs = platform.funcs
|
|
11
|
+
this.hapChar = platform.api.hap.Characteristic
|
|
12
|
+
this.hapErr = platform.api.hap.HapStatusError
|
|
13
|
+
this.hapServ = platform.api.hap.Service
|
|
14
|
+
this.lang = platform.lang
|
|
15
|
+
this.log = platform.config.disableDeviceLogging ? () => {} : platform.log
|
|
16
|
+
this.name = accessory.displayName
|
|
17
|
+
this.platform = platform
|
|
18
|
+
this.refreshInterval = platform.config.refreshInterval
|
|
19
|
+
|
|
20
|
+
// Add the leak sensor service if it doesn't exist already
|
|
21
|
+
this.leakService =
|
|
22
|
+
this.accessory.getService(this.hapServ.LeakSensor) ||
|
|
23
|
+
this.accessory.addService(this.hapServ.LeakSensor)
|
|
24
|
+
|
|
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
|
|
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
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
externalUpdate (params) {
|
|
42
|
+
// Check the data for leak detection
|
|
43
|
+
if (
|
|
44
|
+
this.funcs.hasProperty(params.leakInfo, 'active') &&
|
|
45
|
+
params.leakInfo.active !== this.cacheLeak
|
|
46
|
+
) {
|
|
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 ')
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Check the data for battery level, cacheBatt is true for OK and false for LOW
|
|
53
|
+
if (
|
|
54
|
+
this.funcs.hasProperty(params.devInfo, 'battery_level') &&
|
|
55
|
+
(params.devInfo.battery_level !== 'low') !== this.cacheBatt
|
|
56
|
+
) {
|
|
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')
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Check the data for connectivity, cacheStatus is true for OK and false for NOT CONNECTED
|
|
63
|
+
if (
|
|
64
|
+
this.funcs.hasProperty(params.devInfo, 'connected') &&
|
|
65
|
+
params.devInfo.connected !== this.cacheStatus
|
|
66
|
+
) {
|
|
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 ')
|
|
70
|
+
}
|
|
71
|
+
|
|
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
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
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,15 +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 = {
|
|
243
|
-
const devInfo = await this.httpClient.getDeviceInfo(accessory.context.deviceId
|
|
231
|
+
const toReturn = {}
|
|
232
|
+
const devInfo = await this.httpClient.getDeviceInfo(accessory.context.deviceId)
|
|
244
233
|
toReturn.devInfo = devInfo
|
|
234
|
+
if (this.counter === 0) {
|
|
235
|
+
const waterInfo = await this.httpClient.getWaterInfo(accessory.context.deviceId)
|
|
236
|
+
toReturn.waterInfo = waterInfo
|
|
237
|
+
}
|
|
245
238
|
const leakInfo = await this.httpClient.getLeakInfo(accessory.context.deviceId)
|
|
246
239
|
toReturn.leakInfo = leakInfo
|
|
247
240
|
accessory.control.externalUpdate(toReturn)
|
|
@@ -249,9 +242,8 @@ class FlumePlatform {
|
|
|
249
242
|
const eText = this.funcs.parseError(err)
|
|
250
243
|
this.log.warn('[%s] %s %s.', accessory.displayName, this.lang.devNotRef, eText)
|
|
251
244
|
}
|
|
245
|
+
this.counter++
|
|
252
246
|
})
|
|
253
|
-
|
|
254
|
-
this.lastSync = new Date()
|
|
255
247
|
} catch (err) {
|
|
256
248
|
// Catch any errors performing the sync
|
|
257
249
|
const eText = this.funcs.parseError(err, [])
|
|
@@ -287,7 +279,7 @@ class FlumePlatform {
|
|
|
287
279
|
}
|
|
288
280
|
|
|
289
281
|
// Create the instance for this device type
|
|
290
|
-
accessory.control = new (require('./device/
|
|
282
|
+
accessory.control = new (require('./device/leak-sensor'))(this, accessory)
|
|
291
283
|
|
|
292
284
|
// Log the device initialisation
|
|
293
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
package/lib/device/valve.js
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
/* jshint node: true, esversion: 10, -W014, -W033 */
|
|
2
|
-
/* eslint-disable new-cap */
|
|
3
|
-
'use strict'
|
|
4
|
-
|
|
5
|
-
module.exports = class deviceValve {
|
|
6
|
-
constructor (platform, accessory) {
|
|
7
|
-
// Set up variables from the platform
|
|
8
|
-
this.accessory = accessory
|
|
9
|
-
this.funcs = platform.funcs
|
|
10
|
-
this.threshold = platform.config.threshold
|
|
11
|
-
this.hapChar = platform.api.hap.Characteristic
|
|
12
|
-
this.hapErr = platform.api.hap.HapStatusError
|
|
13
|
-
this.hapServ = platform.api.hap.Service
|
|
14
|
-
this.lang = platform.lang
|
|
15
|
-
this.log = platform.config.disableDeviceLogging ? () => {} : platform.log
|
|
16
|
-
this.name = accessory.displayName
|
|
17
|
-
this.platform = platform
|
|
18
|
-
this.refreshInterval = platform.config.refreshInterval
|
|
19
|
-
|
|
20
|
-
// Add the leak sensor service if it doesn't exist already
|
|
21
|
-
this.leakService =
|
|
22
|
-
this.accessory.getService(this.hapServ.LeakSensor) ||
|
|
23
|
-
this.accessory.addService(this.hapServ.LeakSensor)
|
|
24
|
-
|
|
25
|
-
this.cacheLeak = !!this.leakService.getCharacteristic(this.hapChar.LeakDetected).value
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
externalUpdate (params) {
|
|
29
|
-
// Here we deal with the incoming data
|
|
30
|
-
if (
|
|
31
|
-
this.funcs.hasProperty(params.leakInfo, 'active') &&
|
|
32
|
-
params.leakInfo.active !== this.cacheLeak
|
|
33
|
-
) {
|
|
34
|
-
this.cacheLeak = params.leakInfo.active
|
|
35
|
-
this.leakService.updateCharacteristic(this.hapChar.LeakDetected, this.cacheLeak ? 1 : 0)
|
|
36
|
-
this.log('[%s] current leak status [%sdetected]', this.name, this.cacheLeak ? '' : 'not ')
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const usage =
|
|
40
|
-
params.currentusage && params.currentusage[0] && params.currentusage[0].value
|
|
41
|
-
? params.currentusage[0].value
|
|
42
|
-
: 0
|
|
43
|
-
if (usage > this.threshold) {
|
|
44
|
-
this.log(
|
|
45
|
-
'[%s] usage detected - [%s] gallons within the last [%s] minutes.',
|
|
46
|
-
this.name,
|
|
47
|
-
usage,
|
|
48
|
-
this.refreshInterval
|
|
49
|
-
)
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|