@switchbot/homebridge-switchbot 3.5.0-beta.7 → 3.5.0-beta.70

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 +425 -778
  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 +803 -837
  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 +241 -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 +283 -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 +254 -545
  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 +412 -806
  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 +711 -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 +540 -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 +261 -616
  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 +240 -594
  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 +196 -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 +281 -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 +252 -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 +191 -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 +180 -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 +188 -532
  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 +96 -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 +202 -521
  75. package/dist/device/robotvacuumcleaner.js.map +1 -1
  76. package/dist/device/waterdetector.d.ts +10 -63
  77. package/dist/device/waterdetector.d.ts.map +1 -1
  78. package/dist/device/waterdetector.js +146 -475
  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 +324 -452
  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 +93 -307
  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 +39 -281
  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 +113 -341
  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 +118 -362
  110. package/dist/irdevice/light.js.map +1 -1
  111. package/dist/irdevice/other.d.ts +19 -48
  112. package/dist/irdevice/other.d.ts.map +1 -1
  113. package/dist/irdevice/other.js +438 -570
  114. package/dist/irdevice/other.js.map +1 -1
  115. package/dist/irdevice/tv.d.ts +8 -40
  116. package/dist/irdevice/tv.d.ts.map +1 -1
  117. package/dist/irdevice/tv.js +87 -335
  118. package/dist/irdevice/tv.js.map +1 -1
  119. package/dist/irdevice/vacuumcleaner.d.ts +7 -36
  120. package/dist/irdevice/vacuumcleaner.d.ts.map +1 -1
  121. package/dist/irdevice/vacuumcleaner.js +45 -285
  122. package/dist/irdevice/vacuumcleaner.js.map +1 -1
  123. package/dist/irdevice/waterheater.d.ts +7 -36
  124. package/dist/irdevice/waterheater.d.ts.map +1 -1
  125. package/dist/irdevice/waterheater.js +47 -291
  126. package/dist/irdevice/waterheater.js.map +1 -1
  127. package/dist/platform.d.ts +19 -6
  128. package/dist/platform.d.ts.map +1 -1
  129. package/dist/platform.js +310 -172
  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 +462 -817
  143. package/src/device/bot.ts +862 -931
  144. package/src/device/ceilinglight.ts +259 -633
  145. package/src/device/colorbulb.ts +300 -688
  146. package/src/device/contact.ts +288 -571
  147. package/src/device/curtain.ts +441 -838
  148. package/src/device/device.ts +734 -0
  149. package/src/device/fan.ts +596 -0
  150. package/src/device/hub.ts +299 -645
  151. package/src/device/humidifier.ts +274 -647
  152. package/src/device/iosensor.ts +233 -626
  153. package/src/device/lightstrip.ts +309 -620
  154. package/src/device/lock.ts +292 -601
  155. package/src/device/meter.ts +228 -619
  156. package/src/device/meterplus.ts +216 -619
  157. package/src/device/motion.ts +218 -559
  158. package/src/device/plug.ts +111 -490
  159. package/src/device/robotvacuumcleaner.ts +228 -550
  160. package/src/device/waterdetector.ts +169 -501
  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 +350 -477
  165. package/src/irdevice/airpurifier.ts +120 -330
  166. package/src/irdevice/camera.ts +53 -301
  167. package/src/irdevice/fan.ts +130 -360
  168. package/src/irdevice/irdevice.ts +346 -0
  169. package/src/irdevice/light.ts +157 -412
  170. package/src/irdevice/other.ts +507 -648
  171. package/src/irdevice/tv.ts +117 -367
  172. package/src/irdevice/vacuumcleaner.ts +59 -311
  173. package/src/irdevice/waterheater.ts +61 -320
  174. package/src/platform.ts +355 -219
  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,96 @@
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
+ accessory.context.Battery = accessory.context.Battery ?? {};
52
+ this.Battery = {
53
+ Name: accessory.context.Battery.Name ?? `${accessory.displayName} Battery`,
54
+ Service: accessory.getService(this.hap.Service.Battery) ?? accessory.addService(this.hap.Service.Battery) as Service,
55
+ BatteryLevel: accessory.context.BatteryLevel ?? 100,
56
+ StatusLowBattery: accessory.context.StatusLowBattery ?? this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL,
57
+ };
58
+ accessory.context.Battery = this.Battery as object;
59
+
60
+ // Initialize Battery Characteristics
61
+ this.Battery.Service
62
+ .setCharacteristic(this.hap.Characteristic.Name, this.Battery.Name)
63
+ .setCharacteristic(this.hap.Characteristic.ChargingState, this.hap.Characteristic.ChargingState.NOT_CHARGEABLE)
64
+ .getCharacteristic(this.hap.Characteristic.BatteryLevel)
65
+ .onGet(() => {
66
+ return this.Battery.BatteryLevel;
67
+ });
85
68
 
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);
69
+ this.Battery.Service
70
+ .getCharacteristic(this.hap.Characteristic.StatusLowBattery)
71
+ .onGet(() => {
72
+ return this.Battery.StatusLowBattery;
73
+ });
93
74
 
