@switchbot/homebridge-switchbot 2.0.0-beta.4 → 2.0.0-beta.40

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 (119) hide show
  1. package/CHANGELOG.md +12 -2
  2. package/README.md +3 -2
  3. package/config.schema.json +108 -20
  4. package/dist/device/bot.d.ts +34 -28
  5. package/dist/device/bot.d.ts.map +1 -1
  6. package/dist/device/bot.js +657 -648
  7. package/dist/device/bot.js.map +1 -1
  8. package/dist/device/ceilinglight.d.ts +137 -0
  9. package/dist/device/ceilinglight.d.ts.map +1 -0
  10. package/dist/device/ceilinglight.js +1127 -0
  11. package/dist/device/ceilinglight.js.map +1 -0
  12. package/dist/device/colorbulb.d.ts +36 -19
  13. package/dist/device/colorbulb.d.ts.map +1 -1
  14. package/dist/device/colorbulb.js +486 -309
  15. package/dist/device/colorbulb.js.map +1 -1
  16. package/dist/device/contact.d.ts +18 -8
  17. package/dist/device/contact.d.ts.map +1 -1
  18. package/dist/device/contact.js +306 -237
  19. package/dist/device/contact.js.map +1 -1
  20. package/dist/device/curtain.d.ts +23 -16
  21. package/dist/device/curtain.d.ts.map +1 -1
  22. package/dist/device/curtain.js +566 -502
  23. package/dist/device/curtain.js.map +1 -1
  24. package/dist/device/humidifier.d.ts +24 -18
  25. package/dist/device/humidifier.d.ts.map +1 -1
  26. package/dist/device/humidifier.js +453 -369
  27. package/dist/device/humidifier.js.map +1 -1
  28. package/dist/device/lock.d.ts +27 -8
  29. package/dist/device/lock.d.ts.map +1 -1
  30. package/dist/device/lock.js +305 -148
  31. package/dist/device/lock.js.map +1 -1
  32. package/dist/device/meter.d.ts +22 -16
  33. package/dist/device/meter.d.ts.map +1 -1
  34. package/dist/device/meter.js +367 -267
  35. package/dist/device/meter.js.map +1 -1
  36. package/dist/device/meterplus.d.ts +24 -12
  37. package/dist/device/meterplus.d.ts.map +1 -1
  38. package/dist/device/meterplus.js +381 -213
  39. package/dist/device/meterplus.js.map +1 -1
  40. package/dist/device/motion.d.ts +18 -8
  41. package/dist/device/motion.d.ts.map +1 -1
  42. package/dist/device/motion.js +279 -216
  43. package/dist/device/motion.js.map +1 -1
  44. package/dist/device/plug.d.ts +27 -17
  45. package/dist/device/plug.d.ts.map +1 -1
  46. package/dist/device/plug.js +295 -251
  47. package/dist/device/plug.js.map +1 -1
  48. package/dist/device/striplight.d.ts +43 -19
  49. package/dist/device/striplight.d.ts.map +1 -1
  50. package/dist/device/striplight.js +506 -262
  51. package/dist/device/striplight.js.map +1 -1
  52. package/dist/irdevice/airconditioner.d.ts +9 -12
  53. package/dist/irdevice/airconditioner.d.ts.map +1 -1
  54. package/dist/irdevice/airconditioner.js +278 -230
  55. package/dist/irdevice/airconditioner.js.map +1 -1
  56. package/dist/irdevice/airpurifier.d.ts +5 -3
  57. package/dist/irdevice/airpurifier.d.ts.map +1 -1
  58. package/dist/irdevice/airpurifier.js +154 -104
  59. package/dist/irdevice/airpurifier.js.map +1 -1
  60. package/dist/irdevice/camera.d.ts +11 -8
  61. package/dist/irdevice/camera.d.ts.map +1 -1
  62. package/dist/irdevice/camera.js +133 -86
  63. package/dist/irdevice/camera.js.map +1 -1
  64. package/dist/irdevice/fan.d.ts +10 -7
  65. package/dist/irdevice/fan.d.ts.map +1 -1
  66. package/dist/irdevice/fan.js +160 -109
  67. package/dist/irdevice/fan.js.map +1 -1
  68. package/dist/irdevice/light.d.ts +11 -8
  69. package/dist/irdevice/light.d.ts.map +1 -1
  70. package/dist/irdevice/light.js +137 -103
  71. package/dist/irdevice/light.js.map +1 -1
  72. package/dist/irdevice/other.d.ts +11 -8
  73. package/dist/irdevice/other.d.ts.map +1 -1
  74. package/dist/irdevice/other.js +145 -98
  75. package/dist/irdevice/other.js.map +1 -1
  76. package/dist/irdevice/tv.d.ts +12 -9
  77. package/dist/irdevice/tv.d.ts.map +1 -1
  78. package/dist/irdevice/tv.js +143 -93
  79. package/dist/irdevice/tv.js.map +1 -1
  80. package/dist/irdevice/vacuumcleaner.d.ts +9 -10
  81. package/dist/irdevice/vacuumcleaner.d.ts.map +1 -1
  82. package/dist/irdevice/vacuumcleaner.js +132 -89
  83. package/dist/irdevice/vacuumcleaner.js.map +1 -1
  84. package/dist/irdevice/waterheater.d.ts +8 -9
  85. package/dist/irdevice/waterheater.d.ts.map +1 -1
  86. package/dist/irdevice/waterheater.js +132 -89
  87. package/dist/irdevice/waterheater.js.map +1 -1
  88. package/dist/platform.d.ts +15 -12
  89. package/dist/platform.d.ts.map +1 -1
  90. package/dist/platform.js +574 -454
  91. package/dist/platform.js.map +1 -1
  92. package/dist/settings.d.ts +21 -11
  93. package/dist/settings.d.ts.map +1 -1
  94. package/dist/settings.js.map +1 -1
  95. package/homebridge-ui/public/index.html +1 -0
  96. package/package.json +13 -11
  97. package/src/device/bot.ts +656 -659
  98. package/src/device/ceilinglight.ts +1208 -0
  99. package/src/device/colorbulb.ts +490 -344
  100. package/src/device/contact.ts +309 -241
  101. package/src/device/curtain.ts +571 -516
  102. package/src/device/humidifier.ts +456 -403
  103. package/src/device/lock.ts +314 -149
  104. package/src/device/meter.ts +378 -280
  105. package/src/device/meterplus.ts +391 -219
  106. package/src/device/motion.ts +285 -222
  107. package/src/device/plug.ts +299 -260
  108. package/src/device/striplight.ts +522 -289
  109. package/src/irdevice/airconditioner.ts +282 -241
  110. package/src/irdevice/airpurifier.ts +151 -103
  111. package/src/irdevice/camera.ts +131 -85
  112. package/src/irdevice/fan.ts +157 -106
  113. package/src/irdevice/light.ts +135 -103
  114. package/src/irdevice/other.ts +143 -97
  115. package/src/irdevice/tv.ts +142 -93
  116. package/src/irdevice/vacuumcleaner.ts +131 -89
  117. package/src/irdevice/waterheater.ts +130 -89
  118. package/src/platform.ts +567 -476
  119. package/src/settings.ts +22 -11
