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