94
- // Temperature Sensor Service
75
+ // Initialize Temperature Sensor Service
95
76
  if (device.meter?.hide_temperature) {
96
- this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Removing Temperature Sensor Service`);
97
- this.temperatureService = this.accessory.getService(this.hap.Service.TemperatureSensor);
98
- accessory.removeService(this.temperatureService!);
99
- } else if (!this.temperatureService) {
100
- this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Add Temperature Sensor Service`);
101
- const temperatureService = `${accessory.displayName} Temperature Sensor`;
102
- (this.temperatureService = this.accessory.getService(this.hap.Service.TemperatureSensor)
103
- || this.accessory.addService(this.hap.Service.TemperatureSensor)), temperatureService;
104
-
105
- this.temperatureService.setCharacteristic(this.hap.Characteristic.Name, `${accessory.displayName} Temperature Sensor`);
106
- if (!this.temperatureService.testCharacteristic(this.hap.Characteristic.ConfiguredName)) {
107
- this.temperatureService.addCharacteristic(this.hap.Characteristic.ConfiguredName, `${accessory.displayName} Temperature Sensor`);
77
+ if (this.TemperatureSensor) {
78
+ this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Removing Temperature Sensor Service`);
79
+ this.TemperatureSensor.Service = this.accessory.getService(this.hap.Service.TemperatureSensor) as Service;
80
+ accessory.removeService(this.TemperatureSensor.Service);
108
81
  }
109
- this.temperatureService
82
+ } else {
83
+ accessory.context.TemperatureSensor = accessory.context.TemperatureSensor ?? {};
84
+ this.TemperatureSensor = {
85
+ Name: accessory.context.TemperatureSensor.Name ?? `${accessory.displayName} Temperature Sensor`,
86
+ Service: accessory.getService(this.hap.Service.TemperatureSensor) ?? this.accessory.addService(this.hap.Service.TemperatureSensor) as Service,
87
+ CurrentTemperature: accessory.context.CurrentTemperature ?? 30,
88
+ };
89
+ accessory.context.TemperatureSensor = this.TemperatureSensor as object;
90
+
91
+ // Initialize Temperature Sensor Characteristics
92
+ this.TemperatureSensor.Service
93
+ .setCharacteristic(this.hap.Characteristic.Name, this.TemperatureSensor.Name)
110
94
  .getCharacteristic(this.hap.Characteristic.CurrentTemperature)
111
95
  .setProps({
112
96
  unit: Units['CELSIUS'],
@@ -116,76 +100,74 @@ export class Meter {
116
100
  minStep: 0.1,
117
101
  })
118
102
  .onGet(() => {
119
- return this.CurrentTemperature!;
103
+ return this.TemperatureSensor!.CurrentTemperature!;
120
104
  });
121
- } else {
122
- this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Temperature Sensor Service Not Added`);
123
105
  }