@@ -6,9 +6,11 @@ import { MqttClient } from 'mqtt';
6
6
  import { connectAsync } from 'async-mqtt';
7
7
  import { interval, Subject } from 'rxjs';
8
8
  import { skipWhile } from 'rxjs/operators';
9
+ import superStringify from 'super-stringify';
9
10
  import { SwitchBotPlatform } from '../platform';
10
11
  import { Service, PlatformAccessory, Units, CharacteristicValue } from 'homebridge';
11
12
  import { device, devicesConfig, serviceData, ad, switchbot, temperature, deviceStatus, HostDomain, DevicePath } from '../settings';
13
+ import { IncomingMessage } from 'http';
12
14
 
13
15
  /**
14
16
  * Platform Accessory
@@ -23,14 +25,10 @@ export class Meter {
23
25
 
24
26
  // Characteristic Values
25
27
  CurrentRelativeHumidity!: CharacteristicValue;
26
- CurrentRelativeHumidityCached!: CharacteristicValue;
27
28
  CurrentTemperature?: CharacteristicValue;
28
- CurrentTemperatureCached?: CharacteristicValue;
29
29
  BatteryLevel?: CharacteristicValue;
30
30
  ChargingState?: CharacteristicValue;
31
31
  StatusLowBattery?: CharacteristicValue;
32
- Active!: CharacteristicValue;
33
- WaterLevel!: CharacteristicValue;
34
32
 
35
33
  // OpenAPI Others
36
34
  Temperature: deviceStatus['temperature'];
@@ -40,13 +38,18 @@ export class Meter {
40
38
  // BLE Others
41
39
  connected?: boolean;
42
40
  switchbot!: switchbot;
43
- SwitchToOpenAPI?: boolean;
44
41
  serviceData!: serviceData;
45
42
  address!: ad['address'];
46
43
  temperature!: temperature['c'];
47
44
  battery!: serviceData['battery'];
48
45
  humidity!: serviceData['humidity'];
49
46
 
47
+ //MQTT stuff
48
+ mqttClient: MqttClient | null = null;
49
+
50
+ // EVE history service handler
51
+ historyService?: any;
52
+
50
53
  // Config
51
54
  scanDuration!: number;
52
55
  deviceLogging!: string;
@@ -56,30 +59,19 @@ export class Meter {
56
59
  meterUpdateInProgress!: boolean;
57
60
  doMeterUpdate: Subject<void>;
58
61
 
59
- //MQTT stuff
60
- mqttClient: MqttClient | null = null;
61
-
62
- // EVE history service handler
63
- historyService: any;
62
+ // Connection
63
+ private readonly BLE = (this.device.connectionType === 'BLE' || this.device.connectionType === 'BLE/OpenAPI');
64
+ private readonly OpenAPI = (this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'BLE/OpenAPI');
64
65
 
65
66
  constructor(private readonly platform: SwitchBotPlatform, private accessory: PlatformAccessory, public device: device & devicesConfig) {
66
67
  // default placeholders
67
68
  this.logs(device);
68
69
  this.scan(device);
69
- this.setupHistoryService(device);
70
70
  this.refreshRate(device);
71
71
  this.config(device);
72
+ this.context();
73
+ this.setupHistoryService(device);
72
74
  this.setupMqtt(device);
73
- if (this.CurrentRelativeHumidity === undefined) {
74
- this.CurrentRelativeHumidity = 0;
75
- } else {
76
- this.CurrentRelativeHumidity = this.accessory.context.CurrentRelativeHumidity;
77
- }
78
- if (this.CurrentTemperature === undefined) {
79
- this.CurrentTemperature = 0;
80
- } else {
81
- this.CurrentTemperature = this.accessory.context.CurrentTemperature;
82
- }
83
75
 
84
76
  // this is subject we use to track when we need to POST changes to the SwitchBot API
85
77
  this.doMeterUpdate = new Subject();
@@ -100,11 +92,11 @@ export class Meter {
100
92
 
101
93
  // Temperature Sensor Service
102
94
  if (device.meter?.hide_temperature) {
103
- this.debugLog(`Meter: ${accessory.displayName} Removing Temperature Sensor Service`);
95
+ this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Removing Temperature Sensor Service`);
104
96
  this.temperatureservice = this.accessory.getService(this.platform.Service.TemperatureSensor);
105
97
  accessory.removeService(this.temperatureservice!);
106
98
  } else if (!this.temperatureservice) {
107
- this.debugLog(`Meter: ${accessory.displayName} Add Temperature Sensor Service`);
99
+ this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Add Temperature Sensor Service`);
108
100
  (this.temperatureservice =
109
101
  this.accessory.getService(this.platform.Service.TemperatureSensor) || this.accessory.addService(this.platform.Service.TemperatureSensor)),
110
102
  `${accessory.displayName} Temperature Sensor`;
@@ -124,16 +116,16 @@ export class Meter {
124
116
  return this.CurrentTemperature!;
125
117
  });
126
118
  } else {
127
- this.debugLog(`Meter: ${accessory.displayName} Temperature Sensor Service Not Added`);
119
+ this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Temperature Sensor Service Not Added`);
128
120
  }
129
121
 
130
122
  // Humidity Sensor Service
131
123
  if (device.meter?.hide_humidity) {
132
- this.debugLog(`Meter: ${accessory.displayName} Removing Humidity Sensor Service`);
124
+ this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Removing Humidity Sensor Service`);
133
125
  this.humidityservice = this.accessory.getService(this.platform.Service.HumiditySensor);
134
126
  accessory.removeService(this.humidityservice!);
135
127
  } else if (!this.humidityservice) {
136
- this.debugLog(`Meter: ${accessory.displayName} Add Humidity Sensor Service`);
128
+ this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Add Humidity Sensor Service`);
137
129
  (this.humidityservice =
138
130
  this.accessory.getService(this.platform.Service.HumiditySensor) || this.accessory.addService(this.platform.Service.HumiditySensor)),
139
131
  `${accessory.displayName} Humidity Sensor`;
@@ -149,16 +141,16 @@ export class Meter {
149
141
  return this.CurrentRelativeHumidity;
150
142
  });
151
143
  } else {
152
- this.debugLog(`Meter: ${accessory.displayName} Humidity Sensor Service Not Added`);
144
+ this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Humidity Sensor Service Not Added`);
153
145
  }
154
146
 
155
147
  // Battery Service
156
- if (!device.ble) {
157
- this.debugLog(`Meter: ${accessory.displayName} Removing Battery Service`);
148
+ if (!this.BLE) {
149
+ this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Removing Battery Service`);
158
150
  this.batteryService = this.accessory.getService(this.platform.Service.Battery);
159
151
  accessory.removeService(this.batteryService!);
160
- } else if (device.ble && !this.batteryService) {
161
- this.debugLog(`Meter: ${accessory.displayName} Add Battery Service`);
152
+ } else if (this.BLE && !this.batteryService) {
153
+ this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Add Battery Service`);
162
154
  (this.batteryService = this.accessory.getService(this.platform.Service.Battery) || this.accessory.addService(this.platform.Service.Battery)),
163
155
  `${accessory.displayName} Battery`;
164
156
 
@@ -166,7 +158,7 @@ export class Meter {
166
158
 
167
159
  this.batteryService.setCharacteristic(this.platform.Characteristic.ChargingState, this.platform.Characteristic.ChargingState.NOT_CHARGEABLE);
168
160
  } else {
169
- this.debugLog(`Meter: ${accessory.displayName} Battery Service Not Added`);
161
+ this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Battery Service Not Added`);
170
162
  }
171
163
 
172
164
  // Retrieve initial values and updateHomekit
@@ -180,68 +172,22 @@ export class Meter {
180
172
  });
181
173
  }
182
174
 
183
- /*
184
- * Publish MQTT message for topics of
185
- * 'homebridge-switchbot/meter/xx:xx:xx:xx:xx:xx'
186
- */
187
- mqttPublish(message: any) {
188
- const mac = this.device.deviceId
189
- ?.toLowerCase()
190
- .match(/[\s\S]{1,2}/g)
191
- ?.join(':');
192
- const options = this.device.mqttPubOptions || {};
193
- this.mqttClient?.publish(`homebridge-switchbot/meter/${mac}`, `${message}`, options);
194
- this.debugLog(`Meter: ${this.accessory.displayName} MQTT message: ${message} options:${JSON.stringify(options)}`);
195
- }
196
-
197
- /*
198
- * Setup MQTT hadler if URL is specifed.
199
- */
200
- async setupMqtt(device: device & devicesConfig): Promise<void> {
201
- if (device.mqttURL) {
202
- try {
203
- this.mqttClient = await connectAsync(device.mqttURL, device.mqttOptions || {});
204
- this.debugLog(`Meter: ${this.accessory.displayName} MQTT connection has been established successfully.`);
205
- this.mqttClient.on('error', (e: Error) => {
206
- this.errorLog(`Meter: ${this.accessory.displayName} Failed to publish MQTT messages. ${e}`);
207
- });
208
- } catch (e) {
209
- this.mqttClient = null;
210
- this.errorLog(`Meter: ${this.accessory.displayName} Failed to establish MQTT connection. ${e}`);
211
- }
212
- }
213
- }
214
-
215
- /*
216
- * Setup EVE history graph feature if enabled.
217
- */
218
- async setupHistoryService(device: device & devicesConfig): Promise<void> {
219
- const mac = this.device
220
- .deviceId!.match(/.{1,2}/g)!
221
- .join(':')
222
- .toLowerCase();
223
- this.historyService = device.history
224
- ? new this.platform.fakegatoAPI('room', this.accessory, {
225
- log: this.platform.log,
226
- storage: 'fs',
227
- filename: `${hostname().split('.')[0]}_${mac}_persist.json`,
228
- })
229
- : null;
230
- }
231
-
232
175
  /**
233
176
  * Parse the device status from the SwitchBot api
234
177
  */
