@switchbot/homebridge-switchbot 2.0.0-beta.19 → 2.0.0-beta.20

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.
Files changed (112) hide show
  1. package/CHANGELOG.md +6 -1
  2. package/README.md +1 -2
  3. package/config.schema.json +51 -32
  4. package/dist/device/bot.d.ts +32 -29
  5. package/dist/device/bot.d.ts.map +1 -1
  6. package/dist/device/bot.js +549 -575
  7. package/dist/device/bot.js.map +1 -1
  8. package/dist/device/colorbulb.d.ts +33 -15
  9. package/dist/device/colorbulb.d.ts.map +1 -1
  10. package/dist/device/colorbulb.js +426 -341
  11. package/dist/device/colorbulb.js.map +1 -1
  12. package/dist/device/contact.d.ts +16 -9
  13. package/dist/device/contact.d.ts.map +1 -1
  14. package/dist/device/contact.js +246 -208
  15. package/dist/device/contact.js.map +1 -1
  16. package/dist/device/curtain.d.ts +21 -18
  17. package/dist/device/curtain.d.ts.map +1 -1
  18. package/dist/device/curtain.js +449 -449
  19. package/dist/device/curtain.js.map +1 -1
  20. package/dist/device/humidifier.d.ts +22 -20
  21. package/dist/device/humidifier.d.ts.map +1 -1
  22. package/dist/device/humidifier.js +346 -324
  23. package/dist/device/humidifier.js.map +1 -1
  24. package/dist/device/lock.d.ts +22 -10
  25. package/dist/device/lock.d.ts.map +1 -1
  26. package/dist/device/lock.js +257 -178
  27. package/dist/device/lock.js.map +1 -1
  28. package/dist/device/meter.d.ts +21 -14
  29. package/dist/device/meter.d.ts.map +1 -1
  30. package/dist/device/meter.js +287 -239
  31. package/dist/device/meter.js.map +1 -1
  32. package/dist/device/meterplus.d.ts +23 -10
  33. package/dist/device/meterplus.d.ts.map +1 -1
  34. package/dist/device/meterplus.js +308 -190
  35. package/dist/device/meterplus.js.map +1 -1
  36. package/dist/device/motion.d.ts +17 -10
  37. package/dist/device/motion.d.ts.map +1 -1
  38. package/dist/device/motion.js +225 -193
  39. package/dist/device/motion.js.map +1 -1
  40. package/dist/device/plug.d.ts +24 -17
  41. package/dist/device/plug.d.ts.map +1 -1
  42. package/dist/device/plug.js +270 -267
  43. package/dist/device/plug.js.map +1 -1
  44. package/dist/device/striplight.d.ts +36 -14
  45. package/dist/device/striplight.d.ts.map +1 -1
  46. package/dist/device/striplight.js +447 -299
  47. package/dist/device/striplight.js.map +1 -1
  48. package/dist/irdevice/airconditioner.d.ts +7 -14
  49. package/dist/irdevice/airconditioner.d.ts.map +1 -1
  50. package/dist/irdevice/airconditioner.js +177 -169
  51. package/dist/irdevice/airconditioner.js.map +1 -1
  52. package/dist/irdevice/airpurifier.d.ts +3 -5
  53. package/dist/irdevice/airpurifier.d.ts.map +1 -1
  54. package/dist/irdevice/airpurifier.js +72 -57
  55. package/dist/irdevice/airpurifier.js.map +1 -1
  56. package/dist/irdevice/camera.d.ts +3 -4
  57. package/dist/irdevice/camera.d.ts.map +1 -1
  58. package/dist/irdevice/camera.js +47 -33
  59. package/dist/irdevice/camera.js.map +1 -1
  60. package/dist/irdevice/fan.d.ts +3 -4
  61. package/dist/irdevice/fan.d.ts.map +1 -1
  62. package/dist/irdevice/fan.js +66 -48
  63. package/dist/irdevice/fan.js.map +1 -1
  64. package/dist/irdevice/light.d.ts +3 -4
  65. package/dist/irdevice/light.d.ts.map +1 -1
  66. package/dist/irdevice/light.js +48 -47
  67. package/dist/irdevice/light.js.map +1 -1
  68. package/dist/irdevice/other.d.ts +3 -4
  69. package/dist/irdevice/other.d.ts.map +1 -1
  70. package/dist/irdevice/other.js +47 -33
  71. package/dist/irdevice/other.js.map +1 -1
  72. package/dist/irdevice/tv.d.ts +10 -11
  73. package/dist/irdevice/tv.d.ts.map +1 -1
  74. package/dist/irdevice/tv.js +64 -48
  75. package/dist/irdevice/tv.js.map +1 -1
  76. package/dist/irdevice/vacuumcleaner.d.ts +7 -12
  77. package/dist/irdevice/vacuumcleaner.d.ts.map +1 -1
  78. package/dist/irdevice/vacuumcleaner.js +52 -41
  79. package/dist/irdevice/vacuumcleaner.js.map +1 -1
  80. package/dist/irdevice/waterheater.d.ts +6 -11
  81. package/dist/irdevice/waterheater.d.ts.map +1 -1
  82. package/dist/irdevice/waterheater.js +52 -42
  83. package/dist/irdevice/waterheater.js.map +1 -1
  84. package/dist/platform.d.ts +0 -4
  85. package/dist/platform.d.ts.map +1 -1
  86. package/dist/platform.js +44 -66
  87. package/dist/platform.js.map +1 -1
  88. package/dist/settings.d.ts +3 -3
  89. package/dist/settings.d.ts.map +1 -1
  90. package/package.json +7 -6
  91. package/src/device/bot.ts +551 -589
  92. package/src/device/colorbulb.ts +441 -375
  93. package/src/device/contact.ts +249 -213
  94. package/src/device/curtain.ts +452 -461
  95. package/src/device/humidifier.ts +358 -365
  96. package/src/device/lock.ts +263 -179
  97. package/src/device/meter.ts +302 -253
  98. package/src/device/meterplus.ts +319 -194
  99. package/src/device/motion.ts +230 -199
  100. package/src/device/plug.ts +273 -274
  101. package/src/device/striplight.ts +460 -316
  102. package/src/irdevice/airconditioner.ts +181 -183
  103. package/src/irdevice/airpurifier.ts +70 -60
  104. package/src/irdevice/camera.ts +46 -36
  105. package/src/irdevice/fan.ts +64 -49
  106. package/src/irdevice/light.ts +47 -51
  107. package/src/irdevice/other.ts +46 -36
  108. package/src/irdevice/tv.ts +64 -51
  109. package/src/irdevice/vacuumcleaner.ts +52 -45
  110. package/src/irdevice/waterheater.ts +50 -45
  111. package/src/platform.ts +44 -68
  112. package/src/settings.ts +3 -3
