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

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 +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 +456 -434
  87. package/dist/platform.js.map +1 -1
  88. package/dist/settings.d.ts +16 -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 +447 -457
  113. package/src/settings.ts +16 -11
@@ -1,6 +1,7 @@
1
1
  import https from 'https';
2
2
  import crypto from 'crypto';
3
3
  import { IncomingMessage } from 'http';
4
+ import superStringify from 'super-stringify';
4
5
  import { SwitchBotPlatform } from '../platform';
5
6
  import { irDevicesConfig, irdevice, HostDomain, DevicePath } from '../settings';
6
7
  import { CharacteristicValue, PlatformAccessory, Service } from 'homebridge';
@@ -16,7 +17,6 @@ export class Camera {
16
17
 
17
18
  // Characteristic Values
18
19
  On!: CharacteristicValue;
19
- OnCached!: CharacteristicValue;
20
20
 
21
21
  // Config
22
22
  deviceLogging!: string;
@@ -25,18 +25,17 @@ export class Camera {
25
25
  // default placeholders
26
26
  this.logs(device);
27
27
  this.config(device);
28
- if (this.On === undefined) {
29
- this.On = false;
30
- } else {
31
- this.On = this.accessory.context.On;
32
- }
28
+ this.context();
33
29
 
34
30
  // set accessory information
35
31
  accessory
36
32
  .getService(this.platform.Service.AccessoryInformation)!
37
33
  .setCharacteristic(this.platform.Characteristic.Manufacturer, 'SwitchBot')
38
34
  .setCharacteristic(this.platform.Characteristic.Model, device.remoteType)
39
- .setCharacteristic(this.platform.Characteristic.SerialNumber, device.deviceId!);
35
+ .setCharacteristic(this.platform.Characteristic.SerialNumber, device.deviceId!)
36
+ .setCharacteristic(this.platform.Characteristic.FirmwareRevision, this.FirmwareRevision(accessory, device))
37
+ .getCharacteristic(this.platform.Characteristic.FirmwareRevision)
38
+ .updateValue(this.FirmwareRevision(accessory, device));
40
39
 
41
40
  // get the Television service if it exists, otherwise create a new Television service
42
41
  // you can create multiple services for each accessory
@@ -56,8 +55,9 @@ export class Camera {
56
55
  }
57
56
 
58
57
  async OnSet(value: CharacteristicValue): Promise<void> {
59
- this.debugLog(`Camera: ${this.accessory.displayName} On: ${value}`);
58
+ this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} On: ${value}`);
60
59
  this.On = value;
60
+ this.accessory.context.On = this.On;
61
61
  if (this.On) {
62
62
  this.pushOnChanges();
63
63
  } else {
@@ -65,28 +65,19 @@ export class Camera {
65
65
  }
66
66
  }
67
67
 
68
- async updateHomeKitCharacteristics(): Promise<void> {
69
- if (this.On === undefined) {
70
- this.debugLog(`Camera: ${this.accessory.displayName} On: ${this.On}`);
71
- } else {
72
- this.switchService?.updateCharacteristic(this.platform.Characteristic.On, this.On);
73
- this.debugLog(`Camera: ${this.accessory.displayName} updateCharacteristic On: ${this.On}`);
74
- }
75
- }
76
-
77
68
  /**
78
69
  * Pushes the requested changes to the SwitchBot API
79
70
  * deviceType commandType Command command parameter Description
80
- * Light: "command" "turnOff" "default" = set to OFF state
81
- * Light: "command" "turnOn" "default" = set to ON state
82
- * Light: "command" "volumeAdd" "default" = volume up
83
- * Light: "command" "volumeSub" "default" = volume down
84
- * Light: "command" "channelAdd" "default" = next channel
85
- * Light: "command" "channelSub" "default" = previous channel
71
+ * Camera - "command" "turnOff" "default" = set to OFF state
72
+ * Camera - "command" "turnOn" "default" = set to ON state
73
+ * Camera - "command" "volumeAdd" "default" = volume up
74
+ * Camera - "command" "volumeSub" "default" = volume down
75
+ * Camera - "command" "channelAdd" "default" = next channel
76
+ * Camera - "command" "channelSub" "default" = previous channel
86
77
  */
87
78
  async pushOnChanges(): Promise<void> {
88
79
  if (this.On) {
89
- const body = JSON.stringify({
80
+ const body = superStringify({
90
81
  'command': 'turnOn',
91
82
  'parameter': 'default',
92
83
  'commandType': 'command',
@@ -97,7 +88,7 @@ export class Camera {
97
88
 
98
89
  async pushOffChanges(): Promise<void> {
99
90
  if (!this.On) {
100
- const body = JSON.stringify({
91
+ const body = superStringify({
101
92
  'command': 'turnOff',
102
93
  'parameter': 'default',
103
94
  'commandType': 'command',
@@ -107,92 +98,125 @@ export class Camera {
107
98
  }
108
99
 
109
100
  async pushChanges(body): Promise<void> {
110
- try {
101
+ if (this.device.connectionType === 'OpenAPI') {
102
+ try {
111
103
  // Make Push On request to the API
112
- const t = Date.now();
113
- const nonce = 'requestID';
114
- const data = this.platform.config.credentials?.token + t + nonce;
115
- const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret)
116
- .update(Buffer.from(data, 'utf-8'))
117
- .digest();
118
- const sign = signTerm.toString('base64');
119
- this.debugLog(`Camera: ${this.accessory.displayName} sign: ${sign}`);
120
- this.infoLog(`Camera: ${this.accessory.displayName} Sending request to SwitchBot API. body: ${body},`);
121
- const options = {
122
- hostname: HostDomain,
123
- port: 443,
124
- path: `${DevicePath}/${this.device.deviceId}/commands`,
125
- method: 'POST',
126
- headers: {
127
- 'Authorization': this.platform.config.credentials?.token,
128
- 'sign': sign,
129
- 'nonce': nonce,
130
- 't': t,
131
- 'Content-Type': 'application/json',
132
- 'Content-Length': body.length,
133
- },
134
- };
135
- const req = https.request(options, res => {
136
- this.debugLog(`Camera: ${this.accessory.displayName} statusCode: ${res.statusCode}`);
137
- this.statusCode({ res });
138
- res.on('data', d => {
139
- this.debugLog(`Camera: ${this.accessory.displayName} d: ${d}`);
104
+ const t = Date.now();
105
+ const nonce = 'requestID';
106
+ const data = this.platform.config.credentials?.token + t + nonce;
107
+ const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret)
108
+ .update(Buffer.from(data, 'utf-8'))
109
+ .digest();
110
+ const sign = signTerm.toString('base64');
111
+ this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} sign: ${sign}`);
112
+ this.infoLog(`${this.device.remoteType}: ${this.accessory.displayName} Sending request to SwitchBot API. body: ${body},`);
113
+ const options = {
114
+ hostname: HostDomain,
115
+ port: 443,
116
+ path: `${DevicePath}/${this.device.deviceId}/commands`,
117
+ method: 'POST',
118
+ headers: {
119
+ 'Authorization': this.platform.config.credentials?.token,
120
+ 'sign': sign,
121
+ 'nonce': nonce,
122
+ 't': t,
123
+ 'Content-Type': 'application/json',
124
+ 'Content-Length': body.length,
125
+ },
126
+ };
127
+ const req = https.request(options, res => {
128
+ this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushchanges statusCode: ${res.statusCode}`);
129
+ this.statusCode({ res });
130
+ res.on('data', d => {
131
+ this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} d: ${d}`);
132
+ });
140
133
  });