235
178
  async parseStatus(): Promise<void> {
236
- if (this.SwitchToOpenAPI || !this.device.ble) {
179
+ if (this.BLE) {
180
+ await this.BLEparseStatus();
181
+ } else if (this.OpenAPI && this.platform.config.credentials?.token) {
237
182
  await this.openAPIparseStatus();
238
183
  } else {
239
- await this.BLEparseStatus();
184
+ this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:`
185
+ + ` ${this.device.connectionType}, parseStatus will not happen.`);
240
186
  }
241
187
  }
242
188
 
243
189
  async BLEparseStatus(): Promise<void> {
244
- this.debugLog(`Meter: ${this.accessory.displayName} BLE parseStatus`);
190
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEparseStatus`);
245
191
 
246
192
  // Battery
247
193
  this.BatteryLevel = Number(this.battery);
@@ -250,39 +196,34 @@ export class Meter {
250
196
  } else {
251
197
  this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
252
198
  }
253
- this.debugLog(`Meter: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}, StatusLowBattery: ${this.StatusLowBattery}`);
199
+ this.debugLog(`${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}, StatusLowBattery: ${this.StatusLowBattery}`);
254
200
 
255
201
  // Humidity
256
202
  if (!this.device.meter?.hide_humidity) {
257
203
  this.CurrentRelativeHumidity = this.humidity!;
258
- this.debugLog(`Meter: ${this.accessory.displayName} Humidity: ${this.CurrentRelativeHumidity}%`);
204
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Humidity: ${this.CurrentRelativeHumidity}%`);
259
205
  }
260
206
 
261
207
  // Current Temperature
262
208
  if (!this.device.meter?.hide_temperature) {
263
209
  this.temperature < 0 ? 0 : this.temperature > 100 ? 100 : this.temperature;
264
210
  this.CurrentTemperature = this.temperature;
265
- this.debugLog(`Meter: ${this.accessory.displayName} Temperature: ${this.CurrentTemperature}°c`);
211
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Temperature: ${this.CurrentTemperature}°c`);
266
212
  }
267
213
  }
