@switchbot/homebridge-switchbot 2.0.0-beta.2 → 2.0.0-beta.21

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 (113) hide show
  1. package/CHANGELOG.md +8 -1
  2. package/README.md +1 -2
  3. package/config.schema.json +75 -20
  4. package/dist/device/bot.d.ts +32 -28
  5. package/dist/device/bot.d.ts.map +1 -1
  6. package/dist/device/bot.js +646 -648
  7. package/dist/device/bot.js.map +1 -1
  8. package/dist/device/colorbulb.d.ts +34 -19
  9. package/dist/device/colorbulb.d.ts.map +1 -1
  10. package/dist/device/colorbulb.js +429 -304
  11. package/dist/device/colorbulb.js.map +1 -1
  12. package/dist/device/contact.d.ts +16 -7
  13. package/dist/device/contact.d.ts.map +1 -1
  14. package/dist/device/contact.js +288 -230
  15. package/dist/device/contact.js.map +1 -1
  16. package/dist/device/curtain.d.ts +21 -16
  17. package/dist/device/curtain.d.ts.map +1 -1
  18. package/dist/device/curtain.js +519 -489
  19. package/dist/device/curtain.js.map +1 -1
  20. package/dist/device/humidifier.d.ts +22 -18
  21. package/dist/device/humidifier.d.ts.map +1 -1
  22. package/dist/device/humidifier.js +415 -360
  23. package/dist/device/humidifier.js.map +1 -1
  24. package/dist/device/lock.d.ts +22 -8
  25. package/dist/device/lock.d.ts.map +1 -1
  26. package/dist/device/lock.js +253 -147
  27. package/dist/device/lock.js.map +1 -1
  28. package/dist/device/meter.d.ts +21 -16
  29. package/dist/device/meter.d.ts.map +1 -1
  30. package/dist/device/meter.js +325 -255
  31. package/dist/device/meter.js.map +1 -1
  32. package/dist/device/meterplus.d.ts +23 -12
  33. package/dist/device/meterplus.d.ts.map +1 -1
  34. package/dist/device/meterplus.js +346 -208
  35. package/dist/device/meterplus.js.map +1 -1
  36. package/dist/device/motion.d.ts +17 -8
  37. package/dist/device/motion.d.ts.map +1 -1
  38. package/dist/device/motion.js +261 -209
  39. package/dist/device/motion.js.map +1 -1
  40. package/dist/device/plug.d.ts +24 -16
  41. package/dist/device/plug.d.ts.map +1 -1
  42. package/dist/device/plug.js +267 -242
  43. package/dist/device/plug.js.map +1 -1
  44. package/dist/device/striplight.d.ts +51 -16
  45. package/dist/device/striplight.d.ts.map +1 -1
  46. package/dist/device/striplight.js +527 -185
  47. package/dist/device/striplight.js.map +1 -1
  48. package/dist/irdevice/airconditioner.d.ts +7 -12
  49. package/dist/irdevice/airconditioner.d.ts.map +1 -1
  50. package/dist/irdevice/airconditioner.js +261 -230
  51. package/dist/irdevice/airconditioner.js.map +1 -1
  52. package/dist/irdevice/airpurifier.d.ts +3 -3
  53. package/dist/irdevice/airpurifier.d.ts.map +1 -1
  54. package/dist/irdevice/airpurifier.js +137 -104
  55. package/dist/irdevice/airpurifier.js.map +1 -1
  56. package/dist/irdevice/camera.d.ts +9 -8
  57. package/dist/irdevice/camera.d.ts.map +1 -1
  58. package/dist/irdevice/camera.js +116 -86
  59. package/dist/irdevice/camera.js.map +1 -1
  60. package/dist/irdevice/fan.d.ts +8 -7
  61. package/dist/irdevice/fan.d.ts.map +1 -1
  62. package/dist/irdevice/fan.js +143 -109
  63. package/dist/irdevice/fan.js.map +1 -1
  64. package/dist/irdevice/light.d.ts +9 -8
  65. package/dist/irdevice/light.d.ts.map +1 -1
  66. package/dist/irdevice/light.js +120 -103
  67. package/dist/irdevice/light.js.map +1 -1
  68. package/dist/irdevice/other.d.ts +9 -8
  69. package/dist/irdevice/other.d.ts.map +1 -1
  70. package/dist/irdevice/other.js +128 -98
  71. package/dist/irdevice/other.js.map +1 -1
  72. package/dist/irdevice/tv.d.ts +10 -9
  73. package/dist/irdevice/tv.d.ts.map +1 -1
  74. package/dist/irdevice/tv.js +126 -93
  75. package/dist/irdevice/tv.js.map +1 -1
  76. package/dist/irdevice/vacuumcleaner.d.ts +7 -10
  77. package/dist/irdevice/vacuumcleaner.d.ts.map +1 -1
  78. package/dist/irdevice/vacuumcleaner.js +115 -89
  79. package/dist/irdevice/vacuumcleaner.js.map +1 -1
  80. package/dist/irdevice/waterheater.d.ts +6 -9
  81. package/dist/irdevice/waterheater.d.ts.map +1 -1
  82. package/dist/irdevice/waterheater.js +115 -89
  83. package/dist/irdevice/waterheater.js.map +1 -1
  84. package/dist/platform.d.ts +5 -5
  85. package/dist/platform.d.ts.map +1 -1
  86. package/dist/platform.js +227 -199
  87. package/dist/platform.js.map +1 -1
  88. package/dist/settings.d.ts +15 -11
  89. package/dist/settings.d.ts.map +1 -1
  90. package/dist/settings.js.map +1 -1
  91. package/package.json +12 -10
  92. package/src/device/bot.ts +641 -657
  93. package/src/device/colorbulb.ts +440 -339
  94. package/src/device/contact.ts +289 -233
  95. package/src/device/curtain.ts +523 -503
  96. package/src/device/humidifier.ts +421 -396
  97. package/src/device/lock.ts +257 -147
  98. package/src/device/meter.ts +335 -268
  99. package/src/device/meterplus.ts +354 -213
  100. package/src/device/motion.ts +264 -213
  101. package/src/device/plug.ts +270 -251
  102. package/src/device/striplight.ts +552 -207
  103. package/src/irdevice/airconditioner.ts +263 -241
  104. package/src/irdevice/airpurifier.ts +132 -103
  105. package/src/irdevice/camera.ts +112 -85
  106. package/src/irdevice/fan.ts +138 -106
  107. package/src/irdevice/light.ts +116 -103
  108. package/src/irdevice/other.ts +124 -97
  109. package/src/irdevice/tv.ts +123 -93
  110. package/src/irdevice/vacuumcleaner.ts +112 -89
  111. package/src/irdevice/waterheater.ts +111 -89
  112. package/src/platform.ts +216 -214
  113. package/src/settings.ts +15 -11