141
- });
142
- req.on('error', (e: any) => {
143
- this.errorLog(`Camera: ${this.accessory.displayName} error message: ${e.message}`);
144
- });
145
- req.write(body);
146
- req.end();
147
- this.debugLog(`Camera: ${this.accessory.displayName} pushchanges: ${JSON.stringify(req)}`);
148
- this.updateHomeKitCharacteristics();
149
- this.OnCached = this.On;
150
- this.accessory.context.On = this.OnCached;
151
- } catch (e: any) {
152
- this.errorLog(`Camera: ${this.accessory.displayName} failed pushChanges with OpenAPI Connection`);
153
- if (this.deviceLogging.includes('debug')) {
154
- this.errorLog(
155
- `Camera: ${this.accessory.displayName} failed pushChanges with OpenAPI Connection,` + ` Error Message: ${JSON.stringify(e.message)}`,
134
+ req.on('error', (e: any) => {
135
+ this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} error message: ${e.message}`);
136
+ });
137
+ req.write(body);
138
+ req.end();
139
+ this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushchanges: ${superStringify(req)}`);
140
+ this.updateHomeKitCharacteristics();
141
+ } catch (e: any) {
142
+ this.apiError(e);
143
+ this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType} Connection,`
144
+ + ` Error Message: ${superStringify(e.message)}`,
156
145
  );
157
146
  }
158
- this.apiError(e);
147
+ } else {
148
+ this.warnLog(`${this.device.remoteType}: ${this.accessory.displayName}`
149
+ + ` Connection Type: ${this.device.connectionType}, commands will not be sent to OpenAPI`);
150
+ }
151
+ }
152
+
153
+ async updateHomeKitCharacteristics(): Promise<void> {
154
+ if (this.On === undefined) {
155
+ this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} On: ${this.On}`);
156
+ } else {
157
+ this.accessory.context.On = this.On;
158
+ this.switchService?.updateCharacteristic(this.platform.Characteristic.On, this.On);
159
+ this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} updateCharacteristic On: ${this.On}`);
159
160
  }
160
161
  }
161
162
 
162
163
  async statusCode({ res }: { res: IncomingMessage }): Promise<void> {
163
164
  switch (res.statusCode) {
164
165
  case 151:
165
- this.errorLog(`Camera: ${this.accessory.displayName} Command not supported by this device type.`);
166
+ this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Command not supported by this device type.`);
166
167
  break;