268
214
 
269
215
  async openAPIparseStatus(): Promise<void> {
270
- if (this.device.ble) {
271
- this.SwitchToOpenAPI = false;
216
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIparseStatus`);
217
+ // Current Relative Humidity
218
+ if (!this.device.meter?.hide_humidity) {
219
+ this.CurrentRelativeHumidity = this.Humidity!;
220
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Humidity: ${this.CurrentRelativeHumidity}%`);
272
221
  }
273
- if (this.platform.config.credentials?.token) {
274
- this.debugLog(`Meter: ${this.accessory.displayName} OpenAPI parseStatus`);
275
- // Current Relative Humidity
276
- if (!this.device.meter?.hide_humidity) {
277
- this.CurrentRelativeHumidity = this.Humidity!;
278
- this.debugLog(`Meter: ${this.accessory.displayName} Humidity: ${this.CurrentRelativeHumidity}%`);
279
- }
280
222
 
281
- // Current Temperature
282
- if (!this.device.meter?.hide_temperature) {
283
- this.CurrentTemperature = this.Temperature!;
284
- this.debugLog(`Meter: ${this.accessory.displayName} Temperature: ${this.CurrentTemperature}°c`);
285
- }
223
+ // Current Temperature
224
+ if (!this.device.meter?.hide_temperature) {
225
+ this.CurrentTemperature = this.Temperature!;
226
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Temperature: ${this.CurrentTemperature}°c`);
286
227
  }
287
228
  }
288
229
 
@@ -290,22 +231,25 @@ export class Meter {
290
231
  * Asks the SwitchBot API for the latest device information
291
232
  */
292
233
  async refreshStatus(): Promise<void> {
293
- if (this.device.ble) {
294
- this.BLErefreshStatus();
234
+ if (this.BLE) {
235
+ await this.BLERefreshStatus();
236
+ } else if (this.OpenAPI && this.platform.config.credentials?.token) {
237
+ await this.openAPIRefreshStatus();
295
238
  } else {
296
- this.openAPIRefreshStatus();
239
+ this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:`
240
+ + ` ${this.device.connectionType}, refreshStatus will not happen.`);
297
241
  }
298
242
  }
299
243
 
300
- async BLErefreshStatus(): Promise<void> {
301
- this.debugLog(`Meter: ${this.accessory.displayName} BLE RefreshStatus`);
244
+ async BLERefreshStatus(): Promise<void> {
245
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLERefreshStatus`);
302
246
  const switchbot = await this.platform.connectBLE();
303
247
  // Convert to BLE Address
304
248
  this.device.bleMac = this.device
305
249
  .deviceId!.match(/.{1,2}/g)!
306
250
  .join(':')
307
251
  .toLowerCase();
308
- this.debugLog(`Meter: ${this.accessory.displayName} BLE Address: ${this.device.bleMac}`);
252
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLE Address: ${this.device.bleMac}`);
309
253
  this.getCustomBLEAddress(switchbot);
310
254
  // Start to monitor advertisement packets
311
255
  if (switchbot !== false) {
@@ -318,32 +262,28 @@ export class Meter {
318
262
  // Set an event hander
319
263
  switchbot.onadvertisement = (ad: ad) => {
320
264
  this.address = ad.address;
321
- if (this.deviceLogging.includes('debug')) {
322
- this.infoLog(this.address);
323
- this.infoLog(this.device.bleMac);
324
- this.infoLog(`Meter: ${this.accessory.displayName} BLE Address Found: ${this.address}`);
325
- this.infoLog(`Meter: ${this.accessory.displayName} Config BLE Address: ${this.device.bleMac}`);
326
- }
265
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Config BLE Address: ${this.device.bleMac},`
266
+ + ` BLE Address Found: ${this.address}`);
327
267
  if (ad.serviceData.humidity! > 0) {
328
268
  // reject unreliable data
329
- this.serviceData = ad.serviceData;
330
- this.temperature = ad.serviceData.temperature!.c;
331
269
  this.humidity = ad.serviceData.humidity;
332
- this.battery = ad.serviceData.battery;
333
270
  }
334
- this.debugLog(`Meter: ${this.accessory.displayName} serviceData: ${JSON.stringify(ad.serviceData)}`);
271
+ this.serviceData = ad.serviceData;
272
+ this.temperature = ad.serviceData.temperature!.c;
273
+ this.battery = ad.serviceData.battery;
274
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} serviceData: ${superStringify(ad.serviceData)}`);
335
275
  this.debugLog(
336
- `Meter: ${this.accessory.displayName} model: ${ad.serviceData.model}, modelName: ${ad.serviceData.modelName}, ` +
337
- `temperature: ${JSON.stringify(ad.serviceData.temperature?.c)}, humidity: ${ad.serviceData.humidity}, ` +
276
+ `${this.device.deviceType}: ${this.accessory.displayName} model: ${ad.serviceData.model}, modelName: ${ad.serviceData.modelName}, ` +
277
+ `temperature: ${superStringify(ad.serviceData.temperature?.c)}, humidity: ${ad.serviceData.humidity}, ` +
338
278
  `battery: ${ad.serviceData.battery}`,
339
279
  );
340
280
 
341
281
  if (this.serviceData) {
342
282
  this.connected = true;
343
- this.debugLog(`Meter: ${this.accessory.displayName} connected: ${this.connected}`);
283
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} connected: ${this.connected}`);
344
284
  } else {
345
285
  this.connected = false;
346
- this.debugLog(`Meter: ${this.accessory.displayName} connected: ${this.connected}`);
286
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} connected: ${this.connected}`);
347
287
  }
348
288
  };
349
289
  // Wait 10 seconds
@@ -353,114 +293,73 @@ export class Meter {
353
293
  // Stop to monitor
354
294
  switchbot.stopScan();
355
295
  if (this.connected) {
356
- this.parseStatus();
296
+ this.BLEparseStatus();
357
297
  this.updateHomeKitCharacteristics();
358
298
  } else {
359
- await this.BLEconnection(switchbot);
299
+ await this.BLERefreshConnection(switchbot);
360
300
  }
361
301
  })