@@ -6,6 +6,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.MeterPlus = void 0;
7
7
  const https_1 = __importDefault(require("https"));
8
8
  const crypto_1 = __importDefault(require("crypto"));
9
+ const os_1 = require("os");
10
+ const async_mqtt_1 = require("async-mqtt");
9
11
  const rxjs_1 = require("rxjs");
10
12
  const operators_1 = require("rxjs/operators");
11
13
  const super_stringify_1 = __importDefault(require("super-stringify"));
@@ -20,24 +22,19 @@ class MeterPlus {
20
22
  this.platform = platform;
21
23
  this.accessory = accessory;
22
24
  this.device = device;
25
+ //MQTT stuff
26
+ this.mqttClient = null;
27
+ // Connection
28
+ this.BLE = (this.device.connectionType === 'BLE' || this.device.connectionType === 'Both');
29
+ this.OpenAPI = (this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'Both');
23
30
  // default placeholders
24
31
  this.logs(device);
25
- this.openAPI();
26
32
  this.scan(device);
27
33
  this.refreshRate(device);
28
34
  this.config(device);
29
- if (this.CurrentRelativeHumidity === undefined) {
30
- this.CurrentRelativeHumidity = 0;
31
- }
32
- else {
33
- this.CurrentRelativeHumidity = this.accessory.context.CurrentRelativeHumidity;
34
- }
35
- if (this.CurrentTemperature === undefined) {
36
- this.CurrentTemperature = 0;
37
- }
38
- else {
39
- this.CurrentTemperature = this.accessory.context.CurrentTemperature;
40
- }
35
+ this.context();
36
+ this.setupHistoryService(device);
37
+ this.setupMqtt(device);
41
38
  // this is subject we use to track when we need to POST changes to the SwitchBot API
42
39
  this.doMeterUpdate = new rxjs_1.Subject();
43
40
  this.meterUpdateInProgress = false;
@@ -105,12 +102,12 @@ class MeterPlus {
105
102
  this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Humidity Sensor Service Not Added`);
106
103
  }
107
104
  // Battery Service
108
- if (!device.ble) {
105
+ if (!this.BLE) {
109
106
  this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Removing Battery Service`);
110
107
  this.batteryService = this.accessory.getService(this.platform.Service.Battery);
111
108
  accessory.removeService(this.batteryService);
112
109
  }
