@switchbot/homebridge-switchbot 3.5.0-beta.9 → 3.5.1-beta.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.
Files changed (177) hide show
  1. package/.vscode/settings.json +4 -1
  2. package/CHANGELOG.md +4 -1
  3. package/config.schema.json +164 -22
  4. package/dist/device/blindtilt.d.ts +21 -96
  5. package/dist/device/blindtilt.d.ts.map +1 -1
  6. package/dist/device/blindtilt.js +457 -866
  7. package/dist/device/blindtilt.js.map +1 -1
  8. package/dist/device/bot.d.ts +27 -72
  9. package/dist/device/bot.d.ts.map +1 -1
  10. package/dist/device/bot.js +851 -913
  11. package/dist/device/bot.js.map +1 -1
  12. package/dist/device/ceilinglight.d.ts +15 -69
  13. package/dist/device/ceilinglight.d.ts.map +1 -1
  14. package/dist/device/ceilinglight.js +316 -742
  15. package/dist/device/ceilinglight.js.map +1 -1
  16. package/dist/device/colorbulb.d.ts +15 -76
  17. package/dist/device/colorbulb.d.ts.map +1 -1
  18. package/dist/device/colorbulb.js +380 -833
  19. package/dist/device/colorbulb.js.map +1 -1
  20. package/dist/device/contact.d.ts +14 -66
  21. package/dist/device/contact.d.ts.map +1 -1
  22. package/dist/device/contact.js +267 -602
  23. package/dist/device/contact.js.map +1 -1
  24. package/dist/device/curtain.d.ts +18 -89
  25. package/dist/device/curtain.d.ts.map +1 -1
  26. package/dist/device/curtain.js +469 -897
  27. package/dist/device/curtain.js.map +1 -1
  28. package/dist/device/device.d.ts +76 -0
  29. package/dist/device/device.d.ts.map +1 -0
  30. package/dist/device/device.js +846 -0
  31. package/dist/device/device.js.map +1 -0
  32. package/dist/device/fan.d.ts +63 -0
  33. package/dist/device/fan.d.ts.map +1 -0
  34. package/dist/device/fan.js +645 -0
  35. package/dist/device/fan.js.map +1 -0
  36. package/dist/device/hub.d.ts +19 -58
  37. package/dist/device/hub.d.ts.map +1 -1
  38. package/dist/device/hub.js +304 -640
  39. package/dist/device/hub.js.map +1 -1
  40. package/dist/device/humidifier.d.ts +11 -66
  41. package/dist/device/humidifier.d.ts.map +1 -1
  42. package/dist/device/humidifier.js +300 -710
  43. package/dist/device/humidifier.js.map +1 -1
  44. package/dist/device/iosensor.d.ts +12 -64
  45. package/dist/device/iosensor.d.ts.map +1 -1
  46. package/dist/device/iosensor.js +225 -643
  47. package/dist/device/iosensor.js.map +1 -1
  48. package/dist/device/lightstrip.d.ts +12 -70
  49. package/dist/device/lightstrip.d.ts.map +1 -1
  50. package/dist/device/lightstrip.js +371 -742
  51. package/dist/device/lightstrip.js.map +1 -1
  52. package/dist/device/lock.d.ts +17 -63
  53. package/dist/device/lock.d.ts.map +1 -1
  54. package/dist/device/lock.js +309 -642
  55. package/dist/device/lock.js.map +1 -1
  56. package/dist/device/meter.d.ts +15 -64
  57. package/dist/device/meter.d.ts.map +1 -1
  58. package/dist/device/meter.js +223 -638
  59. package/dist/device/meter.js.map +1 -1
  60. package/dist/device/meterplus.d.ts +15 -65
  61. package/dist/device/meterplus.d.ts.map +1 -1
  62. package/dist/device/meterplus.js +216 -644
  63. package/dist/device/meterplus.js.map +1 -1
  64. package/dist/device/motion.d.ts +12 -69
  65. package/dist/device/motion.d.ts.map +1 -1
  66. package/dist/device/motion.js +209 -588
  67. package/dist/device/motion.js.map +1 -1
  68. package/dist/device/plug.d.ts +10 -57
  69. package/dist/device/plug.d.ts.map +1 -1
  70. package/dist/device/plug.js +141 -532
  71. package/dist/device/plug.js.map +1 -1
  72. package/dist/device/robotvacuumcleaner.d.ts +13 -63
  73. package/dist/device/robotvacuumcleaner.d.ts.map +1 -1
  74. package/dist/device/robotvacuumcleaner.js +252 -609
  75. package/dist/device/robotvacuumcleaner.js.map +1 -1
  76. package/dist/device/waterdetector.d.ts +11 -63
  77. package/dist/device/waterdetector.d.ts.map +1 -1
  78. package/dist/device/waterdetector.js +179 -521
  79. package/dist/device/waterdetector.js.map +1 -1
  80. package/dist/homebridge-ui/public/index.html +22 -16
  81. package/dist/homebridge-ui/server.js +1 -1
  82. package/dist/homebridge-ui/server.js.map +1 -1
  83. package/dist/index.d.ts +1 -1
  84. package/dist/index.d.ts.map +1 -1
  85. package/dist/index.js +2 -2
  86. package/dist/index.js.map +1 -1
  87. package/dist/irdevice/airconditioner.d.ts +10 -50
  88. package/dist/irdevice/airconditioner.d.ts.map +1 -1
  89. package/dist/irdevice/airconditioner.js +337 -482
  90. package/dist/irdevice/airconditioner.js.map +1 -1
  91. package/dist/irdevice/airpurifier.d.ts +8 -39
  92. package/dist/irdevice/airpurifier.d.ts.map +1 -1
  93. package/dist/irdevice/airpurifier.js +108 -333
  94. package/dist/irdevice/airpurifier.js.map +1 -1
  95. package/dist/irdevice/camera.d.ts +7 -36
  96. package/dist/irdevice/camera.d.ts.map +1 -1
  97. package/dist/irdevice/camera.js +47 -299
  98. package/dist/irdevice/camera.js.map +1 -1
  99. package/dist/irdevice/fan.d.ts +7 -43
  100. package/dist/irdevice/fan.d.ts.map +1 -1
  101. package/dist/irdevice/fan.js +95 -364
  102. package/dist/irdevice/fan.js.map +1 -1
  103. package/dist/irdevice/irdevice.d.ts +46 -0
  104. package/dist/irdevice/irdevice.d.ts.map +1 -0
  105. package/dist/irdevice/irdevice.js +393 -0
  106. package/dist/irdevice/irdevice.js.map +1 -0
  107. package/dist/irdevice/light.d.ts +12 -45
  108. package/dist/irdevice/light.d.ts.map +1 -1
  109. package/dist/irdevice/light.js +121 -376
  110. package/dist/irdevice/light.js.map +1 -1
  111. package/dist/irdevice/other.d.ts +19 -48
  112. package/dist/irdevice/other.d.ts.map +1 -1
  113. package/dist/irdevice/other.js +441 -584
  114. package/dist/irdevice/other.js.map +1 -1
  115. package/dist/irdevice/tv.d.ts +8 -40
  116. package/dist/irdevice/tv.d.ts.map +1 -1
  117. package/dist/irdevice/tv.js +94 -353
  118. package/dist/irdevice/tv.js.map +1 -1
  119. package/dist/irdevice/vacuumcleaner.d.ts +7 -36
  120. package/dist/irdevice/vacuumcleaner.d.ts.map +1 -1
  121. package/dist/irdevice/vacuumcleaner.js +48 -299
  122. package/dist/irdevice/vacuumcleaner.js.map +1 -1
  123. package/dist/irdevice/waterheater.d.ts +7 -36
  124. package/dist/irdevice/waterheater.d.ts.map +1 -1
  125. package/dist/irdevice/waterheater.js +50 -305
  126. package/dist/irdevice/waterheater.js.map +1 -1
  127. package/dist/platform.d.ts +22 -8
  128. package/dist/platform.d.ts.map +1 -1
  129. package/dist/platform.js +342 -191
  130. package/dist/platform.js.map +1 -1
  131. package/dist/settings.d.ts +66 -18
  132. package/dist/settings.d.ts.map +1 -1
  133. package/dist/settings.js +16 -552
  134. package/dist/settings.js.map +1 -1
  135. package/dist/utils.d.ts +95 -0
  136. package/dist/utils.d.ts.map +1 -1
  137. package/dist/utils.js +657 -1
  138. package/dist/utils.js.map +1 -1
  139. package/eslint.config.js +96 -0
  140. package/package.json +20 -16
  141. package/src/custom.d.ts +2 -1
  142. package/src/device/blindtilt.ts +488 -937
  143. package/src/device/bot.ts +907 -1016
  144. package/src/device/ceilinglight.ts +330 -798
  145. package/src/device/colorbulb.ts +394 -904
  146. package/src/device/contact.ts +298 -637
  147. package/src/device/curtain.ts +496 -954
  148. package/src/device/device.ts +872 -0
  149. package/src/device/fan.ts +692 -0
  150. package/src/device/hub.ts +338 -671
  151. package/src/device/humidifier.ts +330 -777
  152. package/src/device/iosensor.ts +258 -671
  153. package/src/device/lightstrip.ts +394 -809
  154. package/src/device/lock.ts +345 -700
  155. package/src/device/meter.ts +256 -666
  156. package/src/device/meterplus.ts +248 -672
  157. package/src/device/motion.ts +234 -622
  158. package/src/device/plug.ts +152 -572
  159. package/src/device/robotvacuumcleaner.ts +273 -653
  160. package/src/device/waterdetector.ts +198 -549
  161. package/src/homebridge-ui/public/index.html +22 -16
  162. package/src/homebridge-ui/server.ts +1 -1
  163. package/src/index.ts +4 -3
  164. package/src/irdevice/airconditioner.ts +368 -540
  165. package/src/irdevice/airpurifier.ts +134 -369
  166. package/src/irdevice/camera.ts +60 -324
  167. package/src/irdevice/fan.ts +111 -392
  168. package/src/irdevice/irdevice.ts +406 -0
  169. package/src/irdevice/light.ts +159 -425
  170. package/src/irdevice/other.ts +509 -661
  171. package/src/irdevice/tv.ts +123 -388
  172. package/src/irdevice/vacuumcleaner.ts +61 -324
  173. package/src/irdevice/waterheater.ts +63 -333
  174. package/src/platform.ts +395 -259
  175. package/src/settings.ts +120 -610
  176. package/src/utils.ts +661 -1
  177. package/src/device/waterdetector.json +0 -11
