@switchbot/homebridge-switchbot 2.0.0-beta.3 → 2.0.0-beta.30

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