113
- else if (device.ble && !this.batteryService) {
110
+ else if (this.BLE && !this.batteryService) {
114
111
  this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Add Battery Service`);
115
112
  (this.batteryService = this.accessory.getService(this.platform.Service.Battery) || this.accessory.addService(this.platform.Service.Battery)),
116
113
  `${accessory.displayName} Battery`;
@@ -133,15 +130,20 @@ class MeterPlus {
133
130
  * Parse the device status from the SwitchBot api
134
131
  */
135
132
  async parseStatus() {
136
- if (this.SwitchToOpenAPI || !this.device.ble) {
133
+ if (this.BLE && !this.SwitchToOpenAPI) {
134
+ await this.BLEparseStatus();
135
+ }
136
+ else if (this.OpenAPI && this.platform.config.credentials?.token) {
137
+ this.SwitchToOpenAPI = false;
137
138
  await this.openAPIparseStatus();
138
139
  }
139
140
  else {
140
- await this.BLEparseStatus();
141
+ this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:`
142
+ + ` ${this.device.connectionType}, parseStatus will not happen.`);
141
143
  }
142
144
  }
143
145
  async BLEparseStatus() {
144
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLE parseStatus`);
146
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEparseStatus`);
145
147
  // Battery
146
148
  this.BatteryLevel = Number(this.battery);
147
149
  if (this.BatteryLevel < 15) {
@@ -164,36 +166,35 @@ class MeterPlus {
164
166
  }
165
167
  }
166
168
  async openAPIparseStatus() {
167
- if (this.device.ble) {
168
- this.SwitchToOpenAPI = false;
169
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIparseStatus`);
170
+ // Current Relative Humidity
171
+ if (!this.device.meter?.hide_humidity) {
172
+ this.CurrentRelativeHumidity = this.Humidity;
173
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Humidity: ${this.CurrentRelativeHumidity}%`);
169
174
  }
170
- if (this.platform.config.credentials?.token) {
171
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} OpenAPI parseStatus`);
172
- // Current Relative Humidity
173
- if (!this.device.meter?.hide_humidity) {
174
- this.CurrentRelativeHumidity = this.Humidity;
175
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Humidity: ${this.CurrentRelativeHumidity}%`);
176
- }
177
- // Current Temperature
178
- if (!this.device.meter?.hide_temperature) {
179
- this.CurrentTemperature = this.Temperature;
180
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Temperature: ${this.CurrentTemperature}°c`);
181
- }
175
+ // Current Temperature
176
+ if (!this.device.meter?.hide_temperature) {
177
+ this.CurrentTemperature = this.Temperature;
178
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Temperature: ${this.CurrentTemperature}°c`);
182
179
  }
183
180
  }
184
181
  /**
185
182
  * Asks the SwitchBot API for the latest device information
186
183
  */