362
302
  .catch(async (e: any) => {
363
- this.errorLog(`Meter: ${this.accessory.displayName} failed refreshStatus with BLE Connection`);
364
- if (this.deviceLogging.includes('debug')) {
365
- this.errorLog(
366
- `Meter: ${this.accessory.displayName} failed refreshStatus with BLE Connection,` + ` Error Message: ${JSON.stringify(e.message)}`,
367
- );
368
- }
369
- if (this.platform.config.credentials?.token) {
370
- this.warnLog(`Meter: ${this.accessory.displayName} Using OpenAPI Connection`);
371
- this.SwitchToOpenAPI = true;
372
- this.openAPIRefreshStatus();
373
- }
374
303
  this.apiError(e);
304
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLERefreshStatus with ${this.device.connectionType}`
305
+ + ` Connection, Error Message: ${superStringify(e.message)}`);
306
+ await this.BLERefreshConnection(switchbot);
375
307
  });
376
308
  } else {
377
- await this.BLEconnection(switchbot);
378
- }
379
- }
380
-
381
- async getCustomBLEAddress(switchbot: any) {
382
- if (this.device.customBLEaddress && this.deviceLogging.includes('debug')) {
383
- (async () => {
384
- // Start to monitor advertisement packets
385
- await switchbot.startScan({
386
- model: 'T',
387
- });
388
- // Set an event handler
389
- switchbot.onadvertisement = (ad: any) => {
390
- this.warnLog(`Meter: ${this.accessory.displayName} ad: ${JSON.stringify(ad, null, ' ')}`);
391
- };
392
- await switchbot.wait(10000);
393
- // Stop to monitor
394
- switchbot.stopScan();
395
- })();
396
- }
397
- }
398
-
399
- async BLEconnection(switchbot: any): Promise<void> {
400
- this.errorLog(`Meter: ${this.accessory.displayName} wasn't able to establish BLE Connection, node-switchbot: ${switchbot}`);
401
- if (this.platform.config.credentials?.token) {
402
- this.warnLog(`Meter: ${this.accessory.displayName} Using OpenAPI Connection`);
403
- this.SwitchToOpenAPI = true;
404
- await this.openAPIRefreshStatus();
309
+ await this.BLERefreshConnection(switchbot);
405
310
  }
406
311
  }
407
312
 
408
313
  async openAPIRefreshStatus(): Promise<void> {
409
- if (this.platform.config.credentials?.token) {
410
- this.debugLog(`Meter: ${this.accessory.displayName} OpenAPI RefreshStatus`);
411
- try {
412
- const t = Date.now();
413
- const nonce = 'requestID';
414
- const data = this.platform.config.credentials?.token + t + nonce;
415
- const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret).update(Buffer.from(data, 'utf-8')).digest();
416
- const sign = signTerm.toString('base64');
417
- this.debugLog(`Meter: ${this.accessory.displayName} sign: ${sign}`);
418
- const options = {
419
- hostname: HostDomain,
420
- port: 443,
421
- path: `${DevicePath}/${this.device.deviceId}/status`,
422
- method: 'GET',
423
- headers: {
424
- Authorization: this.platform.config.credentials?.token,
425
- sign: sign,
426
- nonce: nonce,
427
- t: t,
428
- 'Content-Type': 'application/json',
429
- },
430
- };
431
- const req = https.request(options, (res) => {
432
- this.debugLog(`Meter: ${this.accessory.displayName} statusCode: ${res.statusCode}`);
433
- let rawData = '';
434
- res.on('data', (d) => {
435
- rawData += d;
436
- this.debugLog(`Meter: ${this.accessory.displayName} d: ${d}`);
437
- });
438
- res.on('end', () => {
439
- try {
440
- this.deviceStatus = JSON.parse(rawData);
441
- this.debugLog(`Meter: ${this.accessory.displayName} openAPIRefreshStatus: ${JSON.stringify(this.deviceStatus)}`);
442
- this.Humidity = this.deviceStatus.body.humidity!;
443
- this.Temperature = this.deviceStatus.body.temperature!;
444
- this.parseStatus();
445
- this.updateHomeKitCharacteristics();
446
- } catch (e: any) {
447
- this.errorLog(`Meter: ${this.accessory.displayName} error message: ${e.message}`);
448
- }
449
- });
314
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus`);
315
+ try {
316
+ const t = Date.now();
317
+ const nonce = 'requestID';
318
+ const data = this.platform.config.credentials?.token + t + nonce;
319
+ const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret).update(Buffer.from(data, 'utf-8')).digest();
320
+ const sign = signTerm.toString('base64');
321
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} sign: ${sign}`);
322
+ const options = {
323
+ hostname: HostDomain,
324
+ port: 443,
325
+ path: `${DevicePath}/${this.device.deviceId}/status`,
326
+ method: 'GET',
327
+ headers: {
328
+ Authorization: this.platform.config.credentials?.token,
329
+ sign: sign,
330
+ nonce: nonce,
331
+ t: t,
332
+ 'Content-Type': 'application/json',
333
+ },
334
+ };
335
+ const req = https.request(options, (res) => {
336
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus statusCode: ${res.statusCode}`);
337
+ let rawData = '';
338
+ res.on('data', (d) => {
339
+ rawData += d;
340
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} d: ${d}`);
450
341
  });
451
- req.on('error', (e: any) => {
452
- this.errorLog(`Meter: ${this.accessory.displayName} error message: ${e.message}`);
342
+ res.on('end', () => {
343
+ try {
344
+ this.deviceStatus = JSON.parse(rawData);
345
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus: ${superStringify(this.deviceStatus)}`);
346
+ this.Humidity = this.deviceStatus.body.humidity!;
347
+ this.Temperature = this.deviceStatus.body.temperature!;
348
+ this.openAPIparseStatus();
349
+ this.updateHomeKitCharacteristics();
350
+ } catch (e: any) {
351
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
352
+ }
453
353
  });
454
- req.end();
455
- } catch (e: any) {
456
- this.errorLog(`Meter: ${this.accessory.displayName} failed refreshStatus with OpenAPI Connection`);
457
- if (this.deviceLogging.includes('debug')) {
458
- this.errorLog(
459
- `Meter: ${this.accessory.displayName} failed refreshStatus with OpenAPI Connection,` + ` Error Message: ${JSON.stringify(e.message)}`,
460
- );
461
- }
462
- this.apiError(e);
463
- }
354
+ });
355
+ req.on('error', (e: any) => {
356
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
357
+ });
358
+ req.end();
359
+ } catch (e: any) {
360
+ this.apiError(e);
361
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}`
362
+ + ` Connection, Error Message: ${superStringify(e.message)}`);
464
363
  }
465
364
  }
466
365
 
@@ -472,44 +371,209 @@ export class Meter {
472
371
  const entry = { time: Math.round(new Date().valueOf() / 1000) };
473
372
  if (!this.device.meter?.hide_humidity) {
474
373
  if (this.CurrentRelativeHumidity === undefined) {
475
- this.debugLog(`Meter: ${this.accessory.displayName} CurrentRelativeHumidity: ${this.CurrentRelativeHumidity}`);
374
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentRelativeHumidity: ${this.CurrentRelativeHumidity}`);
476
375
  } else {
376
+ this.accessory.context.CurrentRelativeHumidity = this.CurrentRelativeHumidity;
477
377
  this.humidityservice?.updateCharacteristic(this.platform.Characteristic.CurrentRelativeHumidity, this.CurrentRelativeHumidity);
478
- this.debugLog(`Meter: ${this.accessory.displayName} updateCharacteristic CurrentRelativeHumidity: ${this.CurrentRelativeHumidity}`);
479
- mqttmessage.push(`"humidity": ${this.CurrentRelativeHumidity}`);
480
- entry['humidity'] = this.CurrentRelativeHumidity;
378
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic`
379
+ + ` CurrentRelativeHumidity: ${this.CurrentRelativeHumidity}`);
380
+ if (this.device.mqttURL) {
381
+ mqttmessage.push(`"humidity": ${this.CurrentRelativeHumidity}`);
382
+ }
383
+ if (this.device.history) {
384
+ entry['humidity'] = this.CurrentRelativeHumidity;
385
+ }
481
386
  }
482
387
  }
483
388
  if (!this.device.meter?.hide_temperature) {
484
389
  if (this.CurrentTemperature === undefined) {
485
- this.debugLog(`Meter: ${this.accessory.displayName} CurrentTemperature: ${this.CurrentTemperature}`);
390
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentTemperature: ${this.CurrentTemperature}`);
486
391
  } else {
392
+ if (this.device.mqttURL) {
393
+ mqttmessage.push(`"temperature": ${this.CurrentTemperature}`);
394
+ }
395
+ if (this.device.history) {
396
+ entry['temp'] = this.CurrentTemperature;
397
+ }
398
+ this.accessory.context.CurrentTemperature = this.CurrentTemperature;
487
399
  this.temperatureservice?.updateCharacteristic(this.platform.Characteristic.CurrentTemperature, this.CurrentTemperature);
488
- this.debugLog(`Meter: ${this.accessory.displayName} updateCharacteristic CurrentTemperature: ${this.CurrentTemperature}`);
489
- mqttmessage.push(`"temperature": ${this.CurrentTemperature}`);
490
- entry['temp'] = this.CurrentTemperature;
400
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic CurrentTemperature: ${this.CurrentTemperature}`);
401
+
491
402
  }
492
403
  }
493
- if (this.device.ble) {
404
+ if (this.BLE) {
494
405
  if (this.BatteryLevel === undefined) {
495
- this.debugLog(`Meter: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}`);
406
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}`);
496
407
  } else {
408
+ if (this.device.mqttURL) {
409
+ mqttmessage.push(`"battery": ${this.BatteryLevel}`);
410
+ }
411
+ this.accessory.context.BatteryLevel = this.BatteryLevel;
497
412
  this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, this.BatteryLevel);
498
- this.debugLog(`Meter: ${this.accessory.displayName} updateCharacteristic BatteryLevel: ${this.BatteryLevel}`);
499
- mqttmessage.push(`"battery": ${this.BatteryLevel}`);
413
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic BatteryLevel: ${this.BatteryLevel}`);
500
414
  }
501
415
  if (this.StatusLowBattery === undefined) {
502
- this.debugLog(`Meter: ${this.accessory.displayName} StatusLowBattery: ${this.StatusLowBattery}`);
416
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} StatusLowBattery: ${this.StatusLowBattery}`);
503
417
  } else {
418
+ if (this.device.mqttURL) {
419
+ mqttmessage.push(`"lowBattery": ${this.StatusLowBattery}`);
420
+ }
421
+ this.accessory.context.StatusLowBattery = this.StatusLowBattery;
504
422
  this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, this.StatusLowBattery);
505
- this.debugLog(`Meter: ${this.accessory.displayName} updateCharacteristic StatusLowBattery: ${this.StatusLowBattery}`);
506
- mqttmessage.push(`"lowBattery": ${this.StatusLowBattery}`);
423
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic StatusLowBattery: ${this.StatusLowBattery}`);
507
424
  }
508
425
  }
509
- this.mqttPublish(`{${mqttmessage.join(',')}}`);
426
+ if (this.device.mqttURL) {
427
+ this.mqttPublish(`{${mqttmessage.join(',')}}`);
428
+ }
510
429
  if (this.CurrentRelativeHumidity > 0) {
511
430
  // reject unreliable data
512
- this.historyService?.addEntry(entry);
431
+ if (this.device.history) {
432
+ this.historyService?.addEntry(entry);
433
+ }
434
+ }
435
+ }
436
+
437
+ /*
438
+ * Publish MQTT message for topics of
439
+ * 'homebridge-switchbot/meter/xx:xx:xx:xx:xx:xx'
440
+ */
441
+ mqttPublish(message: any) {
442
+ const mac = this.device.deviceId
443
+ ?.toLowerCase()
444
+ .match(/[\s\S]{1,2}/g)
445
+ ?.join(':');
446
+ const options = this.device.mqttPubOptions || {};
447
+ this.mqttClient?.publish(`homebridge-switchbot/meter/${mac}`, `${message}`, options);
448
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} MQTT message: ${message} options:${superStringify(options)}`);
449
+ }
450
+
451
+ /*
452
+ * Setup MQTT hadler if URL is specifed.
453
+ */
454
+ async setupMqtt(device: device & devicesConfig): Promise<void> {
455
+ if (device.mqttURL) {
456
+ try {
457
+ this.mqttClient = await connectAsync(device.mqttURL, device.mqttOptions || {});
458
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} MQTT connection has been established successfully.`);
459
+ this.mqttClient.on('error', (e: Error) => {
460
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Failed to publish MQTT messages. ${e}`);
461
+ });
462
+ } catch (e) {
463
+ this.mqttClient = null;
464
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Failed to establish MQTT connection. ${e}`);
465
+ }
466
+ }
467
+ }
468
+
469
+ /*
470
+ * Setup EVE history graph feature if enabled.
471
+ */
472
+ async setupHistoryService(device: device & devicesConfig): Promise<void> {
473
+ const mac = this.device
474
+ .deviceId!.match(/.{1,2}/g)!
475
+ .join(':')
476
+ .toLowerCase();
477
+ this.historyService = device.history
478
+ ? new this.platform.fakegatoAPI('room', this.accessory, {
479
+ log: this.platform.log,
480
+ storage: 'fs',
481
+ filename: `${hostname().split('.')[0]}_${mac}_persist.json`,
482
+ })
483
+ : null;
484
+ }
485
+
486
+ async getCustomBLEAddress(switchbot: any) {
487
+ if (this.device.customBLEaddress && this.deviceLogging.includes('debug')) {
488
+ (async () => {
489
+ // Start to monitor advertisement packets
490
+ await switchbot.startScan({
491
+ model: 'T',
492
+ });
493
+ // Set an event handler
494
+ switchbot.onadvertisement = (ad: any) => {
495
+ this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} ad: ${superStringify(ad, null, ' ')}`);
496
+ };
497
+ await switchbot.wait(10000);
498
+ // Stop to monitor
499
+ switchbot.stopScan();
500
+ })();
501
+ }
502
+ }
503
+
504
+ async BLERefreshConnection(switchbot: any): Promise<void> {
505
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} wasn't able to establish BLE Connection, node-switchbot: ${switchbot}`);
506
+ if (this.platform.config.credentials?.token && this.device.connectionType === 'BLE/OpenAPI') {
507
+ this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Using OpenAPI Connection to Refresh Status`);
508
+ await this.openAPIRefreshStatus();
509
+ }
510
+ }
511
+
512
+ async scan(device: device & devicesConfig): Promise<void> {
513
+ if (device.scanDuration) {
514
+ this.scanDuration = this.accessory.context.scanDuration = device.scanDuration;
515
+ if (this.BLE) {
516
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config scanDuration: ${this.scanDuration}`);
517
+ }
518
+ } else {
519
+ this.scanDuration = this.accessory.context.scanDuration = 1;
520
+ if (this.BLE) {
521
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Default scanDuration: ${this.scanDuration}`);
522
+ }
523
+ }
524
+ }
525
+
526
+ async statusCode({ res }: { res: IncomingMessage }): Promise<void> {
527
+ switch (res.statusCode) {
528
+ case 151:
529
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command not supported by this device type.`);
530
+ break;
531
+ case 152:
532
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device not found.`);
533
+ break;
534
+ case 160:
535
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command is not supported.`);
536
+ break;
537
+ case 161:
538
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device is offline.`);
539
+ this.offlineOff();
540
+ break;
541
+ case 171:
542
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} is offline. Hub: ${this.device.hubDeviceId}`);
543
+ this.offlineOff();
544
+ break;
545
+ case 190:
546
+ this.errorLog(
547
+ `${this.device.deviceType}: ${this.accessory.displayName} Device internal error due to device states not synchronized with server,` +
548
+ ` Or command: ${superStringify(res)} format is invalid`,
549
+ );
550
+ break;
551
+ case 100:
552
+ if (this.platform.debugMode) {
553
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Command successfully sent.`);
554
+ }
555
+ break;
556
+ default:
557
+ if (this.platform.debugMode) {
558
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode.`);
559
+ }
560
+ }
561
+ }
562
+
563
+ async offlineOff(): Promise<void> {
564
+ if (this.device.offline) {
565
+ if (!this.device.meter?.hide_humidity) {
566
+ this.humidityservice?.updateCharacteristic(this.platform.Characteristic.CurrentRelativeHumidity,
567
+ this.accessory.context.CurrentRelativeHumidity);
568
+ }
569
+ if (!this.device.meter?.hide_temperature) {
570
+ this.temperatureservice?.updateCharacteristic(this.platform.Characteristic.CurrentTemperature, this.accessory.context.CurrentTemperature);
571
+ }
572
+ if (this.BLE) {
573
+ this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, this.accessory.context.BatteryLevel);
574
+ this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, this.accessory.context.StatusLowBattery);
575
+ }
576
+ await this.updateHomeKitCharacteristics();
513
577
  }