@@ -1,112 +1,95 @@
1
- import asyncmqtt from 'async-mqtt';
2
- import { CharacteristicValue, PlatformAccessory, Service, Units, API, Logging, HAP } from 'homebridge';
3
- import { MqttClient } from 'mqtt';
4
- import { hostname } from 'os';
5
- import { interval } from 'rxjs';
6
- import { request } from 'undici';
7
- import { SwitchBotPlatform } from '../platform.js';
8
- import { Devices, device, deviceStatus, devicesConfig, serviceData, temperature, SwitchBotPlatformConfig } from '../settings.js';
9
- import { sleep } from '../utils.js';
10
-
11
- export class Meter {
12
- public readonly api: API;
13
- public readonly log: Logging;
14
- public readonly config!: SwitchBotPlatformConfig;
15
- protected readonly hap: HAP;
1
+ /* Copyright(C) 2021-2024, donavanbecker (https://github.com/donavanbecker). All rights reserved.
2
+ *
3
+ * meter.ts: @switchbot/homebridge-switchbot.
4
+ */
5
+ import { Units } from 'homebridge';
6
+ import { deviceBase } from './device.js';
7
+ import { convertUnits } from '../utils.js';
8
+ import { Subject, interval, skipWhile } from 'rxjs';
9
+
10
+ import type { SwitchBotPlatform } from '../platform.js';
11
+ import type { CharacteristicValue, PlatformAccessory, Service } from 'homebridge';
12
+ import type { device, devicesConfig, serviceData, deviceStatus } from '../settings.js';
13
+
14
+ export class Meter extends deviceBase {
16
15
  // Services
17
- batteryService: Service;
18
- humidityService?: Service;
19
- temperatureService?: Service;
20
-
21
- // Characteristic Values
22
- BatteryLevel!: CharacteristicValue;
23
- FirmwareRevision!: CharacteristicValue;
24
- StatusLowBattery!: CharacteristicValue;
25
- CurrentTemperature?: CharacteristicValue;
26
- CurrentRelativeHumidity?: CharacteristicValue;
27
-
28
- // OpenAPI Status
29
- OpenAPI_BatteryLevel: deviceStatus['battery'];
30
- OpenAPI_FirmwareRevision: deviceStatus['version'];
31
- OpenAPI_CurrentTemperature: deviceStatus['temperature'];
32
- OpenAPI_CurrentRelativeHumidity: deviceStatus['humidity'];
33
-
34
- // BLE Status
35
- BLE_Celsius!: temperature['c'];
36
- BLE_Fahrenheit!: temperature['f'];
37
- BLE_BatteryLevel!: serviceData['battery'];
38
- BLE_CurrentTemperature!: serviceData['temperature'];
39
- BLE_CurrentRelativeHumidity!: serviceData['humidity'];
40
-
41
- // BLE Others
42
- BLE_IsConnected?: boolean;
43
-
44
- //MQTT stuff
45
- mqttClient: MqttClient | null = null;
46
-
47
- // EVE history service handler
48
- historyService?: any;
49
-
50
- // Config
51
- scanDuration!: number;
52
- deviceLogging!: string;
53
- deviceRefreshRate!: number;
54
-
55
- // Connection
56
- private readonly OpenAPI: boolean;
57
- private readonly BLE: boolean;
16
+ private Battery: {
17
+ Name: CharacteristicValue;
18
+ Service: Service;
19
+ BatteryLevel: CharacteristicValue;
20
+ StatusLowBattery: CharacteristicValue;
21
+ };
22
+
23
+ private HumiditySensor?: {
24
+ Name: CharacteristicValue;
25
+ Service: Service;
26
+ CurrentRelativeHumidity: CharacteristicValue;
27
+ };
28
+
29
+ private TemperatureSensor?: {
30
+ Name: CharacteristicValue;
31
+ Service: Service;
32
+ CurrentTemperature: CharacteristicValue;
33
+ };
34
+
35
+ // Updates
36
+ meterUpdateInProgress!: boolean;
37
+ doMeterUpdate: Subject<void>;
58
38
 
59
39
  constructor(
60
- private readonly platform: SwitchBotPlatform,
61
- private accessory: PlatformAccessory,
62
- public device: device & devicesConfig,
40
+ readonly platform: SwitchBotPlatform,
41
+ accessory: PlatformAccessory,
42
+ device: device & devicesConfig,
63
43
  ) {
64
- this.api = this.platform.api;
65
- this.log = this.platform.log;
66
- this.config = this.platform.config;
67
- this.hap = this.api.hap;
68
- // Connection
69
- this.BLE = this.device.connectionType === 'BLE' || this.device.connectionType === 'BLE/OpenAPI';
70
- this.OpenAPI = this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'BLE/OpenAPI';
71
- // default placeholders
72
- this.deviceLogs(device);
73
- this.scan(device);
74
- this.refreshRate(device);
75
- this.deviceContext();
76
- this.setupHistoryService(device);
77
- this.setupMqtt(device);
78
- this.deviceConfig(device);
79
-
80
- this.CurrentRelativeHumidity = accessory.context.CurrentRelativeHumidity;
81
- this.CurrentTemperature = accessory.context.CurrentTemperature;
82
-
83
- // Retrieve initial values and updateHomekit
84
- this.refreshStatus();
44
+ super(platform, accessory, device);
45
+ // this is subject we use to track when we need to POST changes to the SwitchBot API
46
+ this.doMeterUpdate = new Subject();
47
+ this.meterUpdateInProgress = false;
48
+
49
+ // Initialize Battery Service
50
+ accessory.context.Battery = accessory.context.Battery ?? {};
51
+ this.Battery = {
52
+ Name: accessory.context.Battery.Name ?? `${accessory.displayName} Battery`,
53
+ Service: accessory.getService(this.hap.Service.Battery) ?? accessory.addService(this.hap.Service.Battery) as Service,
54
+ BatteryLevel: accessory.context.BatteryLevel ?? 100,
55
+ StatusLowBattery: accessory.context.StatusLowBattery ?? this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL,
56
+ };
57
+ accessory.context.Battery = this.Battery as object;
58
+
59
+ // Initialize Battery Characteristics
60
+ this.Battery.Service
61
+ .setCharacteristic(this.hap.Characteristic.Name, this.Battery.Name)
62
+ .setCharacteristic(this.hap.Characteristic.ChargingState, this.hap.Characteristic.ChargingState.NOT_CHARGEABLE)
63
+ .getCharacteristic(this.hap.Characteristic.BatteryLevel)
64
+ .onGet(() => {
65
+ return this.Battery.BatteryLevel;
66
+ });
85
67
 
86
- // set accessory information
87
- accessory
88
- .getService(this.hap.Service.AccessoryInformation)!
89
- .setCharacteristic(this.hap.Characteristic.Manufacturer, 'SwitchBot')
90
- .setCharacteristic(this.hap.Characteristic.Model, 'METERTH-S1')
91
- .setCharacteristic(this.hap.Characteristic.SerialNumber, device.deviceId)
92
- .setCharacteristic(this.hap.Characteristic.FirmwareRevision, accessory.context.FirmwareRevision);
68
+ this.Battery.Service
69
+ .getCharacteristic(this.hap.Characteristic.StatusLowBattery)
70
+ .onGet(() => {
71
+ return this.Battery.StatusLowBattery;
72
+ });
93
73
 
94
- // Temperature Sensor Service
74
+ // Initialize Temperature Sensor Service
95
75
  if (device.meter?.hide_temperature) {
96
- this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Removing Temperature Sensor Service`);
97
- this.temperatureService = this.accessory.getService(this.hap.Service.TemperatureSensor);
98
- accessory.removeService(this.temperatureService!);
99
- } else if (!this.temperatureService) {
100
- this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Add Temperature Sensor Service`);
101
- const temperatureService = `${accessory.displayName} Temperature Sensor`;
102
- (this.temperatureService = this.accessory.getService(this.hap.Service.TemperatureSensor)
103
- || this.accessory.addService(this.hap.Service.TemperatureSensor)), temperatureService;
104
-
105
- this.temperatureService.setCharacteristic(this.hap.Characteristic.Name, `${accessory.displayName} Temperature Sensor`);
106
- if (!this.temperatureService.testCharacteristic(this.hap.Characteristic.ConfiguredName)) {
107
- this.temperatureService.addCharacteristic(this.hap.Characteristic.ConfiguredName, `${accessory.displayName} Temperature Sensor`);
76
+ if (this.TemperatureSensor) {
77
+ this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Removing Temperature Sensor Service`);
78
+ this.TemperatureSensor.Service = this.accessory.getService(this.hap.Service.TemperatureSensor) as Service;
79
+ accessory.removeService(this.TemperatureSensor.Service);
108
80
  }
109
- this.temperatureService
81
+ } else {
82
+ accessory.context.TemperatureSensor = accessory.context.TemperatureSensor ?? {};
83
+ this.TemperatureSensor = {
84
+ Name: accessory.context.TemperatureSensor.Name ?? `${accessory.displayName} Temperature Sensor`,
85
+ Service: accessory.getService(this.hap.Service.TemperatureSensor) ?? this.accessory.addService(this.hap.Service.TemperatureSensor) as Service,
86
+ CurrentTemperature: accessory.context.CurrentTemperature ?? 30,
87
+ };
88
+ accessory.context.TemperatureSensor = this.TemperatureSensor as object;
89
+
90
+ // Initialize Temperature Sensor Characteristics
91
+ this.TemperatureSensor.Service
92
+ .setCharacteristic(this.hap.Characteristic.Name, this.TemperatureSensor.Name)
110
93
  .getCharacteristic(this.hap.Characteristic.CurrentTemperature)
111
94
  .setProps({
112
95
  unit: Units['CELSIUS'],
@@ -116,168 +99,122 @@ export class Meter {
116
99
  minStep: 0.1,
117
100
  })
118
101
  .onGet(() => {
119
- return this.CurrentTemperature!;
102
+ return this.TemperatureSensor!.CurrentTemperature!;
120
103
  });
121
- } else {
122
- this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Temperature Sensor Service Not Added`);
123
104
  }
124
-
125
- // Humidity Sensor Service
105
+ // Initialize Humidity Sensor Service
126
106
  if (device.meter?.hide_humidity) {
127
- this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Removing Humidity Sensor Service`);
128
- this.humidityService = this.accessory.getService(this.hap.Service.HumiditySensor);
129
- accessory.removeService(this.humidityService!);
130
- } else if (!this.humidityService) {
131
- this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Add Humidity Sensor Service`);
132
- const humidityService = `${accessory.displayName} Humidity Sensor`;
133
- (this.humidityService = this.accessory.getService(this.hap.Service.HumiditySensor)
134
- || this.accessory.addService(this.hap.Service.HumiditySensor)), humidityService;
135
-
136
- this.humidityService.setCharacteristic(this.hap.Characteristic.Name, `${accessory.displayName} Humidity Sensor`);
137
- if (!this.humidityService.testCharacteristic(this.hap.Characteristic.ConfiguredName)) {
138
- this.humidityService.addCharacteristic(this.hap.Characteristic.ConfiguredName, `${accessory.displayName} Humidity Sensor`);
107
+ if (this.HumiditySensor) {
108
+ this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Removing Humidity Sensor Service`);
109
+ this.HumiditySensor.Service = this.accessory.getService(this.hap.Service.HumiditySensor) as Service;
110
+ accessory.removeService(this.HumiditySensor.Service);
139
111
  }
140
- this.humidityService
112
+ } else {
113
+ accessory.context.HumiditySensor = accessory.context.HumiditySensor ?? {};
114
+ this.HumiditySensor = {
115
+ Name: accessory.context.HumiditySensorName ?? `${accessory.displayName} Humidity Sensor`,
116
+ Service: accessory.getService(this.hap.Service.HumiditySensor) ?? this.accessory.addService(this.hap.Service.HumiditySensor) as Service,
117
+ CurrentRelativeHumidity: accessory.context.CurrentRelativeHumidity ?? 50,
118
+ };
119
+ accessory.context.HumiditySensor = this.HumiditySensor as object;
120
+
121
+ // Initialize Humidity Sensor Characteristics
122
+ this.HumiditySensor!.Service
123
+ .setCharacteristic(this.hap.Characteristic.Name, this.HumiditySensor.Name)
141
124
  .getCharacteristic(this.hap.Characteristic.CurrentRelativeHumidity)
142
125
  .setProps({
143
126
  minStep: 0.1,
144
127
  })
145
128
  .onGet(() => {
146
- return this.CurrentRelativeHumidity!;
129
+ return this.HumiditySensor!.CurrentRelativeHumidity!;
147
130
  });
148
- } else {
149
- this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Humidity Sensor Service Not Added`);
150
131
  }
151
132
 
152
- // Battery Service
153
- const batteryService = `${accessory.displayName} Battery`;
154
- (this.batteryService = this.accessory.getService(this.hap.Service.Battery)
155
- || accessory.addService(this.hap.Service.Battery)), batteryService;
156
-
157
- this.batteryService.setCharacteristic(this.hap.Characteristic.Name, `${accessory.displayName} Battery`);
158
- if (!this.batteryService.testCharacteristic(this.hap.Characteristic.ConfiguredName)) {
159
- this.batteryService.addCharacteristic(this.hap.Characteristic.ConfiguredName, `${accessory.displayName} Battery`);
160
- }
161
- this.batteryService.setCharacteristic(this.hap.Characteristic.ChargingState, this.hap.Characteristic.ChargingState.NOT_CHARGEABLE);
133
+ // Retrieve initial values and updateHomekit
134
+ this.refreshStatus();
162
135
 
163
136
  // Retrieve initial values and update Homekit
164
137
  this.updateHomeKitCharacteristics();
165
138
 
166
139
  // Start an update interval
167
140
  interval(this.deviceRefreshRate * 1000)
141
+ .pipe(skipWhile(() => this.meterUpdateInProgress))
168
142
  .subscribe(async () => {
169
143
  await this.refreshStatus();
170
144
  });
171
145
 
172
146
  //regisiter webhook event handler
173
- if (this.device.webhook) {
174
- this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} is listening webhook.`);
175
- this.platform.webhookEventHandler[this.device.deviceId] = async (context) => {
176
- try {
177
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} received Webhook: ${JSON.stringify(context)}`);
178
- if (context.scale === 'CELSIUS') {
179
- const { temperature, humidity } = context;
180
- const { CurrentTemperature, CurrentRelativeHumidity } = this;
181
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ` +
182
- '(temperature, humidity) = ' +
183
- `Webhook:(${temperature}, ${humidity}), ` +
184
- `current:(${CurrentTemperature}, ${CurrentRelativeHumidity})`);
185
- this.CurrentRelativeHumidity = humidity;
186
- this.CurrentTemperature = temperature;
187
- this.updateHomeKitCharacteristics();
188
- }
189
- } catch (e: any) {
190
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} `
191
- + `failed to handle webhook. Received: ${JSON.stringify(context)} Error: ${e}`);
192
- }
193
- };
194
- }
195
- }
196
-
197
- /**
198
- * Parse the device status from the SwitchBot api
199
- */
200
- async parseStatus(): Promise<void> {
201
- if (!this.device.enableCloudService && this.OpenAPI) {
202
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} parseStatus enableCloudService: ${this.device.enableCloudService}`);
203
- } else if (this.BLE) {
204
- await this.BLEparseStatus();
205
- } else if (this.OpenAPI && this.platform.config.credentials?.token) {
206
- await this.openAPIparseStatus();
207
- } else {
208
- await this.offlineOff();
209
- this.debugWarnLog(
210
- `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + ` ${this.device.connectionType}, parseStatus will not happen.`,
211
- );
212
- }
147
+ this.registerWebhook(accessory, device);
213
148
  }