187
184
  async refreshStatus() {
188
- if (this.device.ble) {
189
- this.BLErefreshStatus();
185
+ if (this.BLE) {
186
+ await this.BLERefreshStatus();
187
+ }
188
+ else if (this.OpenAPI && this.platform.config.credentials?.token) {
189
+ await this.openAPIRefreshStatus();
190
190
  }
191
191
  else {
192
- this.openAPIRefreshStatus();
192
+ this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:`
193
+ + ` ${this.device.connectionType}, refreshStatus will not happen.`);
193
194
  }
194
195
  }
195
- async BLErefreshStatus() {
196
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLE RefreshStatus`);
196
+ async BLERefreshStatus() {
197
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLERefreshStatus`);
197
198
  const switchbot = await this.platform.connectBLE();
198
199
  // Convert to BLE Address
199
200
  this.device.bleMac = this.device
@@ -219,9 +220,12 @@ class MeterPlus {
219
220
  this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} BLE Address Found: ${this.address}`);
220
221
  this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Config BLE Address: ${this.device.bleMac}`);
221
222
  }
223
+ if (ad.serviceData.humidity > 0) {
224
+ // reject unreliable data
225
+ this.humidity = ad.serviceData.humidity;
226
+ }
222
227
  this.serviceData = ad.serviceData;
223
228
  this.temperature = ad.serviceData.temperature.c;
224
- this.humidity = ad.serviceData.humidity;
225
229
  this.battery = ad.serviceData.battery;
226
230
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} serviceData: ${(0, super_stringify_1.default)(ad.serviceData)}`);
227
231
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} model: ${ad.serviceData.model}, modelName: ${ad.serviceData.modelName}, ` +
@@ -251,122 +255,87 @@ class MeterPlus {
251
255
  }
252
256
  })
253
257
  .catch(async (e) => {
254
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed refreshStatus with BLE Connection`);
255
- if (this.deviceLogging.includes('debug')) {
256
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed refreshStatus with BLE Connection,`
257
- + ` Error Message: ${(0, super_stringify_1.default)(e.message)}`);
258
- }
259
- if (this.platform.config.credentials?.token) {
260
- this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Using OpenAPI Connection`);
261
- this.SwitchToOpenAPI = true;
262
- this.openAPIRefreshStatus();
263
- }
264
258
  this.apiError(e);
259
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLERefreshStatus with ${this.device.connectionType}`
260
+ + ` Connection, Error Message: ${(0, super_stringify_1.default)(e.message)}`);
261
+ await this.BLEconnection(switchbot);
265
262
  });
266
263
  }
267
264
  else {
268
265
  await this.BLEconnection(switchbot);
269
266
  }
270
267
  }
271
- async getCustomBLEAddress(switchbot) {
272
- if (this.device.customBLEaddress && this.deviceLogging.includes('debug')) {
273
- (async () => {
274
- // Start to monitor advertisement packets
275
- await switchbot.startScan({
276
- model: 'i',
277
- });
278
- // Set an event handler
279
- switchbot.onadvertisement = (ad) => {
280
- this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} ad: ${(0, super_stringify_1.default)(ad, null, ' ')}`);
281
- };
282
- await switchbot.wait(10000);
283
- // Stop to monitor
284
- switchbot.stopScan();
285
- })();
286
- }
287
- }
288
- async BLEconnection(switchbot) {
289
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} wasn't able to establish BLE Connection, node-switchbot: ${switchbot}`);
290
- if (this.platform.config.credentials?.token) {
291
- this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Using OpenAPI Connection`);
292
- this.SwitchToOpenAPI = true;
293
- await this.openAPIRefreshStatus();
294
- }
295
- }
296
268
  async openAPIRefreshStatus() {
297
- if (this.platform.config.credentials?.token && this.OpenAPI) {
298
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} OpenAPI RefreshStatus`);
299
- try {
300
- const t = Date.now();
301
- const nonce = 'requestID';
302
- const data = this.platform.config.credentials?.token + t + nonce;
303
- const signTerm = crypto_1.default.createHmac('sha256', this.platform.config.credentials?.secret).update(Buffer.from(data, 'utf-8')).digest();
304
- const sign = signTerm.toString('base64');
305
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} sign: ${sign}`);
306
- const options = {
307
- hostname: settings_1.HostDomain,
308
- port: 443,
309
- path: `${settings_1.DevicePath}/${this.device.deviceId}/status`,
310
- method: 'GET',
311
- headers: {
312
- Authorization: this.platform.config.credentials?.token,
313
- sign: sign,
314
- nonce: nonce,
315
- t: t,
316
- 'Content-Type': 'application/json',
317
- },
318
- };
319
- const req = https_1.default.request(options, (res) => {
320
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} statusCode: ${res.statusCode}`);
321
- let rawData = '';
322
- res.on('data', (d) => {
323
- rawData += d;
324
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} d: ${d}`);
325
- });
326
- res.on('end', () => {
327
- try {
328
- this.deviceStatus = JSON.parse(rawData);
329
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus: ${(0, super_stringify_1.default)(this.deviceStatus)}`);
330
- this.Humidity = this.deviceStatus.body.humidity;
331
- this.Temperature = this.deviceStatus.body.temperature;
332
- this.parseStatus();
333
- this.updateHomeKitCharacteristics();
334
- }
335
- catch (e) {
336
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
337
- }
338
- });
269
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus`);
270
+ try {
271
+ const t = Date.now();
272
+ const nonce = 'requestID';
273
+ const data = this.platform.config.credentials?.token + t + nonce;
274
+ const signTerm = crypto_1.default.createHmac('sha256', this.platform.config.credentials?.secret).update(Buffer.from(data, 'utf-8')).digest();
275
+ const sign = signTerm.toString('base64');
276
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} sign: ${sign}`);
277
+ const options = {
278
+ hostname: settings_1.HostDomain,
279
+ port: 443,
280
+ path: `${settings_1.DevicePath}/${this.device.deviceId}/status`,
281
+ method: 'GET',
282
+ headers: {
283
+ Authorization: this.platform.config.credentials?.token,
284
+ sign: sign,
285
+ nonce: nonce,
286
+ t: t,
287
+ 'Content-Type': 'application/json',
288
+ },
289
+ };
290
+ const req = https_1.default.request(options, (res) => {
291
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus statusCode: ${res.statusCode}`);
292
+ let rawData = '';
293
+ res.on('data', (d) => {
294
+ rawData += d;
295
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} d: ${d}`);
339
296
  });