124
-
125
- // Humidity Sensor Service
106
+ // Initialize Humidity Sensor Service
126
107
  if (device.meter?.hide_humidity) {
127
- this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Removing Humidity Sensor Service`);
128
- this.humidityService = this.accessory.getService(this.hap.Service.HumiditySensor);
129
- accessory.removeService(this.humidityService!);
130
- } else if (!this.humidityService) {
131
- this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Add Humidity Sensor Service`);
132
- const humidityService = `${accessory.displayName} Humidity Sensor`;
133
- (this.humidityService = this.accessory.getService(this.hap.Service.HumiditySensor)
134
- || this.accessory.addService(this.hap.Service.HumiditySensor)), humidityService;
135
-
136
- this.humidityService.setCharacteristic(this.hap.Characteristic.Name, `${accessory.displayName} Humidity Sensor`);
137
- if (!this.humidityService.testCharacteristic(this.hap.Characteristic.ConfiguredName)) {
138
- this.humidityService.addCharacteristic(this.hap.Characteristic.ConfiguredName, `${accessory.displayName} Humidity Sensor`);
108
+ if (this.HumiditySensor) {
109
+ this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Removing Humidity Sensor Service`);
110
+ this.HumiditySensor.Service = this.accessory.getService(this.hap.Service.HumiditySensor) as Service;
111
+ accessory.removeService(this.HumiditySensor.Service);
139
112
  }
140
- this.humidityService
113
+ } else {
114
+ accessory.context.HumiditySensor = accessory.context.HumiditySensor ?? {};
115
+ this.HumiditySensor = {
116
+ Name: accessory.context.HumiditySensorName ?? `${accessory.displayName} Humidity Sensor`,
117
+ Service: accessory.getService(this.hap.Service.HumiditySensor) ?? this.accessory.addService(this.hap.Service.HumiditySensor) as Service,
118
+ CurrentRelativeHumidity: accessory.context.CurrentRelativeHumidity ?? 50,
119
+ };
120
+ accessory.context.HumiditySensor = this.HumiditySensor as object;
121
+
122
+ // Initialize Humidity Sensor Characteristics
123
+ this.HumiditySensor!.Service
124
+ .setCharacteristic(this.hap.Characteristic.Name, this.HumiditySensor.Name)
141
125
  .getCharacteristic(this.hap.Characteristic.CurrentRelativeHumidity)
142
126
  .setProps({
143
127
  minStep: 0.1,
144
128
  })
145
129
  .onGet(() => {
146
- return this.CurrentRelativeHumidity!;
130
+ return this.HumiditySensor!.CurrentRelativeHumidity!;
147
131
  });
148
- } else {
149
- this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Humidity Sensor Service Not Added`);
150
132
  }
151
133
 
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);
134
+ // Retrieve initial values and updateHomekit
135
+ this.refreshStatus();
162
136
 
163
137
  // Retrieve initial values and update Homekit
164
138
  this.updateHomeKitCharacteristics();
165
139
 
166
140
  // Start an update interval
167
141
  interval(this.deviceRefreshRate * 1000)
142
+ .pipe(skipWhile(() => this.meterUpdateInProgress))
168
143
  .subscribe(async () => {
169
144
  await this.refreshStatus();
170
145
  });
171
146
 
172
147
  //regisiter webhook event handler