214
149
 
215
- async BLEparseStatus(): Promise<void> {
150
+ async BLEparseStatus(serviceData: serviceData): Promise<void> {
216
151
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEparseStatus`);
217
152
 
218
153
  // BatteryLevel
219
- this.BatteryLevel = Number(this.BLE_BatteryLevel);
220
- if (this.BatteryLevel < 15) {
221
- this.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
154
+ this.Battery.BatteryLevel = Number(serviceData.battery);
155
+ if (this.Battery.BatteryLevel < 15) {
156
+ this.Battery.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
222
157
  } else {
223
- this.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
158
+ this.Battery.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
224
159
  }
225
- this.debugLog(`${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}, StatusLowBattery: ${this.StatusLowBattery}`);
160
+ this.debugLog(`${this.accessory.displayName} BatteryLevel: ${this.Battery.BatteryLevel}, StatusLowBattery: ${this.Battery.StatusLowBattery}`);
226
161
 
227
162
  // CurrentRelativeHumidity
228
163
  if (!this.device.meter?.hide_humidity) {
229
- this.CurrentRelativeHumidity = this.BLE_CurrentRelativeHumidity!;
230
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Humidity: ${this.CurrentRelativeHumidity}%`);
164
+ this.HumiditySensor!.CurrentRelativeHumidity = serviceData.humidity!;
165
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Humidity: ${this.HumiditySensor!.CurrentRelativeHumidity}%`);
231
166
  }
232
167
 
233
- // CurrentTemperature
168
+ // Current Temperature
234
169
  if (!this.device.meter?.hide_temperature) {
235
- this.BLE_Celsius < 0 ? 0 : this.BLE_Celsius > 100 ? 100 : this.BLE_Celsius;
236
- this.CurrentTemperature = this.BLE_Celsius;
237
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Temperature: ${this.CurrentTemperature}°c`);
170
+ const celcius = serviceData.temperature!.c < 0 ? 0 : serviceData.temperature!.c > 100 ? 100 : serviceData.temperature!.c;
171
+ this.TemperatureSensor!.CurrentTemperature = celcius;
172
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Temperature: ${this.TemperatureSensor!.CurrentTemperature}°c`);
238
173
  }
239
174
  }
240
175
 
241
- async openAPIparseStatus(): Promise<void> {
176
+ async openAPIparseStatus(deviceStatus: deviceStatus): Promise<void> {
242
177
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIparseStatus`);
243
178
 