340
- req.on('error', (e) => {
341
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
297
+ res.on('end', () => {
298
+ try {
299
+ this.deviceStatus = JSON.parse(rawData);
300
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus: ${(0, super_stringify_1.default)(this.deviceStatus)}`);
301
+ this.Humidity = this.deviceStatus.body.humidity;
302
+ this.Temperature = this.deviceStatus.body.temperature;
303
+ this.parseStatus();
304
+ this.updateHomeKitCharacteristics();
305
+ }
306
+ catch (e) {
307
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
308
+ }
342
309
  });
343
- req.end();
344
- }
345
- catch (e) {
346
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed refreshStatus with OpenAPI Connection`);
347
- if (this.deviceLogging.includes('debug')) {
348
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed refreshStatus with OpenAPI Connection,` +
349
- ` Error Message: ${(0, super_stringify_1.default)(e.message)}`);
350
- }
351
- this.apiError(e);
352
- }
310
+ });
311
+ req.on('error', (e) => {
312
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
313
+ });
314
+ req.end();
353
315
  }
354
- else {
355
- this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} OpenAPI is disabled, commands will not be sent.`);
316
+ catch (e) {
317
+ this.apiError(e);
318
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}`
319
+ + ` Connection, Error Message: ${(0, super_stringify_1.default)(e.message)}`);
356
320
  }
357
321
  }
358
322
  /**
359
323
  * Updates the status for each of the HomeKit Characteristics
360
324
  */
361
325
  async updateHomeKitCharacteristics() {
326
+ const mqttmessage = [];
327
+ const entry = { time: Math.round(new Date().valueOf() / 1000) };
362
328
  if (!this.device.meter?.hide_humidity) {
363
329
  if (this.CurrentRelativeHumidity === undefined) {
364
330
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentRelativeHumidity: ${this.CurrentRelativeHumidity}`);
365
331
  }
366
332
  else {
333
+ this.accessory.context.CurrentRelativeHumidity = this.CurrentRelativeHumidity;
367
334
  this.humidityservice?.updateCharacteristic(this.platform.Characteristic.CurrentRelativeHumidity, this.CurrentRelativeHumidity);
368
335
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
369
336
  + ` updateCharacteristic CurrentRelativeHumidity: ${this.CurrentRelativeHumidity}`);
337
+ mqttmessage.push(`"humidity": ${this.CurrentRelativeHumidity}`);
338
+ entry['humidity'] = this.CurrentRelativeHumidity;
370
339
  }
371
340
  }
372
341
  if (!this.device.meter?.hide_temperature) {
@@ -374,15 +343,20 @@ class MeterPlus {
374
343
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentTemperature: ${this.CurrentTemperature}`);
375
344
  }
376
345
  else {
346
+ mqttmessage.push(`"temperature": ${this.CurrentTemperature}`);
347
+ entry['temp'] = this.CurrentTemperature;
348
+ this.accessory.context.CurrentTemperature = this.CurrentTemperature;
377
349
  this.temperatureservice?.updateCharacteristic(this.platform.Characteristic.CurrentTemperature, this.CurrentTemperature);
378
350
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic CurrentTemperature: ${this.CurrentTemperature}`);
379
351
  }