514
578
  }
515
579
 
@@ -520,11 +584,62 @@ export class Meter {
520
584
  if (!this.device.meter?.hide_temperature) {
521
585
  this.temperatureservice?.updateCharacteristic(this.platform.Characteristic.CurrentTemperature, e);
522
586
  }
523
- if (this.device.ble) {
587
+ if (this.BLE) {
524
588
  this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, e);
525
589
  this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, e);
526
590
  }
527
- //throw new this.platform.api.hap.HapStatusError(HAPStatus.SERVICE_COMMUNICATION_FAILURE);
591
+ }
592
+
593
+ FirmwareRevision(accessory: PlatformAccessory<Context>, device: device & devicesConfig): CharacteristicValue {
594
+ let FirmwareRevision: string;
595
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
596
+ + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`);
597
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} device.firmware: ${device.firmware}`);
598
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`);
599
+ if (accessory.context.FirmwareRevision) {
600
+ FirmwareRevision = accessory.context.FirmwareRevision;
601
+ } else if (device.firmware) {
602
+ FirmwareRevision = device.firmware;
603
+ } else {
604
+ FirmwareRevision = this.platform.version;
605
+ }
606
+ return FirmwareRevision;
607
+ }
608
+
609
+ async context() {
610
+ if (this.CurrentRelativeHumidity === undefined) {
611
+ this.CurrentRelativeHumidity = 0;
612
+ } else {
613
+ this.CurrentRelativeHumidity = this.accessory.context.CurrentRelativeHumidity;
614
+ }
615
+ if (this.CurrentTemperature === undefined) {
616
+ this.CurrentTemperature = 0;
617
+ } else {
618
+ this.CurrentTemperature = this.accessory.context.CurrentTemperature;
619
+ }
620
+ if (this.BLE) {
621
+ if (this.BatteryLevel === undefined) {
622
+ this.BatteryLevel = 100;
623
+ } else {
624
+ this.BatteryLevel = this.accessory.context.BatteryLevel;
625
+ }
626
+ if (this.StatusLowBattery === undefined) {
627
+ this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
628
+ this.accessory.context.StatusLowBattery = this.StatusLowBattery;
629
+ } else {
630
+ this.StatusLowBattery = this.accessory.context.StatusLowBattery;
631
+ }
632
+ }
633
+ }
634
+
635
+ async refreshRate(device: device & devicesConfig): Promise<void> {
636
+ if (device.refreshRate) {
637
+ this.deviceRefreshRate = this.accessory.context.refreshRate = device.refreshRate;
638
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config refreshRate: ${this.deviceRefreshRate}`);
639
+ } else if (this.platform.config.options!.refreshRate) {
640
+ this.deviceRefreshRate = this.accessory.context.refreshRate = this.platform.config.options!.refreshRate;
641
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Platform Config refreshRate: ${this.deviceRefreshRate}`);
642
+ }
528
643
  }
529
644
 
530
645
  async config(device: device & devicesConfig): Promise<void> {
@@ -532,8 +647,14 @@ export class Meter {
532
647
  if (device.meter) {
533
648
  config = device.meter;
534
649
  }
535
- if (device.ble !== undefined) {
536
- config['ble'] = device.ble;
650
+ if (device.connectionType !== undefined) {
651
+ config['connectionType'] = device.connectionType;
652
+ }
653
+ if (device.external !== undefined) {
654
+ config['external'] = device.external;
655
+ }
656
+ if (device.mqttURL !== undefined) {
657
+ config['mqttURL'] = device.mqttURL;
537
658
  }
538
659
  if (device.logging !== undefined) {
539
660
  config['logging'] = device.logging;
@@ -545,63 +666,24 @@ export class Meter {
545
666
  config['scanDuration'] = device.scanDuration;
546
667
  }
547
668
  if (Object.entries(config).length !== 0) {
548
- this.infoLog(`Meter: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`);
549
- }
550
- }
551
-
552
- async refreshRate(device: device & devicesConfig): Promise<void> {
553
- if (device.refreshRate) {
554
- this.deviceRefreshRate = this.accessory.context.refreshRate = device.refreshRate;
555
- this.debugLog(`Meter: ${this.accessory.displayName} Using Device Config refreshRate: ${this.deviceRefreshRate}`);
556
- } else if (this.platform.config.options!.refreshRate) {
557
- this.deviceRefreshRate = this.accessory.context.refreshRate = this.platform.config.options!.refreshRate;
558
- this.debugLog(`Meter: ${this.accessory.displayName} Using Platform Config refreshRate: ${this.deviceRefreshRate}`);
559
- }
560
- }
561
-
562
- async scan(device: device & devicesConfig): Promise<void> {
563
- if (device.scanDuration) {
564
- this.scanDuration = this.accessory.context.scanDuration = device.scanDuration;
565
- if (device.ble) {
566
- this.debugLog(`Meter: ${this.accessory.displayName} Using Device Config scanDuration: ${this.scanDuration}`);
567
- }
568
- } else {
569
- this.scanDuration = this.accessory.context.scanDuration = 1;
570
- if (this.device.ble) {
571
- this.debugLog(`Meter: ${this.accessory.displayName} Using Default scanDuration: ${this.scanDuration}`);
572
- }
669
+ this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${superStringify(config)}`);
573
670
  }