244
- // BatteryLevel
245
- this.BatteryLevel = Number(this.OpenAPI_BatteryLevel);
246
- if (this.BatteryLevel < 15) {
247
- this.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
179
+ // Battery
180
+ this.Battery.BatteryLevel = Number(deviceStatus.body.battery);
181
+ if (this.Battery.BatteryLevel < 10) {
182
+ this.Battery.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
248
183
  } else {
249
- this.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
184
+ this.Battery.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
185
+ }
186
+ if (Number.isNaN(this.Battery.BatteryLevel)) {
187
+ this.Battery.BatteryLevel = 100;
250
188
  }
251
- this.debugLog(`${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}, StatusLowBattery: ${this.StatusLowBattery}`);
189
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.Battery.BatteryLevel},`
190
+ + ` StatusLowBattery: ${this.Battery.StatusLowBattery}`);
252
191
 
253
192
  // CurrentRelativeHumidity
254
193
  if (!this.device.meter?.hide_humidity) {
255
- this.CurrentRelativeHumidity = this.OpenAPI_CurrentRelativeHumidity!;
256
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Humidity: ${this.CurrentRelativeHumidity}%`);
194
+ this.HumiditySensor!.CurrentRelativeHumidity = deviceStatus.body.humidity!;
195
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Humidity: ${this.HumiditySensor!.CurrentRelativeHumidity}%`);
257
196
  }
258
197
 
259
198
  // CurrentTemperature
260
199
  if (!this.device.meter?.hide_temperature) {
261
- this.CurrentTemperature = this.OpenAPI_CurrentTemperature!;
262
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Temperature: ${this.CurrentTemperature}°c`);
263
- }
264
-
265
- // Battery
266
- this.BatteryLevel = Number(this.OpenAPI_BatteryLevel);
267
- if (this.BatteryLevel < 10) {
268
- this.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
269
- } else {
270
- this.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
271
- }
272
- if (Number.isNaN(this.BatteryLevel)) {
273
- this.BatteryLevel = 100;
200
+ this.TemperatureSensor!.CurrentTemperature = deviceStatus.body.temperature!;
201
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Temperature: ${this.TemperatureSensor!.CurrentTemperature}°c`);
202
+ }
203
+
204
+ // Firmware Version
205
+ const version = deviceStatus.body.version?.toString();
206
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Firmware Version: ${version?.replace(/^V|-.*$/g, '')}`);
207
+ if (deviceStatus.body.version) {
208
+ const deviceVersion = version?.replace(/^V|-.*$/g, '') ?? '0.0.0';
209
+ this.accessory
210
+ .getService(this.hap.Service.AccessoryInformation)!
211
+ .setCharacteristic(this.hap.Characteristic.HardwareRevision, deviceVersion)
212
+ .setCharacteristic(this.hap.Characteristic.FirmwareRevision, deviceVersion)
213
+ .getCharacteristic(this.hap.Characteristic.FirmwareRevision)
214
+ .updateValue(deviceVersion);
215
+ this.accessory.context.deviceVersion = deviceVersion;
216
+ this.debugSuccessLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceVersion: ${this.accessory.context.deviceVersion}`);
274
217
  }
275
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel},`
276
- + ` StatusLowBattery: ${this.StatusLowBattery}`);
277
-
278
- // FirmwareRevision
279
- this.FirmwareRevision = this.OpenAPI_FirmwareRevision!;
280
- this.accessory.context.FirmwareRevision = this.FirmwareRevision;
281
218
  }