380
352
  }
381
- if (this.device.ble) {
353
+ if (this.BLE) {
382
354
  if (this.BatteryLevel === undefined) {
383
355
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}`);
384
356
  }
385
357
  else {
358
+ mqttmessage.push(`"battery": ${this.BatteryLevel}`);
359
+ this.accessory.context.BatteryLevel = this.BatteryLevel;
386
360
  this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, this.BatteryLevel);
387
361
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic BatteryLevel: ${this.BatteryLevel}`);
388
362
  }
@@ -390,23 +364,89 @@ class MeterPlus {
390
364
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} StatusLowBattery: ${this.StatusLowBattery}`);
391
365
  }
392
366
  else {
367
+ mqttmessage.push(`"lowBattery": ${this.StatusLowBattery}`);
368
+ this.accessory.context.StatusLowBattery = this.StatusLowBattery;
393
369
  this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, this.StatusLowBattery);
394
370
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic StatusLowBattery: ${this.StatusLowBattery}`);
395
371
  }
396
372
  }
373
+ this.mqttPublish(`{${mqttmessage.join(',')}}`);
374
+ if (this.CurrentRelativeHumidity > 0) {
375
+ // reject unreliable data
376
+ this.historyService?.addEntry(entry);
377
+ }
397
378
  }
398
- async apiError(e) {
399
- if (!this.device.meter?.hide_humidity) {
400
- this.humidityservice?.updateCharacteristic(this.platform.Characteristic.CurrentRelativeHumidity, e);
379
+ /*
380
+ * Publish MQTT message for topics of
381
+ * 'homebridge-switchbot/meter/xx:xx:xx:xx:xx:xx'
382
+ */
383
+ mqttPublish(message) {
384
+ const mac = this.device.deviceId
385
+ ?.toLowerCase()
386
+ .match(/[\s\S]{1,2}/g)
387
+ ?.join(':');
388
+ const options = this.device.mqttPubOptions || {};
389
+ this.mqttClient?.publish(`homebridge-switchbot/meter/${mac}`, `${message}`, options);
390
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} MQTT message: ${message} options:${(0, super_stringify_1.default)(options)}`);
391
+ }
392
+ /*
393
+ * Setup MQTT hadler if URL is specifed.
394
+ */
395
+ async setupMqtt(device) {
396
+ if (device.mqttURL) {
397
+ try {
398
+ this.mqttClient = await (0, async_mqtt_1.connectAsync)(device.mqttURL, device.mqttOptions || {});
399
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} MQTT connection has been established successfully.`);
400
+ this.mqttClient.on('error', (e) => {
401
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Failed to publish MQTT messages. ${e}`);
402
+ });
403
+ }
404
+ catch (e) {
405
+ this.mqttClient = null;
406
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Failed to establish MQTT connection. ${e}`);
407
+ }
401
408
  }
