@switchbot/homebridge-switchbot 1.3.1-beta.9 → 1.4.1-beta.2

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 (103) hide show
  1. package/CHANGELOG.md +18 -2
  2. package/config.schema.json +82 -32
  3. package/dist/devices/bots.d.ts +15 -3
  4. package/dist/devices/bots.d.ts.map +1 -1
  5. package/dist/devices/bots.js +227 -165
  6. package/dist/devices/bots.js.map +1 -1
  7. package/dist/devices/colorbulb.d.ts +14 -3
  8. package/dist/devices/colorbulb.d.ts.map +1 -1
  9. package/dist/devices/colorbulb.js +163 -105
  10. package/dist/devices/colorbulb.js.map +1 -1
  11. package/dist/devices/contact.d.ts +13 -3
  12. package/dist/devices/contact.d.ts.map +1 -1
  13. package/dist/devices/contact.js +102 -63
  14. package/dist/devices/contact.js.map +1 -1
  15. package/dist/devices/curtains.d.ts +14 -5
  16. package/dist/devices/curtains.d.ts.map +1 -1
  17. package/dist/devices/curtains.js +180 -140
  18. package/dist/devices/curtains.js.map +1 -1
  19. package/dist/devices/humidifiers.d.ts +14 -3
  20. package/dist/devices/humidifiers.d.ts.map +1 -1
  21. package/dist/devices/humidifiers.js +173 -133
  22. package/dist/devices/humidifiers.js.map +1 -1
  23. package/dist/devices/meters.d.ts +17 -13
  24. package/dist/devices/meters.d.ts.map +1 -1
  25. package/dist/devices/meters.js +150 -105
  26. package/dist/devices/meters.js.map +1 -1
  27. package/dist/devices/motion.d.ts +13 -3
  28. package/dist/devices/motion.d.ts.map +1 -1
  29. package/dist/devices/motion.js +89 -45
  30. package/dist/devices/motion.js.map +1 -1
  31. package/dist/devices/plugs.d.ts +15 -3
  32. package/dist/devices/plugs.d.ts.map +1 -1
  33. package/dist/devices/plugs.js +115 -53
  34. package/dist/devices/plugs.js.map +1 -1
  35. package/dist/irdevices/airconditioners.d.ts +13 -3
  36. package/dist/irdevices/airconditioners.d.ts.map +1 -1
  37. package/dist/irdevices/airconditioners.js +97 -46
  38. package/dist/irdevices/airconditioners.js.map +1 -1
  39. package/dist/irdevices/airpurifiers.d.ts +13 -3
  40. package/dist/irdevices/airpurifiers.d.ts.map +1 -1
  41. package/dist/irdevices/airpurifiers.js +85 -31
  42. package/dist/irdevices/airpurifiers.js.map +1 -1
  43. package/dist/irdevices/cameras.d.ts +12 -3
  44. package/dist/irdevices/cameras.d.ts.map +1 -1
  45. package/dist/irdevices/cameras.js +73 -24
  46. package/dist/irdevices/cameras.js.map +1 -1
  47. package/dist/irdevices/fans.d.ts +12 -3
  48. package/dist/irdevices/fans.d.ts.map +1 -1
  49. package/dist/irdevices/fans.js +83 -35
  50. package/dist/irdevices/fans.js.map +1 -1
  51. package/dist/irdevices/lights.d.ts +12 -3
  52. package/dist/irdevices/lights.d.ts.map +1 -1
  53. package/dist/irdevices/lights.js +74 -25
  54. package/dist/irdevices/lights.js.map +1 -1
  55. package/dist/irdevices/others.d.ts +12 -3
  56. package/dist/irdevices/others.d.ts.map +1 -1
  57. package/dist/irdevices/others.js +80 -31
  58. package/dist/irdevices/others.js.map +1 -1
  59. package/dist/irdevices/tvs.d.ts +12 -3
  60. package/dist/irdevices/tvs.d.ts.map +1 -1
  61. package/dist/irdevices/tvs.js +90 -42
  62. package/dist/irdevices/tvs.js.map +1 -1
  63. package/dist/irdevices/vacuumcleaners.d.ts +12 -3
  64. package/dist/irdevices/vacuumcleaners.d.ts.map +1 -1
  65. package/dist/irdevices/vacuumcleaners.js +73 -24
  66. package/dist/irdevices/vacuumcleaners.js.map +1 -1
  67. package/dist/irdevices/waterheaters.d.ts +12 -3
  68. package/dist/irdevices/waterheaters.d.ts.map +1 -1
  69. package/dist/irdevices/waterheaters.js +73 -24
  70. package/dist/irdevices/waterheaters.js.map +1 -1
  71. package/dist/platform.d.ts +10 -10
  72. package/dist/platform.d.ts.map +1 -1
  73. package/dist/platform.js +290 -307
  74. package/dist/platform.js.map +1 -1
  75. package/dist/settings.d.ts +9 -6
  76. package/dist/settings.d.ts.map +1 -1
  77. package/dist/settings.js.map +1 -1
  78. package/nodemon.json +1 -1
  79. package/package.json +6 -6
  80. package/src/devices/bots.ts +221 -152
  81. package/src/devices/colorbulb.ts +172 -108
  82. package/src/devices/contact.ts +109 -64
  83. package/src/devices/curtains.ts +190 -146
  84. package/src/devices/humidifiers.ts +181 -135
  85. package/src/devices/meters.ts +156 -105
  86. package/src/devices/motion.ts +95 -45
  87. package/src/devices/plugs.ts +121 -53
  88. package/src/irdevices/airconditioners.ts +102 -46
  89. package/src/irdevices/airpurifiers.ts +91 -31
  90. package/src/irdevices/cameras.ts +79 -24
  91. package/src/irdevices/fans.ts +89 -36
  92. package/src/irdevices/lights.ts +80 -25
  93. package/src/irdevices/others.ts +86 -31
  94. package/src/irdevices/tvs.ts +96 -42
  95. package/src/irdevices/vacuumcleaners.ts +79 -24
  96. package/src/irdevices/waterheaters.ts +79 -24
  97. package/src/platform.ts +285 -302
  98. package/src/settings.ts +10 -6
  99. package/dist/devices/indoorcam.d.ts +0 -64
  100. package/dist/devices/indoorcam.d.ts.map +0 -1
  101. package/dist/devices/indoorcam.js +0 -249
  102. package/dist/devices/indoorcam.js.map +0 -1
  103. package/src/devices/indoorcam.ts +0 -309
