homebridge-flume 1.0.0 → 1.1.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 CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  All notable changes to homebridge-flume will be documented in this file.
4
4
 
5
+ ## 1.1.0 (2021-11-30)
6
+
7
+ ### Added
8
+
9
+ - Daily and monthly usage custom characteristics (viewable in HomeKit apps like Eve)
10
+
11
+ ### Removed
12
+
13
+ - `threshold` configuration option as unused
14
+
5
15
  ## 1.0.0 (2021-11-29)
6
16
 
7
17
  ### Added
@@ -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", "threshold", "disableDeviceLogging", "debug", "disablePlugin"]
76
+ "items": ["refreshInterval", "disableDeviceLogging", "debug", "disablePlugin"]
83
77
  }
84
78
  ]
85
79
  }
@@ -237,14 +237,23 @@ module.exports = class connectionHTTP {
237
237
  if (Date.now() > this.expiresIn) {
238
238
  await this.renewToken()
239
239
  }
240
+ const today = new Date().toISOString().substring(0, 10) + ' 00:00:00'
241
+ const month = today.substring(0, 8) + '01' + today.substring(10)
240
242
 
241
243
  // Generate the JSON data to send
242
244
  const body = {
243
245
  queries: [
244
246
  {
245
- request_id: 'currentusage',
246
- bucket: 'MIN',
247
- since_datetime: fromWhen,
247
+ request_id: 'today',
248
+ bucket: 'DAY',
249
+ since_datetime: today,
250
+ operation: 'SUM',
251
+ units: 'GALLONS'
252
+ },
253
+ {
254
+ request_id: 'month',
255
+ bucket: 'MON',
256
+ since_datetime: month,
248
257
  operation: 'SUM',
249
258
  units: 'GALLONS'
250
259
  }
@@ -2,12 +2,12 @@
2
2
  /* eslint-disable new-cap */
3
3
  'use strict'
4
4
 
5
- module.exports = class deviceValve {
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,14 @@ 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
+ }
28
36
  }
29
37
 
30
38
  externalUpdate (params) {
@@ -58,19 +66,28 @@ module.exports = class deviceValve {
58
66
  this.log('[%s] current status [%sconnected].', this.name, this.cacheStatus ? '' : 'not ')
59
67
  }
60
68
 
61
- const usage =
62
- params.waterInfo.currentusage &&
63
- params.waterInfo.currentusage[0] &&
64
- params.waterInfo.currentusage[0].value
65
- ? params.waterInfo.currentusage[0].value
66
- : 0
67
- if (usage > this.threshold) {
68
- this.log(
69
- '[%s] usage detected - [%s] gallons within the last [%s] minutes.',
70
- this.name,
71
- usage,
72
- this.refreshInterval
73
- )
69
+ // Water info
70
+ if (params.waterInfo) {
71
+ if (
72
+ params.waterInfo.today &&
73
+ params.waterInfo.today[0] &&
74
+ this.funcs.hasProperty(params.waterInfo.today[0], 'value')
75
+ ) {
76
+ this.leakService.updateCharacteristic(
77
+ this.cusChar.TodayUsage,
78
+ params.waterInfo.today[0].value
79
+ )
80
+ }
81
+ if (
82
+ params.waterInfo.month &&
83
+ params.waterInfo.month[0] &&
84
+ this.funcs.hasProperty(params.waterInfo.month[0], 'value')
85
+ ) {
86
+ this.leakService.updateCharacteristic(
87
+ this.cusChar.MonthUsage,
88
+ params.waterInfo.month[0].value
89
+ )
90
+ }
74
91
  }
75
92
  }
76
93
  }
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
- const since = this.lastSync
237
- .toISOString()
238
- .substring(0, 19)
239
- .replace('T', ' ')
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 = { since }
231
+ const toReturn = {}
243
232
  const devInfo = await this.httpClient.getDeviceInfo(accessory.context.deviceId)
244
233
  toReturn.devInfo = devInfo
245
- const waterInfo = await this.httpClient.getWaterInfo(accessory.context.deviceId, since)
246
- toReturn.waterInfo = waterInfo
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/valve'))(this, accessory)
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)
@@ -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,38 @@
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
+ }
13
+ const self = this
14
+ this.TodayUsage = function () {
15
+ self.hapChar.call(this, 'Today Usage', self.uuids.todayUsage)
16
+ this.setProps({
17
+ format: self.hapChar.Formats.UINT32,
18
+ perms: [self.hapChar.Perms.READ, self.hapChar.Perms.NOTIFY],
19
+ unit: 'Gallons'
20
+ })
21
+ this.value = this.getDefaultValue()
22
+ }
23
+ this.MonthUsage = function () {
24
+ self.hapChar.call(this, 'Month Usage', self.uuids.monthUsage)
25
+ this.setProps({
26
+ format: self.hapChar.Formats.UINT32,
27
+ perms: [self.hapChar.Perms.READ, self.hapChar.Perms.NOTIFY],
28
+ unit: 'Gallons'
29
+ })
30
+ this.value = this.getDefaultValue()
31
+ }
32
+ const inherits = require('util').inherits
33
+ inherits(this.TodayUsage, this.hapChar)
34
+ inherits(this.MonthUsage, this.hapChar)
35
+ this.TodayUsage.UUID = this.uuids.todayUsage
36
+ this.MonthUsage.UUID = this.uuids.monthUsage
37
+ }
38
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "homebridge-flume",
3
3
  "alias": "Flume",
4
- "version": "1.0.0",
4
+ "version": "1.1.0",
5
5
  "author": {
6
6
  "name": "Ben Potter",
7
7
  "email": "bwp91@icloud.com"