@@ -7,6 +7,7 @@ exports.Plug = void 0;
7
7
  const https_1 = __importDefault(require("https"));
8
8
  const crypto_1 = __importDefault(require("crypto"));
9
9
  const rxjs_1 = require("rxjs");
10
+ const super_stringify_1 = __importDefault(require("super-stringify"));
10
11
  const operators_1 = require("rxjs/operators");
11
12
  const settings_1 = require("../settings");
12
13
  class Plug {
@@ -14,17 +15,15 @@ class Plug {
14
15
  this.platform = platform;
15
16
  this.accessory = accessory;
16
17
  this.device = device;
18
+ // Connection
19
+ this.BLE = (this.device.connectionType === 'BLE' || this.device.connectionType === 'Both');
20
+ this.OpenAPI = (this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'Both');
17
21
  // default placeholders
18
22
  this.logs(device);
19
23
  this.scan(device);
20
24
  this.refreshRate(device);
21
25
  this.config(device);
22
- if (this.On === undefined) {
23
- this.On = false;
24
- }
25
- else {
26
- this.On = this.accessory.context.On;
27
- }
26
+ this.context();
28
27
  // this is subject we use to track when we need to POST changes to the SwitchBot API
29
28
  this.doPlugUpdate = new rxjs_1.Subject();
30
29
  this.plugUpdateInProgress = false;
@@ -52,7 +51,7 @@ class Plug {
52
51
  // each service must implement at-minimum the "required characteristics" for the given service type
53
52
  // see https://developers.homebridge.io/#/service/Outlet
54
53
  // create handlers for required characteristics
55
- this.outletService.getCharacteristic(this.platform.Characteristic.On).onSet(this.handleOnSet.bind(this));
54
+ this.outletService.getCharacteristic(this.platform.Characteristic.On).onSet(this.OnSet.bind(this));
56
55
  // Update Homekit
57
56
  this.updateHomeKitCharacteristics();
58
57
  // Start an update interval
@@ -72,25 +71,31 @@ class Plug {
72
71
  await this.pushChanges();
73
72
  }
74
73
  catch (e) {
75
- this.errorLog(`Plug: ${this.accessory.displayName} failed pushChanges`);
76
- if (this.deviceLogging.includes('debug')) {
77
- this.errorLog(`Plug: ${this.accessory.displayName} failed pushChanges,` + ` Error Message: ${JSON.stringify(e.message)}`);
78
- }
79
74
  this.apiError(e);
75
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType} Connection,`
76
+ + ` Error Message: ${(0, super_stringify_1.default)(e.message)}`);
80
77
  }
81
78
  this.plugUpdateInProgress = false;
82
79
  });
83
80
  }
81
+ /**
82
+ * Parse the device status from the SwitchBot api
83
+ */
84
84
  async parseStatus() {
85
- if (this.SwitchToOpenAPI || !this.device.ble) {
85
+ if (this.BLE && !this.SwitchToOpenAPI) {
86
+ await this.BLEparseStatus();
87
+ }
88
+ else if (this.OpenAPI && this.platform.config.credentials?.token) {
89
+ this.SwitchToOpenAPI = false;
86
90
  await this.openAPIparseStatus();
87
91
  }
88
92
  else {
89
- await this.BLEparseStatus();
93
+ this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:`
94
+ + ` ${this.device.connectionType}, parseStatus will not happen.`);
90
95
  }
91
96
  }