167
168
  case 152:
168
- this.errorLog(`Camera: ${this.accessory.displayName} Device not found.`);
169
+ this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Device not found.`);
169
170
  break;
170
171
  case 160:
171
- this.errorLog(`Camera: ${this.accessory.displayName} Command is not supported.`);
172
+ this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Command is not supported.`);
172
173
  break;
173
174
  case 161:
174
- this.errorLog(`Camera: ${this.accessory.displayName} Device is offline.`);
175
+ this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Device is offline.`);
175
176
  break;
176
177
  case 171:
177
- this.errorLog(`Camera: ${this.accessory.displayName} Hub Device is offline. Hub: ${this.device.hubDeviceId}`);
178
+ this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Hub Device is offline. Hub: ${this.device.hubDeviceId}`);
178
179
  break;
179
180
  case 190:
180
181
  this.errorLog(
181
- `Camera: ${this.accessory.displayName} Device internal error due to device states not synchronized` +
182
- ` with server, Or command: ${JSON.stringify(res)} format is invalid`,
182
+ `${this.device.remoteType}: ${this.accessory.displayName} Device internal error due to device states not synchronized` +
183
+ ` with server, Or command: ${superStringify(res)} format is invalid`,
183
184
  );
184
185
  break;
185
186
  case 100:
186
- this.debugLog(`Camera: ${this.accessory.displayName} Command successfully sent.`);
187
+ this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Command successfully sent.`);
187
188
  break;
188
189
  default:
189
- this.debugLog(`Camera: ${this.accessory.displayName} Unknown statusCode.`);
190
+ this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Unknown statusCode.`);
190
191
  }
191
192
  }
192
193
 