282
219
 
283
220
  /**
@@ -292,138 +229,84 @@ export class Meter {
292
229
  await this.openAPIRefreshStatus();
293
230
  } else {
294
231
  await this.offlineOff();
295
- this.debugWarnLog(
296
- `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` +
297
- ` ${this.device.connectionType}, refreshStatus will not happen.`,
298
- );
232
+ this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:`
233
+ + ` ${this.device.connectionType}, refreshStatus will not happen.`);
299
234
  }
300
235
  }
301
236
 
302
237
  async BLERefreshStatus(): Promise<void> {
303
238
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLERefreshStatus`);
304
- const switchbot = await this.platform.connectBLE();
305
- // Convert to BLE Address
306
- this.device.bleMac = this.device
307
- .deviceId!.match(/.{1,2}/g)!
308
- .join(':')
309
- .toLowerCase();
310
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLE Address: ${this.device.bleMac}`);
311
- this.getCustomBLEAddress(switchbot);
239
+ const switchbot = await this.switchbotBLE();
240
+
241
+ if (switchbot === undefined) {
242
+ await this.BLERefreshConnection(switchbot);
243
+ } else {
312
244
  // Start to monitor advertisement packets
313
- (async () => {
314
- await switchbot.startScan({
315
- model: 'T',
316
- id: this.device.bleMac,
317
- });
318
- // Set an event handler
319
- switchbot.onadvertisement = (ad: any) => {
320
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ${JSON.stringify(ad, null, ' ')}`);
321
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} address: ${ad.address}, model: ${ad.serviceData.model}`);
322
- if (this.device.bleMac === ad.address && ad.serviceData.model === 'T') {
323
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} serviceData: ${JSON.stringify(ad.serviceData)}`);
324
- this.BLE_CurrentRelativeHumidity = ad.serviceData.humidity < 0 ? 0 : ad.serviceData.humidity > 100 ? 100 : ad.serviceData.humidity;
325
- this.BLE_CurrentTemperature = ad.serviceData.temperature;
326
- this.BLE_Celsius = ad.serviceData.temperature!.c;
327
- this.BLE_Fahrenheit = ad.serviceData.temperature!.f;
328
- this.BLE_BatteryLevel = ad.serviceData.battery;
245
+ (async () => {
246
+ // Start to monitor advertisement packets
247
+ const serviceData: serviceData = await this.monitorAdvertisementPackets(switchbot);
248
+ // Update HomeKit
249
+ if (serviceData.model !== '' && serviceData.modelName !== '') {
250
+ await this.BLEparseStatus(serviceData);
251
+ await this.updateHomeKitCharacteristics();
329
252
  } else {
330
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} serviceData: ${JSON.stringify(ad.serviceData)}`);
331
- }
332
- };
333
- // Wait 1 seconds
334
- await switchbot.wait(this.scanDuration * 1000);
335
- // Stop to monitor
336
- await switchbot.stopScan();
337
- // Update HomeKit
338
- await this.BLEparseStatus();
339
- await this.updateHomeKitCharacteristics();
340
- })();
341
- /*if (switchbot !== false) {
342
- switchbot
343
- .startScan({
344
- model: 'T',
345
- id: this.device.bleMac,
346
- })
347
- .then(async () => {
348
- // Set an event handler
349
- switchbot.onadvertisement = async (ad: ad) => {
350
- this.debugLog(
351
- `${this.device.deviceType}: ${this.accessory.displayName} Config BLE Address: ${this.device.bleMac},` +
352
- ` BLE Address Found: ${ad.address}`,
353
- );
354
- if (ad.serviceData.humidity! > 0) {
355
- // reject unreliable data
356
- this.BLE_CurrentRelativeHumidity = ad.serviceData.humidity;
357
- }
358
- this.BLE_CurrentTemperature = ad.serviceData.temperature;
359
- this.BLE_Celsius = ad.serviceData.temperature!.c;
360
- this.BLE_Fahrenheit = ad.serviceData.temperature!.f;
361
- this.BLE_BatteryLevel = ad.serviceData.battery;
362
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} serviceData: ${JSON.stringify(ad.serviceData)}`);
363
- this.debugLog(
364
- `${this.device.deviceType}: ${this.accessory.displayName} model: ${ad.serviceData.model}, modelName: ${ad.serviceData.modelName}, ` +
365
- `temperature: ${JSON.stringify(ad.serviceData.temperature?.c)}, humidity: ${ad.serviceData.humidity}, ` +
366
- `battery: ${ad.serviceData.battery}`,
367
- );
368
-
369
- if (ad.serviceData) {
370
- this.BLE_IsConnected = true;
371
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} connected: ${this.BLE_IsConnected}`);
372
- await this.stopScanning(switchbot);
373
- } else {
374
- this.BLE_IsConnected = false;
375
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} connected: ${this.BLE_IsConnected}`);
376
- }
377
- };
378
- // Wait
379
- return await sleep(this.scanDuration * 1000);
380
- })
381
- .then(async () => {
382
- // Stop to monitor
383
- await this.stopScanning(switchbot);
384
- })
385
- .catch(async (e: any) => {
386
- this.apiError(e);
387
- this.errorLog(
388
- `${this.device.deviceType}: ${this.accessory.displayName} failed BLERefreshStatus with ${this.device.connectionType}` +
389
- ` Connection, Error Message: ${JSON.stringify(e.message)}`,
390
- );
253
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed to get serviceData, serviceData: ${serviceData}`);
391
254
  await this.BLERefreshConnection(switchbot);
392
- });
393
- } else {
394
- await this.BLERefreshConnection(switchbot);
395
- }*/
255
+ }
256
+ })();
257
+ }
396
258
  }
397
259
 
398
260
  async openAPIRefreshStatus(): Promise<void> {
399
261
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus`);
400
262
  try {
401
- const { body, statusCode } = await request(`${Devices}/${this.device.deviceId}/status`, {
402
- headers: this.platform.generateHeaders(),
403
- });
404
- this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} statusCode: ${statusCode}`);
263
+ const { body, statusCode } = await this.deviceRefreshStatus();
405
264
  const deviceStatus: any = await body.json();
406
- this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus: ${JSON.stringify(deviceStatus)}`);
407
- this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus statusCode: ${deviceStatus.statusCode}`);
265
+ await this.refreshStatusCodes(statusCode, deviceStatus);;
408
266
  if ((statusCode === 200 || statusCode === 100) && (deviceStatus.statusCode === 200 || deviceStatus.statusCode === 100)) {
409
- this.debugErrorLog(`${this.device.deviceType}: ${this.accessory.displayName} `
410
- + `statusCode: ${statusCode} & deviceStatus StatusCode: ${deviceStatus.statusCode}`);
411
- this.OpenAPI_CurrentRelativeHumidity = deviceStatus.body.humidity!;
412
- this.OpenAPI_CurrentTemperature = deviceStatus.body.temperature!;
413
- this.OpenAPI_BatteryLevel = deviceStatus.body.battery;
414
- this.OpenAPI_FirmwareRevision = deviceStatus.body.version;
415
- this.openAPIparseStatus();
416
- this.updateHomeKitCharacteristics();
267
+ await this.successfulRefreshStatus(statusCode, deviceStatus);
268
+ await this.openAPIparseStatus(deviceStatus);
269
+ await this.updateHomeKitCharacteristics();
417
270
  } else {
418
- this.statusCode(statusCode);
419
- this.statusCode(deviceStatus.statusCode);
271
+ await this.statusCodes(statusCode, deviceStatus);
420
272
  }