92
97
  async BLEparseStatus() {
93
- this.debugLog(`Plug: ${this.accessory.displayName} BLE parseStatus`);
98
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEparseStatus`);
94
99
  // State
95
100
  switch (this.state) {
96
101
  case 'on':
@@ -99,9 +104,10 @@ class Plug {
99
104
  default:
100
105
  this.On = false;
101
106
  }
102
- this.debugLog(`Plug: ${this.accessory.displayName} On: ${this.On}`);
107
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
103
108
  }
104
109
  async openAPIparseStatus() {
110
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIparseStatus`);
105
111
  switch (this.power) {
106
112
  case 'on':
107
113
  this.On = true;
@@ -109,25 +115,32 @@ class Plug {
109
115
  default:
110
116
  this.On = false;
111
117
  }
112
- this.debugLog(`Plug: ${this.accessory.displayName} On: ${this.On}`);
118
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
113
119
  }
120
+ /**
121
+ * Asks the SwitchBot API for the latest device information
122
+ */
114
123
  async refreshStatus() {
115
- if (this.device.ble) {
124
+ if (this.BLE) {
116
125
  await this.BLERefreshStatus();
117
126
  }
118
- else {
127
+ else if (this.OpenAPI && this.platform.config.credentials?.token) {
119
128
  await this.openAPIRefreshStatus();
120
129
  }
130
+ else {
131
+ this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:`
132
+ + ` ${this.device.connectionType}, refreshStatus will not happen.`);
133
+ }
121
134
  }
122
135
  async BLERefreshStatus() {
123
- this.debugLog(`Plug: ${this.accessory.displayName} BLE refreshStatus`);
136
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLERefreshStatus`);
124
137
  const switchbot = await this.platform.connectBLE();
125
138
  // Convert to BLE Address
126
139
  this.device.bleMac = this.device
127
140
  .deviceId.match(/.{1,2}/g)
128
141
  .join(':')
129
142
  .toLowerCase();
130
- this.debugLog(`Plug: ${this.accessory.displayName} BLE Address: ${this.device.bleMac}`);
143
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLE Address: ${this.device.bleMac}`);
131
144
  this.getCustomBLEAddress(switchbot);
132
145
  // Start to monitor advertisement packets
133
146
  if (switchbot !== false) {
@@ -143,8 +156,8 @@ class Plug {
143
156
  if (this.deviceLogging.includes('debug')) {
144
157
  this.infoLog(this.address);
145
158
  this.infoLog(this.device.bleMac);
146
- this.infoLog(`Plug: ${this.accessory.displayName} BLE Address Found: ${this.address}`);
147
- this.infoLog(`Plug: ${this.accessory.displayName} Config BLE Address: ${this.device.bleMac}`);
159
+ this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} BLE Address Found: ${this.address}`);
160
+ this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Config BLE Address: ${this.device.bleMac}`);
148
161
  }
149
162
  this.serviceData = ad.serviceData;
150
163
  this.state = ad.serviceData.state;
@@ -154,17 +167,17 @@ class Plug {
154
167
  this.wifiRssi = ad.serviceData.wifiRssi;
155
168
  this.overload = ad.serviceData.overload;
156
169
  this.currentPower = ad.serviceData.currentPower;
157
- this.debugLog(`Plug: ${this.accessory.displayName} serviceData: ${JSON.stringify(ad.serviceData)}`);
158
- this.debugLog(`Plug: ${this.accessory.displayName} state: ${ad.serviceData.state}, ` +
170
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} serviceData: ${(0, super_stringify_1.default)(ad.serviceData)}`);
171
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} state: ${ad.serviceData.state}, ` +
159
172
  `delay: ${ad.serviceData.delay}, timer: ${ad.serviceData.timer}, syncUtcTime: ${ad.serviceData.syncUtcTime} ` +
160
173
  `wifiRssi: ${ad.serviceData.wifiRssi}, overload: ${ad.serviceData.overload}, currentPower: ${ad.serviceData.currentPower}`);
161
174
  if (this.serviceData) {
162
175
  this.connected = true;
163
- this.debugLog(`Plug: ${this.accessory.displayName} connected: ${this.connected}`);
176
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} connected: ${this.connected}`);
164
177
  }
165
178
  else {
166
179
  this.connected = false;
167
- this.debugLog(`Plug: ${this.accessory.displayName} connected: ${this.connected}`);
180
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} connected: ${this.connected}`);
168
181
  }
169
182
  };
170
183
  // Wait 2 seconds
@@ -182,63 +195,25 @@ class Plug {
182
195
  }
183
196
  })
184
197
  .catch(async (e) => {
185
- this.errorLog(`Plug: ${this.accessory.displayName} failed refreshStatus with BLE Connection`);
186
- if (this.deviceLogging.includes('debug')) {
187
- this.errorLog(`Plug: ${this.accessory.displayName} failed refreshStatus with BLE Connection,` + ` Error Message: ${JSON.stringify(e.message)}`);
188
- }
189
- if (this.platform.config.credentials?.token) {
190
- this.warnLog(`Plug: ${this.accessory.displayName} Using OpenAPI Connection`);
191
- this.SwitchToOpenAPI = true;
192
- await this.openAPIRefreshStatus();
193
- }
194
198
  this.apiError(e);
199
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLERefreshStatus with ${this.device.connectionType}`
200
+ + ` Connection, Error Message: ${(0, super_stringify_1.default)(e.message)}`);
201
+ await this.BLEconnection(switchbot);
195
202
  });
