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