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