421
273
  } catch (e: any) {
422
274
  this.apiError(e);
423
- this.errorLog(
424
- `${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}` +
425
- ` Connection, Error Message: ${JSON.stringify(e.message)}`,
426
- );
275
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}`
276
+ + ` Connection, Error Message: ${JSON.stringify(e.message)}`);
277
+ }
278
+ }
279
+
280
+ async registerWebhook(accessory: PlatformAccessory, device: device & devicesConfig) {
281
+ if (device.webhook) {
282
+ this.debugLog(`${device.deviceType}: ${accessory.displayName} is listening webhook.`);
283
+ this.platform.webhookEventHandler[device.deviceId] = async (context) => {
284
+ try {
285
+ this.debugLog(`${device.deviceType}: ${accessory.displayName} received Webhook: ${JSON.stringify(context)}`);
286
+ const { temperature, humidity } = context;
287
+ const { CurrentTemperature } = this.TemperatureSensor ?? { CurrentTemperature: undefined };
288
+ const { CurrentRelativeHumidity } = this.HumiditySensor ?? { CurrentRelativeHumidity: undefined };
289
+ if (context.scale !== 'CELCIUS' && device.meter?.convertUnitTo === undefined) {
290
+ this.warnLog(`${device.deviceType}: ${accessory.displayName} received Webhook scale: `
291
+ + `${context.scale}, instead of CELCIUS. Use the *convertUnitsTo* config under Meter settings, if displaying incorrectly in HomeKit.`);
292
+ }
293
+ this.debugLog(`${device.deviceType}: ${accessory.displayName} ` +
294
+ '(scale, temperature, humidity) = '
295
+ + `Webhook:(${context.scale}, ${convertUnits(temperature, context.scale, device.meter?.convertUnitTo)}, ${humidity}), `
296
+ + `current:(${CurrentTemperature}, ${CurrentRelativeHumidity})`);
297
+ if (!device.meter?.hide_humidity) {
298
+ this.HumiditySensor!.CurrentRelativeHumidity = humidity;
299
+ }
300
+ if (!device.meter?.hide_temperature) {
301
+ this.TemperatureSensor!.CurrentTemperature = convertUnits(temperature, context.scale, device.meter?.convertUnitTo);
302
+ }
303
+ this.updateHomeKitCharacteristics();
304
+ } catch (e: any) {
305
+ this.errorLog(`${device.deviceType}: ${accessory.displayName} failed to handle webhook. Received: ${JSON.stringify(context)} Error: ${e}`);
306
+ }
307
+ };
308
+ } else {
309
+ this.debugLog(`${device.deviceType}: ${accessory.displayName} is not listening webhook.`);
427
310
  }
428
311
  }
429
312
 
@@ -436,64 +319,72 @@ export class Meter {
436
319
 
437
320
  // CurrentRelativeHumidity
438
321
  if (!this.device.meter?.hide_humidity) {
439
- if (this.CurrentRelativeHumidity === undefined) {
440
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentRelativeHumidity: ${this.CurrentRelativeHumidity}`);
322
+ if (this.HumiditySensor!.CurrentRelativeHumidity === undefined) {
323
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
324
+ + ` CurrentRelativeHumidity: ${this.HumiditySensor!.CurrentRelativeHumidity}`);
441
325
  } else {
326
+ this.accessory.context.CurrentRelativeHumidity = this.HumiditySensor!.CurrentRelativeHumidity;
327
+ this.HumiditySensor!.Service.updateCharacteristic(this.hap.Characteristic.CurrentRelativeHumidity,
328
+ this.HumiditySensor!.CurrentRelativeHumidity);
329
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
330
+ + ` updateCharacteristic CurrentRelativeHumidity: ${this.HumiditySensor!.CurrentRelativeHumidity}`);
442
331
  if (this.device.mqttURL) {
443
- mqttmessage.push(`"humidity": ${this.CurrentRelativeHumidity}`);
332
+ mqttmessage.push(`"humidity": ${this.HumiditySensor!.CurrentRelativeHumidity}`);
444
333
  }
445
334
  if (this.device.history) {
446
- entry['humidity'] = this.CurrentRelativeHumidity;
335
+ entry['humidity'] = this.HumiditySensor!.CurrentRelativeHumidity;
447
336
  }
448
- this.accessory.context.CurrentRelativeHumidity = this.CurrentRelativeHumidity;
449
- this.humidityService?.updateCharacteristic(this.hap.Characteristic.CurrentRelativeHumidity, this.CurrentRelativeHumidity);
450
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} `
451
- + `updateCharacteristic CurrentRelativeHumidity: ${this.CurrentRelativeHumidity}`);
452
337
  }
453
338
  }
339
+
454
340
  // CurrentTemperature
455
341
  if (!this.device.meter?.hide_temperature) {
456
- if (this.CurrentTemperature === undefined) {
457
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentTemperature: ${this.CurrentTemperature}`);
342
+ if (this.TemperatureSensor!.CurrentTemperature === undefined) {
343
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentTemperature: ${this.TemperatureSensor!.CurrentTemperature}`);
458
344
  } else {
345
+ this.accessory.context.CurrentTemperature = this.TemperatureSensor!.CurrentTemperature;
346
+ this.TemperatureSensor!.Service.updateCharacteristic(this.hap.Characteristic.CurrentTemperature, this.TemperatureSensor!.CurrentTemperature);
347
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic`
348
+ + ` CurrentTemperature: ${this.TemperatureSensor!.CurrentTemperature}`);
459
349
  if (this.device.mqttURL) {
460
- mqttmessage.push(`"temperature": ${this.CurrentTemperature}`);
350
+ mqttmessage.push(`"temperature": ${this.TemperatureSensor!.CurrentTemperature}`);
461
351
  }
462
352
  if (this.device.history) {
463
- entry['temp'] = this.CurrentTemperature;
353
+ entry['temp'] = this.TemperatureSensor!.CurrentTemperature;
464
354
  }
465
- this.accessory.context.CurrentTemperature = this.CurrentTemperature;
466
- this.temperatureService?.updateCharacteristic(this.hap.Characteristic.CurrentTemperature, this.CurrentTemperature);
467
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic CurrentTemperature: ${this.CurrentTemperature}`);
468
355
  }
469
356
  }
357
+
470
358
  // BatteryLevel
471
- if (this.BatteryLevel === undefined) {
472
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}`);
359
+ if (this.Battery.BatteryLevel === undefined) {
360
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.Battery.BatteryLevel}`);
473
361
  } else {
362
+ this.accessory.context.BatteryLevel = this.Battery.BatteryLevel;
363
+ this.Battery!.Service.updateCharacteristic(this.hap.Characteristic.BatteryLevel, this.Battery.BatteryLevel);
364
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic BatteryLevel: ${this.Battery.BatteryLevel}`);
474
365
  if (this.device.mqttURL) {
475
- mqttmessage.push(`"battery": ${this.BatteryLevel}`);
366
+ mqttmessage.push(`"battery": ${this.Battery.BatteryLevel}`);
476
367
  }
