@switchbot/homebridge-switchbot 3.5.0-beta.6 → 3.5.0-beta.60

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