173
- if (this.device.webhook) {
174
- this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} is listening webhook.`);
148
+ if (device.webhook) {
149
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} is listening webhook.`);
175
150
  this.platform.webhookEventHandler[this.device.deviceId] = async (context) => {
176
151
  try {
177
152
  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();
153
+ const { temperature, humidity } = context;
154
+ const { CurrentTemperature } = this.TemperatureSensor || { CurrentTemperature: undefined };
155
+ const { CurrentRelativeHumidity } = this.HumiditySensor || { CurrentRelativeHumidity: undefined };
156
+ if (context.scale !== 'CELCIUS' && device.meter?.convertUnitTo === undefined) {
157
+ this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} received Webhook scale: `
158
+ + `${context.scale}, instead of CELCIUS. Use the *convertUnitsTo* config under Meter settings, if displaying incorrectly in HomeKit.`);
188
159
  }
160
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ` +
161
+ '(scale, temperature, humidity) = '
162
+ + `Webhook:(${context.scale}, ${convertUnits(temperature, context.scale, device.meter?.convertUnitTo)}, ${humidity}), `
163
+ + `current:(${CurrentTemperature}, ${CurrentRelativeHumidity})`);
164
+ if (this.device.meter?.hide_humidity) {
165
+ this.HumiditySensor!.CurrentRelativeHumidity = humidity;
166
+ }
167
+ if (this.device.meter?.hide_temperature) {
168
+ this.TemperatureSensor!.CurrentTemperature = convertUnits(temperature, context.scale, device.meter?.convertUnitTo);
169
+ }
170
+ this.updateHomeKitCharacteristics();
189
171
  } catch (e: any) {
190
172
  this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} `
191
173
  + `failed to handle webhook. Received: ${JSON.stringify(context)} Error: ${e}`);
@@ -194,90 +176,74 @@ export class Meter {
194
176
  }
195
177
  }
196
178
 
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> {
179
+ async BLEparseStatus(serviceData: serviceData): Promise<void> {
216
180
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEparseStatus`);
217
181
 
218
182
  // BatteryLevel
219
- this.BatteryLevel = Number(this.BLE_BatteryLevel);
220
- if (this.BatteryLevel < 15) {
221
- this.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
183
+ this.Battery.BatteryLevel = Number(serviceData.battery);
184
+ if (this.Battery.BatteryLevel < 15) {
185
+ this.Battery.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
222
186
  } else {
223
- this.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
187
+ this.Battery.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
224
188
  }
225
- this.debugLog(`${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}, StatusLowBattery: ${this.StatusLowBattery}`);
189
+ this.debugLog(`${this.accessory.displayName} BatteryLevel: ${this.Battery.BatteryLevel}, StatusLowBattery: ${this.Battery.StatusLowBattery}`);
226
190
 
227
191
  // CurrentRelativeHumidity
228
192
  if (!this.device.meter?.hide_humidity) {
229
- this.CurrentRelativeHumidity = this.BLE_CurrentRelativeHumidity!;
230
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Humidity: ${this.CurrentRelativeHumidity}%`);
193
+ this.HumiditySensor!.CurrentRelativeHumidity = serviceData.humidity!;
194
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Humidity: ${this.HumiditySensor!.CurrentRelativeHumidity}%`);
231
195
  }
232
196
 
233
197
  // CurrentTemperature
234
198
  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`);
199
+ serviceData.temperature!.c < 0 ? 0 : serviceData.temperature!.c > 100 ? 100 : serviceData.temperature!.c;
200
+ this.TemperatureSensor!.CurrentTemperature = serviceData.temperature!.c;
201
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Temperature: ${this.TemperatureSensor!.CurrentTemperature}°c`);
238
202
  }
239
203
  }
240
204
 
241
- async openAPIparseStatus(): Promise<void> {
205
+ async openAPIparseStatus(deviceStatus: deviceStatus): Promise<void> {
242
206
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIparseStatus`);
243
207
 
244
- // BatteryLevel
245
- this.BatteryLevel = Number(this.OpenAPI_BatteryLevel);
246
- if (this.BatteryLevel < 15) {
247
- this.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
208
+ // Battery
209
+ this.Battery.BatteryLevel = Number(deviceStatus.body.battery);
210
+ if (this.Battery.BatteryLevel < 10) {
211
+ this.Battery.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
248
212
  } else {
249
- this.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
213
+ this.Battery.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
250
214
  }
251
- this.debugLog(`${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}, StatusLowBattery: ${this.StatusLowBattery}`);
215
+ if (Number.isNaN(this.Battery.BatteryLevel)) {
216
+ this.Battery.BatteryLevel = 100;
217
+ }
218
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.Battery.BatteryLevel},`
219
+ + ` StatusLowBattery: ${this.Battery.StatusLowBattery}`);
252
220
 
253
221
  // CurrentRelativeHumidity
254
222
  if (!this.device.meter?.hide_humidity) {
255
- this.CurrentRelativeHumidity = this.OpenAPI_CurrentRelativeHumidity!;
256
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Humidity: ${this.CurrentRelativeHumidity}%`);
223
+ this.HumiditySensor!.CurrentRelativeHumidity = deviceStatus.body.humidity!;
224
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Humidity: ${this.HumiditySensor!.CurrentRelativeHumidity}%`);
257
225
  }