402
- if (!this.device.meter?.hide_temperature) {
403
- this.temperatureservice?.updateCharacteristic(this.platform.Characteristic.CurrentTemperature, e);
409
+ }
410
+ /*
411
+ * Setup EVE history graph feature if enabled.
412
+ */
413
+ async setupHistoryService(device) {
414
+ const mac = this.device
415
+ .deviceId.match(/.{1,2}/g)
416
+ .join(':')
417
+ .toLowerCase();
418
+ this.historyService = device.history
419
+ ? new this.platform.fakegatoAPI('room', this.accessory, {
420
+ log: this.platform.log,
421
+ storage: 'fs',
422
+ filename: `${(0, os_1.hostname)().split('.')[0]}_${mac}_persist.json`,
423
+ })
424
+ : null;
425
+ }
426
+ async getCustomBLEAddress(switchbot) {
427
+ if (this.device.customBLEaddress && this.deviceLogging.includes('debug')) {
428
+ (async () => {
429
+ // Start to monitor advertisement packets
430
+ await switchbot.startScan({
431
+ model: 'i',
432
+ });
433
+ // Set an event handler
434
+ switchbot.onadvertisement = (ad) => {
435
+ this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} ad: ${(0, super_stringify_1.default)(ad, null, ' ')}`);
436
+ };
437
+ await switchbot.wait(10000);
438
+ // Stop to monitor
439
+ switchbot.stopScan();
440
+ })();
404
441
  }
405
- if (this.device.ble) {
406
- this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, e);
407
- this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, e);
442
+ }
443
+ async BLEconnection(switchbot) {
444
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} wasn't able to establish BLE Connection, node-switchbot: ${switchbot}`);
445
+ if (this.platform.config.credentials?.token && this.device.connectionType !== 'Both') {
446
+ this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Using OpenAPI Connection`);
447
+ this.SwitchToOpenAPI = true;
448
+ await this.openAPIRefreshStatus();
408
449
  }
409
- //throw new this.platform.api.hap.HapStatusError(HAPStatus.SERVICE_COMMUNICATION_FAILURE);
410
450
  }
411
451
  model(device) {
412
452
  let model;
@@ -418,28 +458,125 @@ class MeterPlus {
418
458
  }
419
459
  return model;
420
460
  }
421
- async config(device) {
422
- let config = {};
423
- if (device.meter) {
424
- config = device.meter;
461
+ async scan(device) {
462
+ if (device.scanDuration) {
463
+ this.scanDuration = this.accessory.context.scanDuration = device.scanDuration;
464
+ if (this.BLE) {
465
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config scanDuration: ${this.scanDuration}`);
466
+ }
425
467
  }
426
- if (device.ble !== undefined) {
427
- config['ble'] = device.ble;
468
+ else {
469
+ this.scanDuration = this.accessory.context.scanDuration = 1;
470
+ if (this.BLE) {
471
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Default scanDuration: ${this.scanDuration}`);
472
+ }
428
473
  }
429
- if (device.openAPI !== undefined) {
430
- config['openAPI'] = device.openAPI;
474
+ }
475
+ async statusCode({ res }) {
476
+ switch (res.statusCode) {
477
+ case 151:
478
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command not supported by this device type.`);
479
+ break;
480
+ case 152:
481
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device not found.`);
482
+ break;
483
+ case 160:
484
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command is not supported.`);
485
+ break;
486
+ case 161:
487
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device is offline.`);
488
+ this.offlineOff();
489
+ break;
490
+ case 171:
491
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} is offline. Hub: ${this.device.hubDeviceId}`);
492
+ this.offlineOff();
493
+ break;
494
+ case 190:
495
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device internal error due to device states not synchronized with server,` +
496
+ ` Or command: ${(0, super_stringify_1.default)(res)} format is invalid`);
497
+ break;
498
+ case 100:
499
+ if (this.platform.debugMode) {
500
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Command successfully sent.`);
501
+ }
502
+ break;
503
+ default:
504
+ if (this.platform.debugMode) {
505
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode.`);
506
+ }
431
507
  }
432
- if (device.logging !== undefined) {
433
- config['logging'] = device.logging;
508
+ }
509
+ async offlineOff() {
510
+ if (this.device.offline) {
511
+ if (!this.device.meter?.hide_humidity) {
512
+ this.humidityservice?.updateCharacteristic(this.platform.Characteristic.CurrentRelativeHumidity, this.accessory.context.CurrentRelativeHumidity);
513
+ }
514
+ if (!this.device.meter?.hide_temperature) {
515
+ this.temperatureservice?.updateCharacteristic(this.platform.Characteristic.CurrentTemperature, this.accessory.context.CurrentTemperature);
516
+ }
517
+ if (this.BLE) {
518
+ this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, this.accessory.context.BatteryLevel);
519
+ this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, this.accessory.context.StatusLowBattery);
520
+ }
521
+ await this.updateHomeKitCharacteristics();
434
522
  }
435
- if (device.refreshRate !== undefined) {
436
- config['refreshRate'] = device.refreshRate;
523
+ }
524
+ async apiError(e) {
525
+ if (!this.device.meter?.hide_humidity) {
526
+ this.humidityservice?.updateCharacteristic(this.platform.Characteristic.CurrentRelativeHumidity, e);
437
527
  }
438
- if (device.scanDuration !== undefined) {
439
- config['scanDuration'] = device.scanDuration;
528
+ if (!this.device.meter?.hide_temperature) {
529
+ this.temperatureservice?.updateCharacteristic(this.platform.Characteristic.CurrentTemperature, e);
440
530
  }
441
- if (Object.entries(config).length !== 0) {
442
- this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${(0, super_stringify_1.default)(config)}`);
531
+ if (this.BLE) {
532
+ this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, e);
533
+ this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, e);
534
+ }
535
+ }
536
+ FirmwareRevision(accessory, device) {
537
+ let FirmwareRevision;
538
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
539
+ + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`);
540
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} device.firmware: ${device.firmware}`);
541
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`);
542
+ if (accessory.context.FirmwareRevision) {
543
+ FirmwareRevision = accessory.context.FirmwareRevision;
544
+ }
545
+ else if (device.firmware) {
546
+ FirmwareRevision = device.firmware;
547
+ }
548
+ else {
549
+ FirmwareRevision = this.platform.version;
550
+ }
551
+ return FirmwareRevision;
552
+ }
553
+ context() {
554
+ if (this.CurrentRelativeHumidity === undefined) {
555
+ this.CurrentRelativeHumidity = 0;
556
+ }
557
+ else {
558
+ this.CurrentRelativeHumidity = this.accessory.context.CurrentRelativeHumidity;
559
+ }
560
+ if (this.CurrentTemperature === undefined) {
561
+ this.CurrentTemperature = 0;
562
+ }
563
+ else {
564
+ this.CurrentTemperature = this.accessory.context.CurrentTemperature;
565
+ }
566
+ if (this.BLE) {
567
+ if (this.BatteryLevel === undefined) {
568
+ this.BatteryLevel = 100;
569
+ }
570
+ else {
571
+ this.BatteryLevel = this.accessory.context.BatteryLevel;
572
+ }
573
+ if (this.StatusLowBattery === undefined) {
574
+ this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
575
+ this.accessory.context.StatusLowBattery = this.StatusLowBattery;
576
+ }
577
+ else {
578
+ this.StatusLowBattery = this.accessory.context.StatusLowBattery;
579
+ }
443
580
  }
444
581
  }
445
582
  async refreshRate(device) {
@@ -452,27 +589,25 @@ class MeterPlus {
452
589
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Platform Config refreshRate: ${this.deviceRefreshRate}`);
453
590
  }