193
194
  async apiError(e: any): Promise<void> {
194
195
  this.switchService.updateCharacteristic(this.platform.Characteristic.On, e);
195
- //throw new this.platform.api.hap.HapStatusError(HAPStatus.SERVICE_COMMUNICATION_FAILURE);
196
+ }
197
+
198
+ FirmwareRevision(accessory: PlatformAccessory, device: irdevice & irDevicesConfig): string {
199
+ let FirmwareRevision: string;
200
+ this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName}`
201
+ + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`);
202
+ this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} device.firmware: ${device.firmware}`);
203
+ this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`);
204
+ if (accessory.context.FirmwareRevision) {
205
+ FirmwareRevision = accessory.context.FirmwareRevision;
206
+ } else if (device.firmware) {
207
+ FirmwareRevision = device.firmware;
208
+ } else {
209
+ FirmwareRevision = this.platform.version;
210
+ }
211
+ return FirmwareRevision;
212
+ }
213
+
214
+ async context() {
215
+ if (this.On === undefined) {
216
+ this.On = false;
217
+ } else {
218
+ this.On = this.accessory.context.On;
219
+ }
196
220
  }
197
221
 
198
222
  async config(device: irdevice & irDevicesConfig): Promise<void> {
@@ -203,24 +227,27 @@ export class Camera {
203
227
  if (device.logging !== undefined) {
204
228
  config['logging'] = device.logging;
205
229
  }
230
+ if (device.connectionType !== undefined) {
231
+ config['connectionType'] = device.connectionType;
232
+ }
206
233
  if (Object.entries(config).length !== 0) {
207
- this.infoLog(`Camera: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`);
234
+ this.infoLog(`${this.device.remoteType}: ${this.accessory.displayName} Config: ${superStringify(config)}`);
208
235
  }
209
236
  }
210
237
 
211
238
  async logs(device: irdevice & irDevicesConfig): Promise<void> {
212
239
  if (this.platform.debugMode) {
213
240
  this.deviceLogging = this.accessory.context.logging = 'debugMode';
214
- this.debugLog(`Camera: ${this.accessory.displayName} Using Debug Mode Logging: ${this.deviceLogging}`);
241
+ this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Using Debug Mode Logging: ${this.deviceLogging}`);
215
242
  } else if (device.logging) {
216
243
  this.deviceLogging = this.accessory.context.logging = device.logging;
217
- this.debugLog(`Camera: ${this.accessory.displayName} Using Device Config Logging: ${this.deviceLogging}`);
244
+ this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Using Device Config Logging: ${this.deviceLogging}`);
218
245
  } else if (this.platform.config.options?.logging) {
219
246
  this.deviceLogging = this.accessory.context.logging = this.platform.config.options?.logging;
220
- this.debugLog(`Camera: ${this.accessory.displayName} Using Platform Config Logging: ${this.deviceLogging}`);
247
+ this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Using Platform Config Logging: ${this.deviceLogging}`);
221
248
  } else {
222
249
  this.deviceLogging = this.accessory.context.logging = 'standard';
223
- this.debugLog(`Camera: ${this.accessory.displayName} Logging Not Set, Using: ${this.deviceLogging}`);
250
+ this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Logging Not Set, Using: ${this.deviceLogging}`);
224
251
  }
225
252
  }
226
253
 
@@ -239,12 +266,28 @@ export class Camera {
239
266
  }
240
267
  }
241
268
 
269
+ debugWarnLog(...log: any[]): void {
270
+ if (this.enablingDeviceLogging()) {
271
+ if (this.deviceLogging?.includes('debug')) {
272
+ this.platform.log.warn('[DEBUG]', String(...log));
273
+ }
274
+ }
275
+ }
276
+
242
277
  errorLog(...log: any[]): void {
243
278
  if (this.enablingDeviceLogging()) {
244
279
  this.platform.log.error(String(...log));
245
280
  }
246
281
  }
247
282
 
283
+ debugErrorLog(...log: any[]): void {
284
+ if (this.enablingDeviceLogging()) {
285
+ if (this.deviceLogging?.includes('debug')) {
286
+ this.platform.log.error('[DEBUG]', String(...log));
287
+ }
288
+ }
289
+ }
290
+
248
291
  debugLog(...log: any[]): void {
249
292
  if (this.enablingDeviceLogging()) {
250
293
  if (this.deviceLogging === 'debug') {