196
203
  }
197
204
  else {
198
205
  await this.BLEconnection(switchbot);
199
206
  }
200
207
  }
201
- BLEmodel() {
202
- if (this.device.deviceType === 'Plug Mini (US)') {
203
- return 'g';
204
- }
205
- else {
206
- return 'j';
207
- }
208
- }
209
- async getCustomBLEAddress(switchbot) {
210
- if (this.device.customBLEaddress && this.deviceLogging.includes('debug')) {
211
- (async () => {
212
- // Start to monitor advertisement packets
213
- await switchbot.startScan({
214
- model: this.BLEmodel(),
215
- });
216
- // Set an event handler
217
- switchbot.onadvertisement = (ad) => {
218
- this.warnLog(`Plug: ${this.accessory.displayName} ad: ${JSON.stringify(ad, null, ' ')}`);
219
- };
220
- await switchbot.wait(10000);
221
- // Stop to monitor
222
- switchbot.stopScan();
223
- })();
224
- }
225
- }
226
- async BLEconnection(switchbot) {
227
- this.errorLog(`Plug: ${this.accessory.displayName} wasn't able to establish BLE Connection, node-switchbot: ${switchbot}`);
228
- if (this.platform.config.credentials?.token) {
229
- this.warnLog(`Plug: ${this.accessory.displayName} Using OpenAPI Connection`);
230
- this.SwitchToOpenAPI = true;
231
- await this.openAPIRefreshStatus();
232
- }
233
- }
234
208
  async openAPIRefreshStatus() {
209
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus`);
235
210
  try {
236
211
  const t = Date.now();
237
212
  const nonce = 'requestID';
238
213
  const data = this.platform.config.credentials?.token + t + nonce;
239
214
  const signTerm = crypto_1.default.createHmac('sha256', this.platform.config.credentials?.secret).update(Buffer.from(data, 'utf-8')).digest();
240
215
  const sign = signTerm.toString('base64');
241
- this.debugLog(`Plug: ${this.accessory.displayName} sign: ${sign}`);
216
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} sign: ${sign}`);
242
217
  const options = {
243
218
  hostname: settings_1.HostDomain,
244
219
  port: 443,
@@ -253,36 +228,35 @@ class Plug {
253
228
  },
254
229
  };
255
230
  const req = https_1.default.request(options, (res) => {
256
- this.debugLog(`Plug: ${this.accessory.displayName} statusCode: ${res.statusCode}`);
231
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus statusCode: ${res.statusCode}`);
232
+ this.statusCode({ res });
257
233
  let rawData = '';
258
234
  res.on('data', (d) => {
259
235
  rawData += d;
260
- this.debugLog(`Plug: ${this.accessory.displayName} d: ${d}`);
236
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} d: ${d}`);
261
237
  });
262
238
  res.on('end', () => {
263
239
  try {
264
240
  this.deviceStatus = JSON.parse(rawData);
265
- this.debugLog(`Plug: ${this.accessory.displayName} refreshStatus: ${JSON.stringify(this.deviceStatus)}`);
241
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus: ${(0, super_stringify_1.default)(this.deviceStatus)}`);
266
242
  this.power = this.deviceStatus.body.power;
267
243
  this.parseStatus();
268
244
  this.updateHomeKitCharacteristics();
269
245
  }
270
246
  catch (e) {
271
- this.errorLog(`Plug: ${this.accessory.displayName} error message: ${e.message}`);
247
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
272
248
  }
273
249
  });
274
250
  });
275
251
  req.on('error', (e) => {
276
- this.errorLog(`Plug: ${this.accessory.displayName} error message: ${e.message}`);
252
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
277
253
  });
278
254
  req.end();
279
255
  }
280
256
  catch (e) {
281
- this.errorLog(`Plug: ${this.accessory.displayName} failed refreshStatus with OpenAPI Connection`);
282
- if (this.deviceLogging.includes('debug')) {
283
- this.errorLog(`Plug: ${this.accessory.displayName} failed refreshStatus with OpenAPI Connection,` + ` Error Message: ${JSON.stringify(e.message)}`);
284
- }
285
257
  this.apiError(e);
258
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}`
259
+ + ` Connection, Error Message: ${(0, super_stringify_1.default)(e.message)}`);
286
260
  }
287
261
  }
288
262
  /**
@@ -295,73 +269,66 @@ class Plug {
295
269
  * Plug Mini (US/JP) - "command" toggle default = toggle state
296
270
  */