258
226
 
259
227
  // CurrentTemperature
260
228
  if (!this.device.meter?.hide_temperature) {
261
- this.CurrentTemperature = this.OpenAPI_CurrentTemperature!;
262
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Temperature: ${this.CurrentTemperature}°c`);
263
- }
264
-
265
- // Battery
266
- this.BatteryLevel = Number(this.OpenAPI_BatteryLevel);
267
- if (this.BatteryLevel < 10) {
268
- this.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
269
- } else {
270
- this.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
229
+ this.TemperatureSensor!.CurrentTemperature = deviceStatus.body.temperature!;
230
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Temperature: ${this.TemperatureSensor!.CurrentTemperature}°c`);
231
+ }
232
+
233
+ // Firmware Version
234
+ const version = deviceStatus.body.version?.toString();
235
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Firmware Version: ${version?.replace(/^V|-.*$/g, '')}`);
236
+ if (deviceStatus.body.version) {
237
+ const deviceVersion = version?.replace(/^V|-.*$/g, '') ?? '0.0.0';
238
+ this.accessory
239
+ .getService(this.hap.Service.AccessoryInformation)!
240
+ .setCharacteristic(this.hap.Characteristic.HardwareRevision, deviceVersion)
241
+ .setCharacteristic(this.hap.Characteristic.FirmwareRevision, deviceVersion)
242
+ .getCharacteristic(this.hap.Characteristic.FirmwareRevision)
243
+ .updateValue(deviceVersion);
244
+ this.accessory.context.deviceVersion = deviceVersion;
245
+ this.debugSuccessLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceVersion: ${this.accessory.context.deviceVersion}`);
271
246
  }
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
247
  }
282
248
 
283
249
  /**
@@ -311,108 +277,44 @@ export class Meter {
311
277
  this.getCustomBLEAddress(switchbot);
312
278
  // Start to monitor advertisement packets
313
279
  (async () => {
314
- await switchbot.startScan({
315
- model: 'T',
316
- id: this.device.bleMac,
317
- });
280
+ // Start to monitor advertisement packets
281
+ await switchbot.startScan({ model: this.device.bleModel, id: this.device.bleMac });
318
282
  // Set an event handler
319
283
  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') {
284
+ if (this.device.bleMac === ad.address && ad.model === this.device.bleModel) {
285
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ${JSON.stringify(ad, null, ' ')}`);
286
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} address: ${ad.address}, model: ${ad.model}`);
323
287
  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
288
  } else {
330
289
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} serviceData: ${JSON.stringify(ad.serviceData)}`);
331
290
  }
332
291
  };
333
- // Wait 1 seconds
292
+ // Wait 10 seconds
334
293
  await switchbot.wait(this.scanDuration * 1000);
335
294
  // Stop to monitor
336
295
  await switchbot.stopScan();
337
296
  // Update HomeKit
338
- await this.BLEparseStatus();
297
+ await this.BLEparseStatus(switchbot.onadvertisement.serviceData);
339
298
  await this.updateHomeKitCharacteristics();
340
299
  })();
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 {
300
+ if (switchbot === undefined) {
394
301
  await this.BLERefreshConnection(switchbot);
395
- }*/
302
+ }
396
303
  }
397
304
 
398
305
  async openAPIRefreshStatus(): Promise<void> {
399
306
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus`);
400
307
  try {
401
- const { body, statusCode } = await request(`${Devices}/${this.device.deviceId}/status`, {
402
- headers: this.platform.generateHeaders(),
403
- });
308
+ const { body, statusCode } = await this.platform.retryRequest(this.deviceMaxRetries, this.deviceDelayBetweenRetries,
309
+ `${Devices}/${this.device.deviceId}/status`, { headers: this.platform.generateHeaders() });
404
310
  this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} statusCode: ${statusCode}`);