574
671
  }
575
672
 
576
673
  async logs(device: device & devicesConfig): Promise<void> {
577
674
  if (this.platform.debugMode) {
578
675
  this.deviceLogging = this.accessory.context.logging = 'debugMode';
579
- this.debugLog(`Meter: ${this.accessory.displayName} Using Debug Mode Logging: ${this.deviceLogging}`);
676
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Debug Mode Logging: ${this.deviceLogging}`);
580
677
  } else if (device.logging) {
581
678
  this.deviceLogging = this.accessory.context.logging = device.logging;
582
- this.debugLog(`Meter: ${this.accessory.displayName} Using Device Config Logging: ${this.deviceLogging}`);
679
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config Logging: ${this.deviceLogging}`);
583
680
  } else if (this.platform.config.options?.logging) {
584
681
  this.deviceLogging = this.accessory.context.logging = this.platform.config.options?.logging;
585
- this.debugLog(`Meter: ${this.accessory.displayName} Using Platform Config Logging: ${this.deviceLogging}`);
682
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Platform Config Logging: ${this.deviceLogging}`);
586
683
  } else {
587
684
  this.deviceLogging = this.accessory.context.logging = 'standard';
588
- this.debugLog(`Meter: ${this.accessory.displayName} Logging Not Set, Using: ${this.deviceLogging}`);
589
- }
590
- }
591
-
592
- FirmwareRevision(accessory: PlatformAccessory<Context>, device: device & devicesConfig): CharacteristicValue {
593
- let FirmwareRevision: string;
594
- this.debugLog(`Meter: ${this.accessory.displayName} accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`);
595
- this.debugLog(`Meter: ${this.accessory.displayName} device.firmware: ${device.firmware}`);
596
- this.debugLog(`Meter: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`);
597
- if (accessory.context.FirmwareRevision) {
598
- FirmwareRevision = accessory.context.FirmwareRevision;
599
- } else if (device.firmware) {
600
- FirmwareRevision = device.firmware;
601
- } else {
602
- FirmwareRevision = this.platform.version;
685
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Logging Not Set, Using: ${this.deviceLogging}`);
603
686
  }
604
- return FirmwareRevision;
605
687
  }
606
688
 
607
689
  /**
@@ -619,12 +701,28 @@ export class Meter {
619
701
  }
620
702
  }
621
703
 
704
+ debugWarnLog(...log: any[]): void {
705
+ if (this.enablingDeviceLogging()) {
706
+ if (this.deviceLogging?.includes('debug')) {
707
+ this.platform.log.warn('[DEBUG]', String(...log));
708
+ }
709
+ }
710
+ }
711
+
622
712
  errorLog(...log: any[]): void {
623
713
  if (this.enablingDeviceLogging()) {
624
714
  this.platform.log.error(String(...log));
625
715
  }
626
716
  }
627
717
 
718
+ debugErrorLog(...log: any[]): void {
719
+ if (this.enablingDeviceLogging()) {
720
+ if (this.deviceLogging?.includes('debug')) {
721
+ this.platform.log.error('[DEBUG]', String(...log));
722
+ }
723
+ }
724
+ }
725
+
628
726
  debugLog(...log: any[]): void {
629
727
  if (this.enablingDeviceLogging()) {
630
728
  if (this.deviceLogging === 'debug') {