297
271
  async pushChanges() {
298
- if (this.device.ble) {
272
+ if (this.BLE) {
299
273
  await this.BLEpushChanges();
300
274
  }
301
- else {
275
+ else if (this.OpenAPI && this.platform.config.credentials?.token) {
302
276
  await this.openAPIpushChanges();
303
277
  }
304
- }
305
- async BLEpushChanges() {
306
- this.debugLog(`Plug: ${this.accessory.displayName} BLE pushChanges On: ${this.On} OnCached: ${this.OnCached}`);
307
- this.debugLog(`Plug: ${this.accessory.displayName} BLE pushChanges`);
308
- const switchbot = await this.platform.connectBLE();
309
- // Convert to BLE Address
310
- this.device.bleMac = this.device
311
- .deviceId.match(/.{1,2}/g)
312
- .join(':')
313
- .toLowerCase();
314
- this.debugLog(`Plug: ${this.accessory.displayName} BLE Address: ${this.device.bleMac}`);
315
- switchbot
316
- .discover({
317
- model: this.BLEmodel(),
318
- id: this.device.bleMac,
319
- })
320
- .then((device_list) => {
321
- this.infoLog(`Plug: ${this.accessory.displayName} On: ${this.On}`);
322
- return this.turnOnOff(device_list);
323
- })
324
- .then(() => {
325
- this.debugLog(`Plug: ${this.accessory.displayName} Done.`);
326
- this.On = false;
327
- this.OnCached = this.On;
328
- this.accessory.context.On = this.OnCached;
329
- })
330
- .catch(async (e) => {
331
- this.errorLog(`Plug: ${this.accessory.displayName} failed pushChanges with BLE Connection`);
332
- if (this.deviceLogging.includes('debug')) {
333
- this.errorLog(`Plug: ${this.accessory.displayName} failed pushChanges with BLE Connection,` + ` Error Message: ${JSON.stringify(e.message)}`);
334
- }
335
- if (this.platform.debugMode) {
336
- this.errorLog(`Plug: ${this.accessory.displayName} failed pushChanges with BLE Connection,` + ` Error: ${JSON.stringify(e)}`);
337
- }
338
- if (this.platform.config.credentials?.token) {
339
- this.warnLog(`Plug: ${this.accessory.displayName} Using OpenAPI Connection`);
340
- await this.openAPIpushChanges();
341
- }
342
- this.apiError(e);
278
+ else {
279
+ this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:`
280
+ + ` ${this.device.connectionType}, pushChanges will not happen.`);
281
+ }
282
+ (0, rxjs_1.interval)(5000)
283
+ .pipe((0, operators_1.take)(1))
284
+ .subscribe(async () => {
285
+ await this.refreshStatus();
343
286
  });
344
- this.OnCached = this.On;
345
- this.accessory.context.On = this.OnCached;
346
287
  }
347
- async turnOnOff(device_list) {
348
- return await this.retry({
349
- max: await this.maxRetry(),
350
- fn: () => {
351
- if (this.On) {
352
- return device_list[0].turnOn({ id: this.device.bleMac });
353
- }
354
- else {
355
- return device_list[0].turnOff({ id: this.device.bleMac });
288
+ async BLEpushChanges() {
289
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEpushChanges`);
290
+ if (this.On !== this.accessory.context.On) {
291
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEpushChanges On: ${this.On} OnCached: ${this.accessory.context.On}`);
292
+ const switchbot = await this.platform.connectBLE();
293
+ // Convert to BLE Address
294
+ this.device.bleMac = this.device
295
+ .deviceId.match(/.{1,2}/g)
296
+ .join(':')
297
+ .toLowerCase();
298
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLE Address: ${this.device.bleMac}`);
299
+ switchbot
300
+ .discover({
301
+ model: this.BLEmodel(),
302
+ id: this.device.bleMac,
303
+ })
304
+ .then((device_list) => {
305
+ this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
306
+ return this.turnOnOff(device_list);
307
+ })
308
+ .then(() => {
309
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Done.`);
310
+ this.On = false;
311
+ })
312
+ .catch(async (e) => {
313
+ this.apiError(e);
314
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushChanges with ${this.device.connectionType}`
315
+ + ` Connection, Error Message: ${(0, super_stringify_1.default)(e.message)}`);
316
+ if (this.platform.config.credentials?.token && this.device.connectionType !== 'Both') {
317
+ this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Using OpenAPI Connection`);
318
+ await this.openAPIpushChanges();
356
319
  }
357
- },
358
- });
320
+ });
321
+ }
322
+ else {
323
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No BLEpushChanges.` + `On: ${this.On}, `
324
+ + `OnCached: ${this.accessory.context.On}`);
325
+ }
359
326
  }
360
327
  async openAPIpushChanges() {
361
- if (this.platform.config.credentials?.token) {
362
- if (this.On !== this.OnCached) {
328
+ try {
329
+ if (this.On !== this.accessory.context.On) {
363
330
  // Make Push On request to the API
364
- this.debugLog(`Plug: ${this.accessory.displayName} OpenAPI pushChanges`);
331
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIpushChanges`);
365
332
  const t = Date.now();
366
333
  const nonce = 'requestID';
367
334
  const data = this.platform.config.credentials?.token + t + nonce;
@@ -369,7 +336,7 @@ class Plug {
369
336
  .update(Buffer.from(data, 'utf-8'))
370
337
  .digest();
371
338
  const sign = signTerm.toString('base64');
372
- this.debugLog(`Plug: ${this.accessory.displayName} sign: ${sign}`);
339
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} sign: ${sign}`);
373
340
  let command = '';
374
341
  if (this.On) {
375
342
  command = 'turnOn';
@@ -377,12 +344,12 @@ class Plug {
377
344
  else {
378
345
  command = 'turnOff';
379
346
  }
380
- const body = JSON.stringify({
347
+ const body = (0, super_stringify_1.default)({
381
348
  'command': `${command}`,
382
349
  'parameter': 'default',
383
350
  'commandType': 'command',
384
351
  });
385
- this.infoLog(`Plug: ${this.accessory.displayName} Sending request to SwitchBot API. body: ${body},`);
352
+ this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API. body: ${body},`);
386
353
  const options = {
387
354
  hostname: settings_1.HostDomain,
388
355
  port: 443,
@@ -398,126 +365,224 @@ class Plug {
398
365
  },
399
366
  };
400
367
  const req = https_1.default.request(options, res => {
401
- this.debugLog(`Plug: ${this.accessory.displayName} statusCode: ${res.statusCode}`);
368
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIpushChanges statusCode: ${res.statusCode}`);
402
369
  this.statusCode({ res });
403
370
  res.on('data', d => {
404
- this.debugLog(`Plug: ${this.accessory.displayName} d: ${d}`);
371
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} d: ${d}`);
405
372
  });
406
373
  });
407
374
  req.on('error', (e) => {
408
- this.errorLog(`Plug: ${this.accessory.displayName} error message: ${e.message}`);
375
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
409
376
  });
410
377
  req.write(body);
411
378
  req.end();
412
- this.debugLog(`Plug: ${this.accessory.displayName} openAPIpushChanges: ${JSON.stringify(req)}`);
413
- this.OnCached = this.On;
414
- this.accessory.context.On = this.OnCached;
379
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIpushChanges: ${(0, super_stringify_1.default)(req)}`);
415
380
  }
416
- (0, rxjs_1.interval)(5000)
417
- .pipe((0, operators_1.take)(1))
418
- .subscribe(async () => {
419
- await this.refreshStatus();
420
- });
381
+ else {
382
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No openAPIpushChanges.` + `On: ${this.On}, `
383
+ + `OnCached: ${this.accessory.context.On}`);
384
+ }
385
+ }
386
+ catch (e) {
387
+ this.apiError(e);
388
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIpushChanges with ${this.device.connectionType}`
389
+ + ` Connection, Error Message: ${(0, super_stringify_1.default)(e.message)}`);
421
390
  }
422
391
  }
392
+ /**
393
+ * Handle requests to set the value of the "On" characteristic
394
+ */
395
+ async OnSet(value) {
396
+ this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set On: ${value}`);
397
+ this.On = value;
398
+ this.doPlugUpdate.next();
399
+ }
423
400
  async updateHomeKitCharacteristics() {
424
401
  if (this.On === undefined) {
425
- this.debugLog(`Plug: ${this.accessory.displayName} On: ${this.On}`);
402
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
426
403
  }
427
404
  else {
405
+ this.accessory.context.On = this.On;
428
406
  this.outletService.updateCharacteristic(this.platform.Characteristic.On, this.On);
429
- this.debugLog(`Plug: ${this.accessory.displayName} updateCharacteristic On: ${this.On}`);
407
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic On: ${this.On}`);
430
408
  }
431
409
  }
432
- async apiError(e) {
433
- this.outletService.updateCharacteristic(this.platform.Characteristic.On, e);
434
- //throw new this.platform.api.hap.HapStatusError(HAPStatus.SERVICE_COMMUNICATION_FAILURE);
410
+ BLEmodel() {
411
+ if (this.device.deviceType === 'Plug Mini (US)') {
412
+ return 'g';
413
+ }
414
+ else {
415
+ return 'j';
416
+ }
417
+ }
418
+ async getCustomBLEAddress(switchbot) {
419
+ if (this.device.customBLEaddress && this.deviceLogging.includes('debug')) {
420
+ (async () => {
421
+ // Start to monitor advertisement packets
422
+ await switchbot.startScan({
423
+ model: this.BLEmodel(),
424
+ });
425
+ // Set an event handler
426
+ switchbot.onadvertisement = (ad) => {
427
+ this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} ad: ${(0, super_stringify_1.default)(ad, null, ' ')}`);
428
+ };
429
+ await switchbot.wait(10000);
430
+ // Stop to monitor
431
+ switchbot.stopScan();
432
+ })();
433
+ }
434
+ }
435
+ async BLEconnection(switchbot) {
436
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} wasn't able to establish BLE Connection, node-switchbot: ${switchbot}`);
437
+ if (this.platform.config.credentials?.token && this.device.connectionType !== 'Both') {
438
+ this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Using OpenAPI Connection`);
439
+ this.SwitchToOpenAPI = true;
440
+ await this.openAPIRefreshStatus();
441
+ }
442
+ }
443
+ async turnOnOff(device_list) {
444
+ return await this.retry({
445
+ max: await this.maxRetry(),
446
+ fn: () => {
447
+ if (this.On) {
448
+ return device_list[0].turnOn({ id: this.device.bleMac });
449
+ }
450
+ else {
451
+ return device_list[0].turnOff({ id: this.device.bleMac });
452
+ }
453
+ },
454
+ });
455
+ }
456
+ async retry({ max, fn }) {
457
+ return fn().catch(async (err) => {
458
+ if (max === 0) {
459
+ throw err;
460
+ }
461
+ this.infoLog(err);
462
+ this.infoLog('Retrying');
463
+ await this.switchbot.wait(1000);
464
+ return this.retry({ max: max - 1, fn });
465
+ });
466
+ }
467
+ async maxRetry() {
468
+ let maxRetry;
469
+ if (this.device.bot?.maxRetry) {
470
+ maxRetry = this.device.bot?.maxRetry;
471
+ }
472
+ else {
473
+ maxRetry = 5;
474
+ }
475
+ return maxRetry;
476
+ }
477
+ model(device) {
478
+ let model;
479
+ if (device.deviceType === 'Plug Mini (US)') {
480
+ model = 'W1901400';
481
+ }
482
+ else if (device.deviceType === 'Plug Mini (JP)') {
483
+ model = 'W2001400';
484
+ }
485
+ else {
486
+ model = 'SP11';
487
+ }
488
+ return model;
489
+ }
490
+ async scan(device) {
491
+ if (device.scanDuration) {
492
+ this.scanDuration = this.accessory.context.scanDuration = device.scanDuration;
493
+ if (this.BLE) {
494
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config scanDuration: ${this.scanDuration}`);
495
+ }
496
+ }
497
+ else {
498
+ this.scanDuration = this.accessory.context.scanDuration = 1;
499
+ if (this.BLE) {
500
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Default scanDuration: ${this.scanDuration}`);
501
+ }
502
+ }
435
503
  }
436
504
  async statusCode({ res }) {
437
505
  switch (res.statusCode) {
438
506
  case 151:
439
- this.errorLog(`Plug: ${this.accessory.displayName} Command not supported by this device type.`);
507
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command not supported by this device type.`);
440
508
  break;
441
509
  case 152:
442
- this.errorLog(`Plug: ${this.accessory.displayName} Device not found.`);
510
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device not found.`);
443
511
  break;
444
512
  case 160:
445
- this.errorLog(`Plug: ${this.accessory.displayName} Command is not supported.`);
513
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command is not supported.`);
446
514
  break;
447
515
  case 161:
448
- this.errorLog(`Plug: ${this.accessory.displayName} Device is offline.`);
516
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device is offline.`);
449
517
  this.offlineOff();
450
518
  break;
451
519
  case 171:
452
- this.errorLog(`Plug: ${this.accessory.displayName} Hub Device is offline. Hub: ${this.device.hubDeviceId}`);
520
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline. Hub: ${this.device.hubDeviceId}`);
453
521
  this.offlineOff();
454
522
  break;
455
523
  case 190:
456
- this.errorLog(`Plug: ${this.accessory.displayName} Device internal error due to device states not synchronized with server,` +
457
- ` Or command: ${JSON.stringify(res)} format is invalid`);
524
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device internal error due to device states not synchronized with server,` +
525
+ ` Or command: ${(0, super_stringify_1.default)(res)} format is invalid`);
458
526
  break;
459
527
  case 100:
460
- this.debugLog(`Plug: ${this.accessory.displayName} Command successfully sent.`);
528
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Command successfully sent.`);
461
529
  break;
462
530
  default:
463
- this.debugLog(`Plug: ${this.accessory.displayName} Unknown statusCode.`);
531
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode.`);
464
532
  }
465
533
  }
466
534
  async offlineOff() {
467
535
  if (this.device.offline) {
468
536
  this.On = false;
469
537
  this.outletService.getCharacteristic(this.platform.Characteristic.On).updateValue(this.On);
538
+ await this.updateHomeKitCharacteristics();
470
539
  }
471
540
  }
472
- /**
473
- * Handle requests to set the value of the "On" characteristic
474
- */
475
- async handleOnSet(value) {
476
- this.debugLog(`Plug: ${this.accessory.displayName} - Set On: ${value}`);
477
- this.On = value;
478
- this.doPlugUpdate.next();
541
+ async apiError(e) {
542
+ this.outletService.updateCharacteristic(this.platform.Characteristic.On, e);
479
543
  }
480
- model(device) {
481
- let model;
482
- if (device.deviceType === 'Plug Mini (US)') {
483
- model = 'W1901400';
544
+ FirmwareRevision(accessory, device) {
545
+ let FirmwareRevision;
546
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
547
+ + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`);
548
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} device.firmware: ${device.firmware}`);
549
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`);
550
+ if (accessory.context.FirmwareRevision) {
551
+ FirmwareRevision = accessory.context.FirmwareRevision;
484
552
  }
485
- else if (device.deviceType === 'Plug Mini (JP)') {
486
- model = 'W2001400';
553
+ else if (device.firmware) {
554
+ FirmwareRevision = device.firmware;
487
555
  }
488
556
  else {
489
- model = 'SP11';
557
+ FirmwareRevision = this.platform.version;
490
558
  }
491
- return model;
492
- }
493
- async retry({ max, fn }) {
494
- return fn().catch(async (err) => {
495
- if (max === 0) {
496
- throw err;
497
- }
498
- this.infoLog(err);
499
- this.infoLog('Retrying');
500
- await this.switchbot.wait(1000);
501
- return this.retry({ max: max - 1, fn });
502
- });
559
+ return FirmwareRevision;
503
560
  }
504
- async maxRetry() {
505
- let maxRetry;
506
- if (this.device.bot?.maxRetry) {
507
- maxRetry = this.device.bot?.maxRetry;
561
+ async context() {
562
+ if (this.On === undefined) {
563
+ this.On = false;
508
564
  }
509
565
  else {
510
- maxRetry = 5;
566
+ this.On = this.accessory.context.On;
567
+ }
568
+ }
569
+ async refreshRate(device) {
570
+ if (device.refreshRate) {
571
+ this.deviceRefreshRate = this.accessory.context.refreshRate = device.refreshRate;
572
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config refreshRate: ${this.deviceRefreshRate}`);
573
+ }
574
+ else if (this.platform.config.options.refreshRate) {
575
+ this.deviceRefreshRate = this.accessory.context.refreshRate = this.platform.config.options.refreshRate;
576
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Platform Config refreshRate: ${this.deviceRefreshRate}`);
511
577
  }
512
- return maxRetry;
513
578
  }
514
579
  async config(device) {
515
580
  let config = {};
516
581
  if (device.plug) {
517
582
  config = device.plug;
518
583
  }
519
- if (device.ble !== undefined) {
520
- config['ble'] = device.ble;
584
+ if (device.connectionType !== undefined) {
585
+ config['connectionType'] = device.connectionType;
521
586
  }
522
587
  if (device.logging !== undefined) {
523
588
  config['logging'] = device.logging;
@@ -532,67 +597,27 @@ class Plug {
532
597
  config['offline'] = device.offline;
533
598
  }
534
599
  if (Object.entries(config).length !== 0) {
535
- this.infoLog(`Plug: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`);
536
- }
537
- }
538
- async refreshRate(device) {
539
- if (device.refreshRate) {
540
- this.deviceRefreshRate = this.accessory.context.refreshRate = device.refreshRate;
541
- this.debugLog(`Plug: ${this.accessory.displayName} Using Device Config refreshRate: ${this.deviceRefreshRate}`);
542
- }
543
- else if (this.platform.config.options.refreshRate) {
544
- this.deviceRefreshRate = this.accessory.context.refreshRate = this.platform.config.options.refreshRate;
545
- this.debugLog(`Plug: ${this.accessory.displayName} Using Platform Config refreshRate: ${this.deviceRefreshRate}`);
546
- }
547
- }
548
- async scan(device) {
549
- if (device.scanDuration) {
550
- this.scanDuration = this.accessory.context.scanDuration = device.scanDuration;
551
- if (device.ble) {
552
- this.debugLog(`Plug: ${this.accessory.displayName} Using Device Config scanDuration: ${this.scanDuration}`);
553
- }
554
- }
555
- else {
556
- this.scanDuration = this.accessory.context.scanDuration = 1;
557
- if (this.device.ble) {
558
- this.debugLog(`Plug: ${this.accessory.displayName} Using Default scanDuration: ${this.scanDuration}`);
559
- }
600
+ this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${(0, super_stringify_1.default)(config)}`);
560
601
  }
561
602
  }
562
603
  async logs(device) {
563
604
  if (this.platform.debugMode) {
564
605
  this.deviceLogging = this.accessory.context.logging = 'debugMode';
565
- this.debugLog(`Plug: ${this.accessory.displayName} Using Debug Mode Logging: ${this.deviceLogging}`);
606
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Debug Mode Logging: ${this.deviceLogging}`);
566
607
  }
567
608
  else if (device.logging) {
568
609
  this.deviceLogging = this.accessory.context.logging = device.logging;
569
- this.debugLog(`Plug: ${this.accessory.displayName} Using Device Config Logging: ${this.deviceLogging}`);
610
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config Logging: ${this.deviceLogging}`);
570
611
  }
571
612
  else if (this.platform.config.options?.logging) {
572
613
  this.deviceLogging = this.accessory.context.logging = this.platform.config.options?.logging;
573
- this.debugLog(`Plug: ${this.accessory.displayName} Using Platform Config Logging: ${this.deviceLogging}`);
614
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Platform Config Logging: ${this.deviceLogging}`);
574
615
  }
575
616
  else {
576
617
  this.deviceLogging = this.accessory.context.logging = 'standard';
577
- this.debugLog(`Plug: ${this.accessory.displayName} Logging Not Set, Using: ${this.deviceLogging}`);
618
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Logging Not Set, Using: ${this.deviceLogging}`);
578
619
  }
579
620
  }
580
- FirmwareRevision(accessory, device) {
581
- let FirmwareRevision;
582
- this.debugLog(`Plug: ${this.accessory.displayName} accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`);
583
- this.debugLog(`Plug: ${this.accessory.displayName} device.firmware: ${device.firmware}`);
584
- this.debugLog(`Plug: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`);
585
- if (accessory.context.FirmwareRevision) {
586
- FirmwareRevision = accessory.context.FirmwareRevision;
587
- }
588
- else if (device.firmware) {
589
- FirmwareRevision = device.firmware;
590
- }
591
- else {
592
- FirmwareRevision = this.platform.version;
593
- }
594
- return FirmwareRevision;
595
- }
596
621
  /**
597
622
  * Logging for Device
598
623
  */