405
311
  const deviceStatus: any = await body.json();
406
312
  this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus: ${JSON.stringify(deviceStatus)}`);
407
313
  this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus statusCode: ${deviceStatus.statusCode}`);
408
314
  if ((statusCode === 200 || statusCode === 100) && (deviceStatus.statusCode === 200 || deviceStatus.statusCode === 100)) {
409
- this.debugErrorLog(`${this.device.deviceType}: ${this.accessory.displayName} `
315
+ this.debugSuccessLog(`${this.device.deviceType}: ${this.accessory.displayName} `
410
316
  + `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();
317
+ this.openAPIparseStatus(deviceStatus);
416
318
  this.updateHomeKitCharacteristics();
417
319
  } else {
418
320
  this.statusCode(statusCode);
@@ -436,64 +338,72 @@ export class Meter {
436
338
 
437
339
  // CurrentRelativeHumidity
438
340
  if (!this.device.meter?.hide_humidity) {
439
- if (this.CurrentRelativeHumidity === undefined) {
440
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentRelativeHumidity: ${this.CurrentRelativeHumidity}`);
341
+ if (this.HumiditySensor!.CurrentRelativeHumidity === undefined) {
342
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
343
+ + ` CurrentRelativeHumidity: ${this.HumiditySensor!.CurrentRelativeHumidity}`);
441
344
  } else {
345
+ this.accessory.context.CurrentRelativeHumidity = this.HumiditySensor!.CurrentRelativeHumidity;
346
+ this.HumiditySensor!.Service.updateCharacteristic(this.hap.Characteristic.CurrentRelativeHumidity,
347
+ this.HumiditySensor!.CurrentRelativeHumidity);
348
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
349
+ + ` updateCharacteristic CurrentRelativeHumidity: ${this.HumiditySensor!.CurrentRelativeHumidity}`);
442
350
  if (this.device.mqttURL) {
443
- mqttmessage.push(`"humidity": ${this.CurrentRelativeHumidity}`);
351
+ mqttmessage.push(`"humidity": ${this.HumiditySensor!.CurrentRelativeHumidity}`);
444
352
  }
445
353
  if (this.device.history) {
446
- entry['humidity'] = this.CurrentRelativeHumidity;
354
+ entry['humidity'] = this.HumiditySensor!.CurrentRelativeHumidity;
447
355
  }
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
356
  }
453
357
  }
358
+
454
359
  // CurrentTemperature
455
360
  if (!this.device.meter?.hide_temperature) {
456
- if (this.CurrentTemperature === undefined) {
457
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentTemperature: ${this.CurrentTemperature}`);
361
+ if (this.TemperatureSensor!.CurrentTemperature === undefined) {
362
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentTemperature: ${this.TemperatureSensor!.CurrentTemperature}`);
458
363
  } else {
364
+ this.accessory.context.CurrentTemperature = this.TemperatureSensor!.CurrentTemperature;
365
+ this.TemperatureSensor!.Service.updateCharacteristic(this.hap.Characteristic.CurrentTemperature, this.TemperatureSensor!.CurrentTemperature);
366
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic`
367
+ + ` CurrentTemperature: ${this.TemperatureSensor!.CurrentTemperature}`);
459
368
  if (this.device.mqttURL) {
460
- mqttmessage.push(`"temperature": ${this.CurrentTemperature}`);
369
+ mqttmessage.push(`"temperature": ${this.TemperatureSensor!.CurrentTemperature}`);
461
370
  }
462
371
  if (this.device.history) {
463
- entry['temp'] = this.CurrentTemperature;
372
+ entry['temp'] = this.TemperatureSensor!.CurrentTemperature;
464
373
  }
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
374
  }
469
375
  }
376
+
470
377
  // BatteryLevel
471
- if (this.BatteryLevel === undefined) {
472
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}`);
378
+ if (this.Battery.BatteryLevel === undefined) {
379
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.Battery.BatteryLevel}`);
473
380
  } else {
381
+ this.accessory.context.BatteryLevel = this.Battery.BatteryLevel;
382
+ this.Battery!.Service.updateCharacteristic(this.hap.Characteristic.BatteryLevel, this.Battery.BatteryLevel);
383
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic BatteryLevel: ${this.Battery.BatteryLevel}`);
474
384
  if (this.device.mqttURL) {
475
- mqttmessage.push(`"battery": ${this.BatteryLevel}`);
385
+ mqttmessage.push(`"battery": ${this.Battery.BatteryLevel}`);
476
386
  }
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
387
  }