@@ -2,7 +2,7 @@ import Switchbot from 'node-switchbot';
2
2
  import { interval, Subject } from 'rxjs';
3
3
  import { skipWhile } from 'rxjs/operators';
4
4
  import { SwitchBotPlatform } from '../platform';
5
- import { Service, PlatformAccessory, CharacteristicValue } from 'homebridge';
5
+ import { Service, PlatformAccessory, CharacteristicValue, HAPStatus } from 'homebridge';
6
6
  import { DeviceURL, device, devicesConfig, serviceData, switchbot, deviceStatusResponse } from '../settings';
7
7
 
8
8
  /**
@@ -34,8 +34,8 @@ export class Motion {
34
34
  lightLevel!: serviceData['lightLevel'];
35
35
 
36
36
  // Config
37
- private readonly deviceDebug = this.platform.config.options?.debug === 'device' || this.platform.debugMode;
38
- private readonly debugDebug = this.platform.config.options?.debug === 'debug' || this.platform.debugMode;
37
+ deviceLogging!: string;
38
+ deviceRefreshRate!: number;
39
39
 
40
40
  // Updates
41
41
  motionUbpdateInProgress!: boolean;
@@ -47,6 +47,8 @@ export class Motion {
47
47
  public device: device & devicesConfig,
48
48
  ) {
49
49
  // default placeholders
50
+ this.refreshRate();
51
+ this.logs();
50
52
  this.MotionDetected = false;
51
53
 
52
54
  // this is subject we use to track when we need to POST changes to the SwitchBot API
@@ -102,13 +104,31 @@ export class Motion {
102
104
  this.updateHomeKitCharacteristics();
103
105
 
104
106
  // Start an update interval
105
- interval(this.platform.config.options!.refreshRate! * 1000)
107
+ interval(this.deviceRefreshRate * 1000)
106
108
  .pipe(skipWhile(() => this.motionUbpdateInProgress))
107
109
  .subscribe(() => {
108
110
  this.refreshStatus();
109
111
  });
110
112
  }
111
113
 
114
+ refreshRate() {
115
+ if (this.device.refreshRate) {
116
+ this.deviceRefreshRate = this.accessory.context.refreshRate = this.device.refreshRate;
117
+ } else if (this.platform.config.options!.refreshRate) {
118
+ this.deviceRefreshRate = this.accessory.context.refreshRate = this.platform.config.options!.refreshRate;
119
+ }
120
+ }
121
+
122
+ logs() {
123
+ if (this.device.logging) {
124
+ this.deviceLogging = this.accessory.context.logging = this.device.logging;
125
+ } else if (this.platform.config.options?.logging) {
126
+ this.deviceLogging = this.accessory.context.logging = this.platform.config.options?.logging;
127
+ } else {
128
+ this.deviceLogging = this.accessory.context.logging = 'standard';
129
+ }
130
+ }
131
+
112
132
  /**
113
133
  * Parse the device status from the SwitchBot api
114
134
  */