477
- this.accessory.context.BatteryLevel = this.BatteryLevel;
478
- this.batteryService?.updateCharacteristic(this.hap.Characteristic.BatteryLevel, this.BatteryLevel);
479
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic BatteryLevel: ${this.BatteryLevel}`);
480
368
  }
481
- if (this.StatusLowBattery === undefined) {
482
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} StatusLowBattery: ${this.StatusLowBattery}`);
369
+ if (this.Battery.StatusLowBattery === undefined) {
370
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} StatusLowBattery: ${this.Battery.StatusLowBattery}`);
483
371
  } else {
372
+ this.accessory.context.StatusLowBattery = this.Battery.StatusLowBattery;
373
+ this.Battery!.Service.updateCharacteristic(this.hap.Characteristic.StatusLowBattery, this.Battery.StatusLowBattery);
374
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic`
375
+ + ` StatusLowBattery: ${this.Battery.StatusLowBattery}`);
484
376
  if (this.device.mqttURL) {
485
- mqttmessage.push(`"lowBattery": ${this.StatusLowBattery}`);
377
+ mqttmessage.push(`"lowBattery": ${this.Battery.StatusLowBattery}`);
486
378
  }
487
- this.accessory.context.StatusLowBattery = this.StatusLowBattery;
488
- this.batteryService?.updateCharacteristic(this.hap.Characteristic.StatusLowBattery, this.StatusLowBattery);
489
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic StatusLowBattery: ${this.StatusLowBattery}`);
490
379
  }
491
380
 
492
- // MQTT
381
+ // MQTT Publish
493
382
  if (this.device.mqttURL) {
494
383
  this.mqttPublish(`{${mqttmessage.join(',')}}`);
495
384
  }
496
- if (Number(this.CurrentRelativeHumidity) > 0) {
385
+
386
+ // History Service
387
+ if (!this.device.meter?.hide_humidity && (Number(this.HumiditySensor!.CurrentRelativeHumidity) > 0)) {
497
388
  // reject unreliable data
498
389
  if (this.device.history) {
499
390
  this.historyService?.addEntry(entry);
@@ -501,84 +392,6 @@ export class Meter {
501
392
  }
502
393
  }
503
394
 
504
- /*
505
- * Publish MQTT message for topics of
506
- * 'homebridge-switchbot/meter/xx:xx:xx:xx:xx:xx'
507
- */
508
- mqttPublish(message: any) {
509
- const mac = this.device.deviceId
510
- ?.toLowerCase()
511
- .match(/[\s\S]{1,2}/g)
512
- ?.join(':');
513
- const options = this.device.mqttPubOptions || {};
514
- this.mqttClient?.publish(`homebridge-switchbot/meter/${mac}`, `${message}`, options);
515
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} MQTT message: ${message} options:${JSON.stringify(options)}`);
516
- }
517
-
518
- /*
519
- * Setup MQTT hadler if URL is specified.
520
- */
521
- async setupMqtt(device: device & devicesConfig): Promise<void> {
522
- if (device.mqttURL) {
523
- try {
524
- const { connectAsync } = asyncmqtt;
525
- this.mqttClient = await connectAsync(device.mqttURL, device.mqttOptions || {});
526
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} MQTT connection has been established successfully.`);
527
- this.mqttClient.on('error', (e: Error) => {
528
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Failed to publish MQTT messages. ${e}`);
529
- });
530
- } catch (e) {
531
- this.mqttClient = null;
532
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Failed to establish MQTT connection. ${e}`);
533
- }
534
- }
535
- }
536
-
537
- /*
538
- * Setup EVE history graph feature if enabled.
539
- */
540
- async setupHistoryService(device: device & devicesConfig): Promise<void> {
541
- const mac = this.device
542
- .deviceId!.match(/.{1,2}/g)!
543
- .join(':')
544
- .toLowerCase();
545
- this.historyService = device.history
546
- ? new this.platform.fakegatoAPI('room', this.accessory, {
547
- log: this.platform.log,
548
- storage: 'fs',
549
- filename: `${hostname().split('.')[0]}_${mac}_persist.json`,
550
- })
551
- : null;
552
- }
553
-
554
- async stopScanning(switchbot: any) {
555
- switchbot.stopScan();
556
- if (this.BLE_IsConnected) {
557
- await this.BLEparseStatus();
558
- await this.updateHomeKitCharacteristics();
559
- } else {
560
- await this.BLERefreshConnection(switchbot);
561
- }
562
- }
563
-
564
- async getCustomBLEAddress(switchbot: any) {
565
- if (this.device.customBLEaddress && this.deviceLogging.includes('debug')) {
566
- (async () => {
567
- // Start to monitor advertisement packets
568
- await switchbot.startScan({
569
- model: 'T',
570
- });
571
- // Set an event handler
572
- switchbot.onadvertisement = (ad: any) => {
573
- this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} ad: ${JSON.stringify(ad, null, ' ')}`);
574
- };
575
- await sleep(10000);
576
- // Stop to monitor
577
- switchbot.stopScan();
578
- })();
579
- }
580
- }
581
-
582
395
  async BLERefreshConnection(switchbot: any): Promise<void> {
583
396
  this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} wasn't able to establish BLE Connection, node-switchbot:`
584
397
  + ` ${JSON.stringify(switchbot)}`);
@@ -588,249 +401,26 @@ export class Meter {
588
401
  }
589
402
  }
590
403
 
