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

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 +3 -5
  85. package/dist/platform.d.ts.map +1 -1
  86. package/dist/platform.js +203 -200
  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 +195 -216
  113. package/src/settings.ts +15 -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