@@ -121,9 +141,9 @@ export class Motion {
121
141
  }
122
142
 
123
143
  private async BLEparseStatus() {
124
- this.platform.device(`Motion Sensor: ${this.accessory.displayName} BLE parseStatus`);
144
+ this.debugLog(`Motion Sensor: ${this.accessory.displayName} BLE parseStatus`);
125
145
  this.MotionDetected = Boolean(this.movement);
126
- this.platform.debug(`Motion Sensor: ${this.accessory.displayName} MotionDetected: ${this.MotionDetected}`);
146
+ this.debugLog(`Motion Sensor: ${this.accessory.displayName} MotionDetected: ${this.MotionDetected}`);
127
147
  // Light Level
128
148
  switch (this.lightLevel) {
129
149
  case 'dark':
@@ -144,9 +164,9 @@ export class Motion {
144
164
 
145
165
  private async openAPIparseStatus() {
146
166
  if (this.platform.config.credentials?.openToken) {
147
- this.platform.device(`Motion Sensor: ${this.accessory.displayName} OpenAPI parseStatus`);
167
+ this.debugLog(`Motion Sensor: ${this.accessory.displayName} OpenAPI parseStatus`);
148
168
  this.MotionDetected = Boolean(this.deviceStatus.body.moveDetected);
149
- this.platform.debug(`Motion Sensor: ${this.accessory.displayName} MotionDetected: ${this.MotionDetected}`);
169
+ this.debugLog(`Motion Sensor: ${this.accessory.displayName} MotionDetected: ${this.MotionDetected}`);
150
170
  }
151
171
  }
152
172
 
@@ -164,12 +184,12 @@ export class Motion {
164
184
  private connectBLE() {
165
185
  const switchbot = new Switchbot();
166
186
  this.device.bleMac = ((this.device.deviceId!.match(/.{1,2}/g))!.join(':')).toLowerCase();
167
- this.platform.device(`Motion Sensor: ${this.accessory.displayName} BLE Address: ${this.device.bleMac}`);
187
+ this.debugLog(`Motion Sensor: ${this.accessory.displayName} BLE Address: ${this.device.bleMac}`);
168
188
  return switchbot;
169
189
  }
170
190
 
171
191
  private async BLERefreshStatus() {
172
- this.platform.debug(`Motion Sensor: ${this.accessory.displayName} BLE RefreshStatus`);
192
+ this.debugLog(`Motion Sensor: ${this.accessory.displayName} BLE RefreshStatus`);
173
193
  // eslint-disable-next-line @typescript-eslint/no-var-requires
174
194
  const switchbot = this.connectBLE();
175
195
  // Start to monitor advertisement packets
@@ -183,16 +203,16 @@ export class Motion {
183
203
  this.movement = ad.serviceData.movement;
184
204
  this.battery = ad.serviceData.battery;
185
205
  this.lightLevel = ad.serviceData.lightLevel;
186
- this.platform.device(`Motion Sensor: ${this.accessory.displayName} serviceData: ${JSON.stringify(ad.serviceData)}`);
187
- this.platform.device(`Motion Sensor: ${this.accessory.displayName} movement: ${ad.serviceData.movement}, lightLevel: `
206
+ this.debugLog(`Motion Sensor: ${this.accessory.displayName} serviceData: ${JSON.stringify(ad.serviceData)}`);
207
+ this.debugLog(`Motion Sensor: ${this.accessory.displayName} movement: ${ad.serviceData.movement}, lightLevel: `
188
208
  + `${ad.serviceData.lightLevel}, battery: ${ad.serviceData.battery}`);
189
209
 
190
210
  if (this.serviceData) {
191
211
  this.connected = true;
192
- this.platform.device(`Motion Sensor: ${this.accessory.displayName} connected: ${this.connected}`);
212
+ this.debugLog(`Motion Sensor: ${this.accessory.displayName} connected: ${this.connected}`);
193
213
  } else {
194
214
  this.connected = false;
195
- this.platform.device(`Motion Sensor: ${this.accessory.displayName} connected: ${this.connected}`);
215
+ this.debugLog(`Motion Sensor: ${this.accessory.displayName} connected: ${this.connected}`);
196
216
  }
197
217
  };
198
218
  // Wait 10 seconds
@@ -204,49 +224,49 @@ export class Motion {
204
224
  this.parseStatus();
205
225
  this.updateHomeKitCharacteristics();
206
226
  } else {
207
- this.platform.log.error(`Motion Sensor: ${this.accessory.displayName} wasn't able to establish BLE Connection`);
227
+ this.errorLog(`Motion Sensor: ${this.accessory.displayName} wasn't able to establish BLE Connection`);
208
228
  if (this.platform.config.credentials?.openToken) {
209
- this.platform.log.warn(`Motion Sensor: ${this.accessory.displayName} Using OpenAPI Connection`);
229
+ this.warnLog(`Motion Sensor: ${this.accessory.displayName} Using OpenAPI Connection`);
210
230
  await this.openAPIRefreshStatus();
211
231
  }
212
232
  }
213
233
  }).catch(async (e: any) => {
214
- this.platform.log.error(`Motion Sensor: ${this.accessory.displayName} failed refreshStatus with BLE Connection`);
215
- if (this.deviceDebug) {
216
- this.platform.log.error(`Motion Sensor: ${this.accessory.displayName} failed refreshStatus with BLE Connection,`
234
+ this.errorLog(`Motion Sensor: ${this.accessory.displayName} failed refreshStatus with BLE Connection`);
235
+ if (this.deviceLogging === 'debug') {
236
+ this.errorLog(`Motion Sensor: ${this.accessory.displayName} failed refreshStatus with BLE Connection,`
217
237
  + ` Error Message: ${JSON.stringify(e.message)}`);
218
238
  }
219
- if (this.debugDebug) {
220
- this.platform.log.error(`Motion Sensor: ${this.accessory.displayName} failed refreshStatus with BLE Connection,`
239
+ if (this.platform.debugMode) {
240
+ this.errorLog(`Motion Sensor: ${this.accessory.displayName} failed refreshStatus with BLE Connection,`
221
241
  + ` Error: ${JSON.stringify(e)}`);
222
242
  }
223
243
  if (this.platform.config.credentials?.openToken) {
224
- this.platform.log.warn(`Motion Sensor: ${this.accessory.displayName} Using OpenAPI Connection`);
244
+ this.warnLog(`Motion Sensor: ${this.accessory.displayName} Using OpenAPI Connection`);
225
245
  await this.openAPIRefreshStatus();
226
246
  }
227
- this.apiError(e);
247
+ this.apiError();
228
248
  });
229
249
  }
230
250
 
231
251
  private async openAPIRefreshStatus() {
232
252
  if (this.platform.config.credentials?.openToken) {
233
- this.platform.debug(`Motion Sensor: ${this.accessory.displayName} OpenAPI RefreshStatus`);
253
+ this.debugLog(`Motion Sensor: ${this.accessory.displayName} OpenAPI RefreshStatus`);
234
254
  try {
235
255
  this.deviceStatus = (await this.platform.axios.get(`${DeviceURL}/${this.device.deviceId}/status`)).data;
236
- this.platform.debug(`Motion Sensor: ${this.accessory.displayName} refreshStatus: ${JSON.stringify(this.deviceStatus)}`);
256
+ this.debugLog(`Motion Sensor: ${this.accessory.displayName} refreshStatus: ${JSON.stringify(this.deviceStatus)}`);
237
257
  this.parseStatus();
238
258
  this.updateHomeKitCharacteristics();
239
259
  } catch (e: any) {
240
- this.platform.log.error(`Motion Sensor: ${this.accessory.displayName} failed refreshStatus with OpenAPI Connection`);
241
- if (this.deviceDebug) {
242
- this.platform.log.error(`Motion Sensor: ${this.accessory.displayName} failed refreshStatus with OpenAPI Connection,`
260
+ this.errorLog(`Motion Sensor: ${this.accessory.displayName} failed refreshStatus with OpenAPI Connection`);
261
+ if (this.deviceLogging === 'debug') {
262
+ this.errorLog(`Motion Sensor: ${this.accessory.displayName} failed refreshStatus with OpenAPI Connection,`
243
263
  + ` Error Message: ${JSON.stringify(e.message)}`);
244
264
  }
245
- if (this.debugDebug) {
246
- this.platform.log.error(`Motion Sensor: ${this.accessory.displayName} failed refreshStatus with OpenAPI Connection,`
265
+ if (this.platform.debugMode) {
266
+ this.errorLog(`Motion Sensor: ${this.accessory.displayName} failed refreshStatus with OpenAPI Connection,`
247
267
  + ` Error: ${JSON.stringify(e)}`);
248
268
  }
249
- this.apiError(e);
269
+ this.apiError();
250
270
  }
251
271
  }
252
272
  }
@@ -256,40 +276,70 @@ export class Motion {
256
276
  */
257
277
  updateHomeKitCharacteristics() {
258
278
  if (this.MotionDetected === undefined) {
259
- this.platform.debug(`Motion Sensor: ${this.accessory.displayName} MotionDetected: ${this.MotionDetected}`);
279
+ this.debugLog(`Motion Sensor: ${this.accessory.displayName} MotionDetected: ${this.MotionDetected}`);
260
280
  } else {
261
281
  this.service.updateCharacteristic(this.platform.Characteristic.MotionDetected, this.MotionDetected);
262
- this.platform.device(`Motion Sensor: ${this.accessory.displayName} updateCharacteristic MotionDetected: ${this.MotionDetected}`);
282
+ this.debugLog(`Motion Sensor: ${this.accessory.displayName} updateCharacteristic MotionDetected: ${this.MotionDetected}`);
263
283
  }
264
284
  if (this.device.ble) {
265
285
  if (this.BatteryLevel === undefined) {
266
- this.platform.debug(`Motion Sensor: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}`);
286
+ this.debugLog(`Motion Sensor: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}`);
267
287
  } else {
268
288
  this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, this.BatteryLevel);
269
- this.platform.device(`Motion Sensor: ${this.accessory.displayName} updateCharacteristic BatteryLevel: ${this.BatteryLevel}`);
289
+ this.debugLog(`Motion Sensor: ${this.accessory.displayName} updateCharacteristic BatteryLevel: ${this.BatteryLevel}`);
270
290
  }
271
291
  if (this.StatusLowBattery === undefined) {
272
- this.platform.debug(`Motion Sensor: ${this.accessory.displayName} StatusLowBattery: ${this.StatusLowBattery}`);
292
+ this.debugLog(`Motion Sensor: ${this.accessory.displayName} StatusLowBattery: ${this.StatusLowBattery}`);
273
293
  } else {
274
294
  this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, this.StatusLowBattery);
275
- this.platform.device(`Motion Sensor: ${this.accessory.displayName} updateCharacteristic StatusLowBattery: ${this.StatusLowBattery}`);
295
+ this.debugLog(`Motion Sensor: ${this.accessory.displayName} updateCharacteristic StatusLowBattery: ${this.StatusLowBattery}`);
276
296
  }
277
297
  if (this.CurrentAmbientLightLevel === undefined) {
278
- this.platform.debug(`Motion Sensor: ${this.accessory.displayName} CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`);
298
+ this.debugLog(`Motion Sensor: ${this.accessory.displayName} CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`);
279
299
  } else {
280
300
  this.lightSensorService?.updateCharacteristic(this.platform.Characteristic.CurrentAmbientLightLevel, this.CurrentAmbientLightLevel);
281
- this.platform.device(`Motion Sensor: ${this.accessory.displayName}`
301
+ this.debugLog(`Motion Sensor: ${this.accessory.displayName}`
282
302
  + ` updateCharacteristic CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`);
283
303
  }
284
304
  }
285
305
  }
286
306
 
287
- public apiError(e: any) {
288
- this.service.updateCharacteristic(this.platform.Characteristic.MotionDetected, e);
289
- if (this.device.ble) {
290
- this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, e);
291
- this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, e);
292
- this.lightSensorService?.updateCharacteristic(this.platform.Characteristic.CurrentAmbientLightLevel, e);
307
+ public apiError() {
308
+ throw new this.platform.api.hap.HapStatusError(HAPStatus.SERVICE_COMMUNICATION_FAILURE);
309
+ }
310
+
311
+ /**
312
+ * Logging for Device
313
+ */
314
+ infoLog(...log: any[]) {
315
+ if (this.enablingDeviceLogging()) {
316
+ this.platform.log.info(String(...log));
293
317
  }
294
318
  }
319
+
320
+ warnLog(...log: any[]) {
321
+ if (this.enablingDeviceLogging()) {
322
+ this.platform.log.warn(String(...log));
323
+ }
324
+ }
325
+
326
+ errorLog(...log: any[]) {
327
+ if (this.enablingDeviceLogging()) {
328
+ this.platform.log.error(String(...log));
329
+ }
330
+ }
331
+
332
+ debugLog(...log: any[]) {
333
+ if (this.enablingDeviceLogging()) {
334
+ if (this.deviceLogging === 'debug') {
335
+ this.platform.log.info('[DEBUG]', String(...log));
336
+ } else {
337
+ this.platform.log.debug(String(...log));
338
+ }
339
+ }
340
+ }
341
+
342
+ enablingDeviceLogging(): boolean {
343
+ return this.deviceLogging === 'debug' || this.deviceLogging === 'standard';
344
+ }
295
345
  }
@@ -3,7 +3,7 @@ import { AxiosResponse } from 'axios';
3
3
  import { interval, Subject } from 'rxjs';
4
4
  import { SwitchBotPlatform } from '../platform';
5
5
  import { debounceTime, skipWhile, take, tap } from 'rxjs/operators';
6
- import { Service, PlatformAccessory, CharacteristicValue } from 'homebridge';
6
+ import { Service, PlatformAccessory, CharacteristicValue, HAPStatus } from 'homebridge';
7
7
  import { DeviceURL, device, devicesConfig, deviceStatusResponse, payload } from '../settings';
8
8
 
9
9
  export class Plug {
@@ -12,13 +12,14 @@ export class Plug {
12
12
 
13
13
  // Characteristic Values
14
14
  On!: CharacteristicValue;
15
+ OnCached!: CharacteristicValue;
15
16
 
16
17
  // OpenAPI Others
17
18
  deviceStatus!: deviceStatusResponse;
18
19
 
19
20
  // Config
20
- private readonly deviceDebug = this.platform.config.options?.debug === 'device' || this.platform.debugMode;
21
- private readonly debugDebug = this.platform.config.options?.debug === 'debug' || this.platform.debugMode;
21
+ deviceLogging!: string;
22
+ deviceRefreshRate!: number;
22
23
 
23
24
  // Updates
24
25
  plugUpdateInProgress!: boolean;
@@ -30,7 +31,16 @@ export class Plug {
30
31
  public device: device & devicesConfig,
31
32
  ) {
32
33
  // default placeholders
33
- this.On = false;
34
+ this.refreshRate();
35
+ this.logs();
36
+ if (this.On === undefined) {
37
+ this.On = false;
38
+ } else {
39
+ this.On = this.accessory.context.On;
40
+ }
41
+
42
+ // Plug Config
43
+ this.debugLog(`Plug: ${this.accessory.displayName} Config: (offline: ${device.offline})`);
34
44
 
35
45
  // this is subject we use to track when we need to POST changes to the SwitchBot API
36
46
  this.doPlugUpdate = new Subject();
@@ -70,7 +80,7 @@ export class Plug {
70
80
  this.updateHomeKitCharacteristics();
71
81
 
72
82
  // Start an update interval
73
- interval(this.platform.config.options!.refreshRate! * 1000)
83
+ interval(this.deviceRefreshRate * 1000)
74
84
  .pipe(skipWhile(() => this.plugUpdateInProgress))
75
85
  .subscribe(() => {
76
86
  this.refreshStatus();
@@ -89,21 +99,39 @@ export class Plug {
89
99
  try {
90
100
  await this.pushChanges();
91
101
  } catch (e: any) {
92
- this.platform.log.error(`Plug: ${this.accessory.displayName} failed pushChanges`);
93
- if (this.deviceDebug) {
94
- this.platform.log.error(`Plug: ${this.accessory.displayName} failed pushChanges,`
102
+ this.errorLog(`Plug: ${this.accessory.displayName} failed pushChanges`);
103
+ if (this.deviceLogging === 'debug') {
104
+ this.errorLog(`Plug: ${this.accessory.displayName} failed pushChanges,`
95
105
  + ` Error Message: ${JSON.stringify(e.message)}`);
96
106
  }
97
- if (this.debugDebug) {
98
- this.platform.log.error(`Plug: ${this.accessory.displayName} failed pushChanges,`
107
+ if (this.platform.debugMode) {
108
+ this.errorLog(`Plug: ${this.accessory.displayName} failed pushChanges,`
99
109
  + ` Error: ${JSON.stringify(e)}`);
100
110
  }
101
- this.apiError(e);
111
+ this.apiError();
102
112
  }
103
113
  this.plugUpdateInProgress = false;
104
114
  });
105
115
  }
106
116
 
117
+ refreshRate() {
118
+ if (this.device.refreshRate) {
119
+ this.deviceRefreshRate = this.accessory.context.refreshRate = this.device.refreshRate;
120
+ } else if (this.platform.config.options!.refreshRate) {
121
+ this.deviceRefreshRate = this.accessory.context.refreshRate = this.platform.config.options!.refreshRate;
122
+ }
123
+ }
124
+
125
+ logs() {
126
+ if (this.device.logging) {
127
+ this.deviceLogging = this.accessory.context.logging = this.device.logging;
128
+ } else if (this.platform.config.options?.logging) {
129
+ this.deviceLogging = this.accessory.context.logging = this.platform.config.options?.logging;
130
+ } else {
131
+ this.deviceLogging = this.accessory.context.logging = 'standard';
132
+ }
133
+ }
134
+
107
135
  parseStatus() {
108
136
  switch (this.deviceStatus.body.power) {
109
137
  case 'on':
@@ -112,26 +140,26 @@ export class Plug {
112
140
  default:
113
141
  this.On = false;
114
142
  }
115
- this.platform.debug(`Plug ${this.accessory.displayName} On: ${this.On}`);
143
+ this.debugLog(`Plug ${this.accessory.displayName} On: ${this.On}`);
116
144
  }
117
145
 
118
146
  private async refreshStatus() {
119
147
  try {
120
148
  this.deviceStatus = (await this.platform.axios.get(`${DeviceURL}/${this.device.deviceId}/status`)).data;
121
- this.platform.device(`Plug: ${this.accessory.displayName} refreshStatus: ${JSON.stringify(this.deviceStatus)}`);
149
+ this.debugLog(`Plug: ${this.accessory.displayName} refreshStatus: ${JSON.stringify(this.deviceStatus)}`);
122
150
  this.parseStatus();
123
151
  this.updateHomeKitCharacteristics();
124
152
  } catch (e: any) {
125
- this.platform.log.error(`Plug: ${this.accessory.displayName} failed refreshStatus with OpenAPI Connection`);
126
- if (this.deviceDebug) {
127
- this.platform.log.error(`Plug: ${this.accessory.displayName} failed refreshStatus with OpenAPI Connection,`
153
+ this.errorLog(`Plug: ${this.accessory.displayName} failed refreshStatus with OpenAPI Connection`);
154
+ if (this.deviceLogging === 'debug') {
155
+ this.errorLog(`Plug: ${this.accessory.displayName} failed refreshStatus with OpenAPI Connection,`
128
156
  + ` Error Message: ${JSON.stringify(e.message)}`);
129
157
  }
130
- if (this.debugDebug) {
131
- this.platform.log.error(`Plug: ${this.accessory.displayName} failed refreshStatus with OpenAPI Connection,`
158
+ if (this.platform.debugMode) {
159
+ this.errorLog(`Plug: ${this.accessory.displayName} failed refreshStatus with OpenAPI Connection,`
132
160
  + ` Error: ${JSON.stringify(e)}`);
133
161
  }
134
- this.apiError(e);
162
+ this.apiError();
135
163
  }
136
164
  }
137
165
 
@@ -142,24 +170,28 @@ export class Plug {
142
170
  * Plug - "command" "turnOn" "default" = set to ON state
143
171
  */
144
172
  async pushChanges() {
145
- const payload = {
146
- commandType: 'command',
147
- parameter: 'default',
148
- } as payload;
173
+ if (this.On !== this.OnCached) {
174
+ const payload = {
175
+ commandType: 'command',
176
+ parameter: 'default',
177
+ } as payload;
149
178
 
150
- if (this.On) {
151
- payload.command = 'turnOn';
152
- } else {
153
- payload.command = 'turnOff';
154
- }
179
+ if (this.On) {
180
+ payload.command = 'turnOn';
181
+ } else {
182
+ payload.command = 'turnOff';
183
+ }
155
184
 
156
- this.platform.log.info(`Plug: ${this.accessory.displayName} Sending request to SwitchBot API. command: ${payload.command},`
157
- + ` parameter: ${payload.parameter}, commandType: ${payload.commandType}`);
185
+ this.infoLog(`Plug: ${this.accessory.displayName} Sending request to SwitchBot API. command: ${payload.command},`
186
+ + ` parameter: ${payload.parameter}, commandType: ${payload.commandType}`);
158
187
 
159
- // Make the API request
160
- const push: any = (await this.platform.axios.post(`${DeviceURL}/${this.device.deviceId}/commands`, payload));
161
- this.platform.debug(`Plug: ${this.accessory.displayName} pushchanges: ${JSON.stringify(push.data)}`);
162
- this.statusCode(push);
188
+ // Make the API request
189
+ const push: any = (await this.platform.axios.post(`${DeviceURL}/${this.device.deviceId}/commands`, payload));
190
+ this.debugLog(`Plug: ${this.accessory.displayName} pushchanges: ${JSON.stringify(push.data)}`);
191
+ this.statusCode(push);
192
+ this.OnCached = this.On;
193
+ this.accessory.context.On = this.OnCached;
194
+ }
163
195
  interval(5000)
164
196
  .pipe(skipWhile(() => this.plugUpdateInProgress))
165
197
  .pipe(take(1))
@@ -170,49 +202,52 @@ export class Plug {
170
202
 
171
203
  updateHomeKitCharacteristics() {
172
204
  if (this.On === undefined) {
173
- this.platform.debug(`Plug: ${this.accessory.displayName} On: ${this.On}`);
205
+ this.debugLog(`Plug: ${this.accessory.displayName} On: ${this.On}`);
174
206
  } else {
175
207
  this.service.updateCharacteristic(this.platform.Characteristic.On, this.On);
176
- this.platform.device(`Plug: ${this.accessory.displayName} updateCharacteristic On: ${this.On}`);
208
+ this.debugLog(`Plug: ${this.accessory.displayName} updateCharacteristic On: ${this.On}`);
177
209
  }
178
210
  }
179
211
 
180
- public apiError(e: any) {
181
- this.service.updateCharacteristic(this.platform.Characteristic.On, e);
212
+ public apiError() {
213
+ throw new this.platform.api.hap.HapStatusError(HAPStatus.SERVICE_COMMUNICATION_FAILURE);
182
214
  }
183
215
 
184
216
  private statusCode(push: AxiosResponse<{ statusCode: number; }>) {
185
217
  switch (push.data.statusCode) {
186
218
  case 151:
187
- this.platform.log.error(`Plug: ${this.accessory.displayName} Command not supported by this device type.`);
219
+ this.errorLog(`Plug: ${this.accessory.displayName} Command not supported by this device type.`);
188
220
  break;
189
221
  case 152:
190
- this.platform.log.error(`Plug: ${this.accessory.displayName} Device not found.`);
222
+ this.errorLog(`Plug: ${this.accessory.displayName} Device not found.`);
191
223
  break;
192
224
  case 160:
193
- this.platform.log.error(`Plug: ${this.accessory.displayName} Command is not supported.`);
225
+ this.errorLog(`Plug: ${this.accessory.displayName} Command is not supported.`);
194
226
  break;
195
227
  case 161:
196
- this.platform.log.error(`Plug: ${this.accessory.displayName} Device is offline.`);
197
- if (this.device.offline) {
198
- this.On = false;
199
- }
228
+ this.errorLog(`Plug: ${this.accessory.displayName} Device is offline.`);
229
+ this.offlineOff();
200
230
  break;
201
231
  case 171:
202
- this.platform.log.error(`Plug: ${this.accessory.displayName} Hub Device is offline. Hub: ${this.device.hubDeviceId}`);
203
- if (this.device.offline) {
204
- this.On = false;
205
- }
232
+ this.errorLog(`Plug: ${this.accessory.displayName} Hub Device is offline. Hub: ${this.device.hubDeviceId}`);
233
+ this.offlineOff();
206
234
  break;
207
235
  case 190:
208
- this.platform.log.error(`Plug: ${this.accessory.displayName} Device internal error due to device states not synchronized with server,`
236
+ this.errorLog(`Plug: ${this.accessory.displayName} Device internal error due to device states not synchronized with server,`
209
237
  + ` Or command: ${JSON.stringify(push.data)} format is invalid`);
210
238
  break;
211
239
  case 100:
212
- this.platform.debug(`Plug: ${this.accessory.displayName} Command successfully sent.`);
240
+ this.debugLog(`Plug: ${this.accessory.displayName} Command successfully sent.`);
213
241
  break;
214
242
  default:
215
- this.platform.debug(`Plug: ${this.accessory.displayName} Unknown statusCode.`);
243
+ this.debugLog(`Plug: ${this.accessory.displayName} Unknown statusCode.`);
244
+ }
245
+ }
246
+
247
+ private offlineOff() {
248
+ if (this.device.offline) {
249
+ this.On = false;
250
+ this.service.getCharacteristic(this.platform.Characteristic.On).updateValue(this.On);
216
251
  }
217
252
  }
218
253
 
@@ -220,11 +255,44 @@ export class Plug {
220
255
  * Handle requests to set the value of the "On" characteristic
221
256
  */
222
257
  OnSet(value: CharacteristicValue) {
223
- this.platform.debug(`Plug: ${this.accessory.displayName} - Set On: ${value}`);
258
+ this.debugLog(`Plug: ${this.accessory.displayName} - Set On: ${value}`);
224
259
 
225
260
  this.On = value;
226
261
  this.doPlugUpdate.next();
227
262
  }
228
263
 
264
+ /**
265
+ * Logging for Device
266
+ */
267
+ infoLog(...log: any[]) {
268
+ if (this.enablingDeviceLogging()) {
269
+ this.platform.log.info(String(...log));
270
+ }
271
+ }
272
+
273
+ warnLog(...log: any[]) {
274
+ if (this.enablingDeviceLogging()) {
275
+ this.platform.log.warn(String(...log));
276
+ }
277
+ }
229
278
 
279
+ errorLog(...log: any[]) {
280
+ if (this.enablingDeviceLogging()) {
281
+ this.platform.log.error(String(...log));
282
+ }
283
+ }
284
+
285
+ debugLog(...log: any[]) {
286
+ if (this.enablingDeviceLogging()) {
287
+ if (this.deviceLogging === 'debug') {
288
+ this.platform.log.info('[DEBUG]', String(...log));
289
+ } else {
290
+ this.platform.log.debug(String(...log));
291
+ }
292
+ }
293
+ }
294
+
295
+ enablingDeviceLogging(): boolean {
296
+ return this.deviceLogging === 'debug' || this.deviceLogging === 'standard';
297
+ }
230
298
  }