454
591
  }
455
- async openAPI() {
456
- if (!this.device.openAPI) {
457
- this.OpenAPI = true;
592
+ async config(device) {
593
+ let config = {};
594
+ if (device.meter) {
595
+ config = device.meter;
458
596
  }
459
- else {
460
- this.OpenAPI = this.device.openAPI;
597
+ if (device.connectionType !== undefined) {
598
+ config['connectionType'] = device.connectionType;
461
599
  }
462
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using OpenAPI: ${this.OpenAPI}`);
463
- }
464
- async scan(device) {
465
- if (device.scanDuration) {
466
- this.scanDuration = this.accessory.context.scanDuration = device.scanDuration;
467
- if (device.ble) {
468
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config scanDuration: ${this.scanDuration}`);
469
- }
600
+ if (device.logging !== undefined) {
601
+ config['logging'] = device.logging;
470
602
  }
471
- else {
472
- this.scanDuration = this.accessory.context.scanDuration = 1;
473
- if (this.device.ble) {
474
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Default scanDuration: ${this.scanDuration}`);
475
- }
603
+ if (device.refreshRate !== undefined) {
604
+ config['refreshRate'] = device.refreshRate;
605
+ }
606
+ if (device.scanDuration !== undefined) {
607
+ config['scanDuration'] = device.scanDuration;
608
+ }
609
+ if (Object.entries(config).length !== 0) {
610
+ this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${(0, super_stringify_1.default)(config)}`);
476
611
  }
477
612
  }
478
613
  async logs(device) {
@@ -493,23 +628,6 @@ class MeterPlus {
493
628
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Logging Not Set, Using: ${this.deviceLogging}`);
494
629
  }
495
630
  }
496
- FirmwareRevision(accessory, device) {
497
- let FirmwareRevision;
498
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
499
- + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`);
500
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} device.firmware: ${device.firmware}`);
501
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`);
502
- if (accessory.context.FirmwareRevision) {
503
- FirmwareRevision = accessory.context.FirmwareRevision;
504
- }
505
- else if (device.firmware) {
506
- FirmwareRevision = device.firmware;
507
- }
508
- else {
509
- FirmwareRevision = this.platform.version;
510
- }
511
- return FirmwareRevision;
512
- }
513
631
  /**
514
632
  * Logging for Device
515
633
  */