481
- if (this.StatusLowBattery === undefined) {
482
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} StatusLowBattery: ${this.StatusLowBattery}`);
388
+ if (this.Battery.StatusLowBattery === undefined) {
389
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} StatusLowBattery: ${this.Battery.StatusLowBattery}`);
483
390
  } else {
391
+ this.accessory.context.StatusLowBattery = this.Battery.StatusLowBattery;
392
+ this.Battery!.Service.updateCharacteristic(this.hap.Characteristic.StatusLowBattery, this.Battery.StatusLowBattery);
393
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic`
394
+ + ` StatusLowBattery: ${this.Battery.StatusLowBattery}`);
484
395
  if (this.device.mqttURL) {
485
- mqttmessage.push(`"lowBattery": ${this.StatusLowBattery}`);
396
+ mqttmessage.push(`"lowBattery": ${this.Battery.StatusLowBattery}`);
486
397
  }
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
398
  }
491
399
 
492
- // MQTT
400
+ // MQTT Publish
493
401
  if (this.device.mqttURL) {
494
402
  this.mqttPublish(`{${mqttmessage.join(',')}}`);
495
403
  }
496
- if (Number(this.CurrentRelativeHumidity) > 0) {
404
+
405
+ // History Service
406
+ if (!this.device.meter?.hide_humidity && (Number(this.HumiditySensor!.CurrentRelativeHumidity) > 0)) {
497
407
  // reject unreliable data
498
408
  if (this.device.history) {
499
409
  this.historyService?.addEntry(entry);
@@ -501,84 +411,6 @@ export class Meter {
501
411
  }
502
412
  }
503
413
 
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
414
  async BLERefreshConnection(switchbot: any): Promise<void> {
583
415
  this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} wasn't able to establish BLE Connection, node-switchbot:`
584
416
  + ` ${JSON.stringify(switchbot)}`);
@@ -588,249 +420,26 @@ export class Meter {
588
420
  }
589
421
  }
590
422
 
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
423
  async offlineOff(): Promise<void> {
684
424
  if (this.device.offline) {
685
- await this.deviceContext();
686
- await this.updateHomeKitCharacteristics();
425
+ if (!this.device.meter?.hide_humidity) {
426
+ this.HumiditySensor!.Service.updateCharacteristic(this.hap.Characteristic.CurrentRelativeHumidity, 50);
427
+ }
428
+ if (!this.device.meter?.hide_temperature) {
429
+ this.TemperatureSensor!.Service.updateCharacteristic(this.hap.Characteristic.CurrentTemperature, 30);
430
+ }
431
+ this.Battery.Service.updateCharacteristic(this.hap.Characteristic.BatteryLevel, 100);
687
432
  }
688
433
  }
689
434
 
690
435
  async apiError(e: any): Promise<void> {
691
436
  if (!this.device.meter?.hide_humidity) {
692
- this.humidityService?.updateCharacteristic(this.hap.Characteristic.CurrentRelativeHumidity, e);
437
+ this.HumiditySensor!.Service.updateCharacteristic(this.hap.Characteristic.CurrentRelativeHumidity, e);
693
438
  }
694
439
  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;
440
+ this.TemperatureSensor!.Service.updateCharacteristic(this.hap.Characteristic.CurrentTemperature, e);
749
441
  }
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';
442
+ this.Battery!.Service.updateCharacteristic(this.hap.Characteristic.BatteryLevel, e);
443
+ this.Battery!.Service.updateCharacteristic(this.hap.Characteristic.StatusLowBattery, e);
835
444
  }
836
445
  }