591
- async scan(device: device & devicesConfig): Promise<void> {
592
- if (device.scanDuration) {
593
- this.scanDuration = this.accessory.context.scanDuration = device.scanDuration;
594
- if (this.BLE) {
595
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config scanDuration: ${this.scanDuration}`);
596
- }
597
- } else {
598
- this.scanDuration = this.accessory.context.scanDuration = 1;
599
- if (this.BLE) {
600
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Default scanDuration: ${this.scanDuration}`);
601
- }
602
- }
603
- }
604
-
605
- async statusCode(statusCode: number): Promise<void> {
606
- switch (statusCode) {
607
- case 151:
608
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command not supported by this deviceType, statusCode: ${statusCode}`);
609
- break;
610
- case 152:
611
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device not found, statusCode: ${statusCode}`);
612
- break;
613
- case 160:
614
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command is not supported, statusCode: ${statusCode}`);
615
- break;
616
- case 161:
617
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device is offline, statusCode: ${statusCode}`);
618
- this.offlineOff();
619
- break;
620
- case 171:
621
- this.errorLog(
622
- `${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` +
623
- `Hub: ${this.device.hubDeviceId}`,
624
- );
625
- this.offlineOff();
626
- break;
627
- case 190:
628
- this.errorLog(
629
- `${this.device.deviceType}: ${this.accessory.displayName} Device internal error due to device states not synchronized with server,` +
630
- ` Or command format is invalid, statusCode: ${statusCode}`,
631
- );
632
- break;
633
- case 100:
634
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Command successfully sent, statusCode: ${statusCode}`);
635
- break;
636
- case 200:
637
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Request successful, statusCode: ${statusCode}`);
638
- break;
639
- case 400:
640
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Bad Request, The client has issued an invalid request. `
641
- + `This is commonly used to specify validation errors in a request payload, statusCode: ${statusCode}`);
642
- break;
643
- case 401:
644
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Unauthorized, Authorization for the API is required, `
645
- + `but the request has not been authenticated, statusCode: ${statusCode}`);
646
- break;
647
- case 403:
648
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Forbidden, The request has been authenticated but does not `
649
- + `have appropriate permissions, or a requested resource is not found, statusCode: ${statusCode}`);
650
- break;
651
- case 404:
652
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Not Found, Specifies the requested path does not exist, `
653
- + `statusCode: ${statusCode}`);
654
- break;
655
- case 406:
656
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Not Acceptable, The client has requested a MIME type via `
657
- + `the Accept header for a value not supported by the server, statusCode: ${statusCode}`);
658
- break;
659
- case 415:
660
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Unsupported Media Type, The client has defined a contentType `
661
- + `header that is not supported by the server, statusCode: ${statusCode}`);
662
- break;
663
- case 422:
664
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Unprocessable Entity, The client has made a valid request, `
665
- + `but the server cannot process it. This is often used for APIs for which certain limits have been exceeded, statusCode: ${statusCode}`);
666
- break;
667
- case 429:
668
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Too Many Requests, The client has exceeded the number of `
669
- + `requests allowed for a given time window, statusCode: ${statusCode}`);
670
- break;
671
- case 500:
672
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Internal Server Error, An unexpected error on the SmartThings `
673
- + `servers has occurred. These errors should be rare, statusCode: ${statusCode}`);
674
- break;
675
- default:
676
- this.infoLog(
677
- `${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode: ` +
678
- `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`,
679
- );
680
- }
681
- }
682
-
683
404
  async offlineOff(): Promise<void> {
684
405
  if (this.device.offline) {
685
- await this.deviceContext();
686
- await this.updateHomeKitCharacteristics();
406
+ if (!this.device.meter?.hide_humidity) {
407
+ this.HumiditySensor!.Service.updateCharacteristic(this.hap.Characteristic.CurrentRelativeHumidity, 50);
408
+ }
409
+ if (!this.device.meter?.hide_temperature) {
410
+ this.TemperatureSensor!.Service.updateCharacteristic(this.hap.Characteristic.CurrentTemperature, 30);
411
+ }
412
+ this.Battery.Service.updateCharacteristic(this.hap.Characteristic.BatteryLevel, 100);
687
413
  }
688
414
  }
689
415
 
690
416
  async apiError(e: any): Promise<void> {
691
417
  if (!this.device.meter?.hide_humidity) {
692
- this.humidityService?.updateCharacteristic(this.hap.Characteristic.CurrentRelativeHumidity, e);
418
+ this.HumiditySensor!.Service.updateCharacteristic(this.hap.Characteristic.CurrentRelativeHumidity, e);
693
419
  }
694
420
  if (!this.device.meter?.hide_temperature) {
695
- this.temperatureService?.updateCharacteristic(this.hap.Characteristic.CurrentTemperature, e);
696
- }
697
- this.batteryService?.updateCharacteristic(this.hap.Characteristic.BatteryLevel, e);
698
- this.batteryService?.updateCharacteristic(this.hap.Characteristic.StatusLowBattery, e);
699
- }
700
-
701
- async deviceContext() {
702
- if (this.CurrentRelativeHumidity === undefined) {
703
- this.CurrentRelativeHumidity = 0;
704
- } else {
705
- this.CurrentRelativeHumidity = this.accessory.context.CurrentRelativeHumidity;
706
- }
707
- if (this.CurrentTemperature === undefined) {
708
- this.CurrentTemperature = 0;
709
- } else {
710
- this.CurrentTemperature = this.accessory.context.CurrentTemperature;
711
- }
712
- if (this.BatteryLevel === undefined) {
713
- this.BatteryLevel = 100;
714
- } else {
715
- this.BatteryLevel = this.accessory.context.BatteryLevel;
716
- }
717
- if (this.StatusLowBattery === undefined) {
718
- this.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
719
- this.accessory.context.StatusLowBattery = this.StatusLowBattery;
720
- } else {
721
- this.StatusLowBattery = this.accessory.context.StatusLowBattery;
722
- }
723
- if (this.FirmwareRevision === undefined) {
724
- this.FirmwareRevision = this.platform.version;
725
- this.accessory.context.FirmwareRevision = this.FirmwareRevision;
726
- }
727
- }
728
-
729
- async refreshRate(device: device & devicesConfig): Promise<void> {
730
- if (device.refreshRate) {
731
- this.deviceRefreshRate = this.accessory.context.refreshRate = device.refreshRate;
732
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config refreshRate: ${this.deviceRefreshRate}`);
733
- } else if (this.platform.config.options!.refreshRate) {
734
- this.deviceRefreshRate = this.accessory.context.refreshRate = this.platform.config.options!.refreshRate;
735
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Platform Config refreshRate: ${this.deviceRefreshRate}`);
421
+ this.TemperatureSensor!.Service.updateCharacteristic(this.hap.Characteristic.CurrentTemperature, e);
736
422
  }
737
- }
738
-
739
- async deviceConfig(device: device & devicesConfig): Promise<void> {
740
- let config = {};
741
- if (device.meter) {
742
- config = device.meter;
743
- }
744
- if (device.connectionType !== undefined) {
745
- config['connectionType'] = device.connectionType;
746
- }
747
- if (device.external !== undefined) {
748
- config['external'] = device.external;
749
- }
750
- if (device.mqttURL !== undefined) {
751
- config['mqttURL'] = device.mqttURL;
752
- }
753
- if (device.logging !== undefined) {
754
- config['logging'] = device.logging;
755
- }
756
- if (device.refreshRate !== undefined) {
757
- config['refreshRate'] = device.refreshRate;
758
- }
759
- if (device.scanDuration !== undefined) {
760
- config['scanDuration'] = device.scanDuration;
761
- }
762
- if (device.webhook !== undefined) {
763
- config['webhook'] = device.webhook;
764
- }
765
- if (Object.entries(config).length !== 0) {
766
- this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`);
767
- }
768
- }
769
-
770
- async deviceLogs(device: device & devicesConfig): Promise<void> {
771
- if (this.platform.debugMode) {
772
- this.deviceLogging = this.accessory.context.logging = 'debugMode';
773
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Debug Mode Logging: ${this.deviceLogging}`);
774
- } else if (device.logging) {
775
- this.deviceLogging = this.accessory.context.logging = device.logging;
776
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config Logging: ${this.deviceLogging}`);
777
- } else if (this.platform.config.options?.logging) {
778
- this.deviceLogging = this.accessory.context.logging = this.platform.config.options?.logging;
779
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Platform Config Logging: ${this.deviceLogging}`);
780
- } else {
781
- this.deviceLogging = this.accessory.context.logging = 'standard';
782
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Logging Not Set, Using: ${this.deviceLogging}`);
783
- }
784
- }
785
-
786
- /**
787
- * Logging for Device
788
- */
789
- infoLog(...log: any[]): void {
790
- if (this.enablingDeviceLogging()) {
791
- this.platform.log.info(String(...log));
792
- }
793
- }
794
-
795
- warnLog(...log: any[]): void {
796
- if (this.enablingDeviceLogging()) {
797
- this.platform.log.warn(String(...log));
798
- }
799
- }
800
-
801
- debugWarnLog(...log: any[]): void {
802
- if (this.enablingDeviceLogging()) {
803
- if (this.deviceLogging?.includes('debug')) {
804
- this.platform.log.warn('[DEBUG]', String(...log));
805
- }
806
- }
807
- }
808
-
809
- errorLog(...log: any[]): void {
810
- if (this.enablingDeviceLogging()) {
811
- this.platform.log.error(String(...log));
812
- }
813
- }
814
-
815
- debugErrorLog(...log: any[]): void {
816
- if (this.enablingDeviceLogging()) {
817
- if (this.deviceLogging?.includes('debug')) {
818
- this.platform.log.error('[DEBUG]', String(...log));
819
- }
820
- }
821
- }
822
-
823
- debugLog(...log: any[]): void {
824
- if (this.enablingDeviceLogging()) {
825
- if (this.deviceLogging === 'debug') {
826
- this.platform.log.info('[DEBUG]', String(...log));
827
- } else {
828
- this.platform.log.debug(String(...log));
829
- }
830
- }
831
- }
832
-
833
- enablingDeviceLogging(): boolean {
834
- return this.deviceLogging.includes('debug') || this.deviceLogging === 'standard';
423
+ this.Battery!.Service.updateCharacteristic(this.hap.Characteristic.BatteryLevel, e);
424
+ this.Battery!.Service.updateCharacteristic(this.hap.Characteristic.StatusLowBattery, e);
835
425
  }
836
426
  }