node-switchbot 1.0.9-beta.4 → 1.1.0
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.
- package/CHANGELOG.md +10 -2
- package/README.md +1 -1
- package/lib/switchbot-advertising.js +61 -47
- package/lib/switchbot-device-wohumi.js +99 -0
- package/lib/switchbot.js +20 -12
- package/package.json +40 -40
package/CHANGELOG.md
CHANGED
|
@@ -2,7 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. This project uses [Semantic Versioning](https://semver.org/)
|
|
4
4
|
|
|
5
|
-
## [Version 1.0
|
|
5
|
+
## [Version 1.1.0](https://github.com/OpenWonderLabs/homebridge-switchbot/releases/tag/v1.1.0) (2021-10-26)
|
|
6
|
+
|
|
7
|
+
### Changes
|
|
8
|
+
|
|
9
|
+
- Add Contact/Motion Sensor advertisement
|
|
10
|
+
- Add Humidifier advertisement
|
|
11
|
+
- Correct Model for advertisement
|
|
12
|
+
|
|
13
|
+
## [Version 1.0.8](https://github.com/OpenWonderLabs/homebridge-switchbot/releases/tag/v1.0.8) (2021-09-30)
|
|
6
14
|
|
|
7
15
|
### Changes
|
|
8
16
|
|
|
@@ -93,4 +101,4 @@ All notable changes to this project will be documented in this file. This projec
|
|
|
93
101
|
|
|
94
102
|
### Changes
|
|
95
103
|
|
|
96
|
-
- First public release
|
|
104
|
+
- First public release
|
package/README.md
CHANGED
|
@@ -899,4 +899,4 @@ Property | Type | Description
|
|
|
899
899
|
## References
|
|
900
900
|
|
|
901
901
|
* [Switchbot official global site](https://www.switch-bot.com/)
|
|
902
|
-
* [Github - OpenWonderLabs/python-host](https://github.com/OpenWonderLabs/python-host)
|
|
902
|
+
* [Github - OpenWonderLabs/python-host](https://github.com/OpenWonderLabs/python-host)
|
|
@@ -78,13 +78,15 @@ class SwitchbotAdvertising {
|
|
|
78
78
|
|
|
79
79
|
if (model === 'H') { // WoHand
|
|
80
80
|
sd = this._parseServiceDataForWoHand(buf);
|
|
81
|
+
} else if (model === 'e') { // WoHumi
|
|
82
|
+
sd = this._parseServiceDataForWoHumi(buf);
|
|
81
83
|
} else if (model === 'T') { // WoSensorTH
|
|
82
84
|
sd = this._parseServiceDataForWoSensorTH(buf);
|
|
83
85
|
} else if (model === 'c') { // WoCurtain
|
|
84
86
|
sd = this._parseServiceDataForWoCurtain(buf);
|
|
85
|
-
} else if (model === '
|
|
87
|
+
} else if (model === 's') { // WoMotion
|
|
86
88
|
sd = this._parseServiceDataForWoPresence(buf);
|
|
87
|
-
} else if (model === '
|
|
89
|
+
} else if (model === 'd') { // WoContact
|
|
88
90
|
sd = this._parseServiceDataForWoContact(buf);
|
|
89
91
|
} else {
|
|
90
92
|
return null;
|
|
@@ -139,6 +141,31 @@ class SwitchbotAdvertising {
|
|
|
139
141
|
return data;
|
|
140
142
|
}
|
|
141
143
|
|
|
144
|
+
_parseServiceDataForWoHumi(buf) {
|
|
145
|
+
if (buf.length !== 8) {
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
let byte1 = buf.readUInt8(1);
|
|
149
|
+
// let byte2 = buf.readUInt8(2);
|
|
150
|
+
let byte3 = buf.readUInt8(3);
|
|
151
|
+
let byte4 = buf.readUInt8(4);
|
|
152
|
+
let byte5 = buf.readUInt8(5);
|
|
153
|
+
|
|
154
|
+
let onState = (byte1 & 0b10000000) ? true : false; // 1 - on
|
|
155
|
+
let autoMode = (byte4 & 0b10000000) ? true : false; // 1 - auto
|
|
156
|
+
let percentage = byte4 & 0b01111111; // 0-100%, 101/102/103 - Quick gear 1/2/3
|
|
157
|
+
|
|
158
|
+
let data = {
|
|
159
|
+
model: 'e',
|
|
160
|
+
modelName: 'WoHumi',
|
|
161
|
+
onState: onState,
|
|
162
|
+
autoMode: autoMode,
|
|
163
|
+
percentage: autoMode ? 0 : percentage,
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
return data;
|
|
167
|
+
}
|
|
168
|
+
|
|
142
169
|
_parseServiceDataForWoSensorTH(buf) {
|
|
143
170
|
if (buf.length !== 6) {
|
|
144
171
|
return null;
|
|
@@ -172,66 +199,53 @@ class SwitchbotAdvertising {
|
|
|
172
199
|
if (buf.length !== 6) {
|
|
173
200
|
return null;
|
|
174
201
|
}
|
|
202
|
+
let byte1 = buf.readUInt8(1);
|
|
203
|
+
let byte2 = buf.readUInt8(2);
|
|
204
|
+
// let byte3 = buf.readUInt8(3);
|
|
205
|
+
// let byte4 = buf.readUInt8(4);
|
|
206
|
+
let byte5 = buf.readUInt8(5);
|
|
175
207
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
const byte4 = buf.readUInt8(4);
|
|
180
|
-
const byte5 = buf.readUInt8(5);
|
|
181
|
-
|
|
182
|
-
const motion = byte1 & 0b01000000; // Whether the calibration is completed
|
|
183
|
-
const battery = byte2 & 0b01111111; // %
|
|
184
|
-
const pir_trigger3 = byte3 & 0b00001111; //
|
|
185
|
-
const pir_trigger4 = byte4 & 0b01000000; //
|
|
186
|
-
const state = byte5 & 0b01111111; // %
|
|
208
|
+
let pirState = (byte1 & 0b01000000) ? true : false; // 1 - Movement detected
|
|
209
|
+
let battery = byte2 & 0b01111111; // %
|
|
210
|
+
let lightLevel = byte5 & 0b00000011;
|
|
187
211
|
|
|
188
|
-
|
|
212
|
+
let data = {
|
|
189
213
|
model: 's',
|
|
190
|
-
modelName: '
|
|
191
|
-
|
|
214
|
+
modelName: 'WoMotion',
|
|
215
|
+
movement: pirState,
|
|
192
216
|
battery: battery,
|
|
193
|
-
|
|
194
|
-
pir_trigger4: pir_trigger4,
|
|
195
|
-
state: state ? true : false,
|
|
217
|
+
lightLevel: (lightLevel == 1) ? 'dark' : ((lightLevel == 2) ? 'bright' : 'unknown'),
|
|
196
218
|
};
|
|
197
219
|
|
|
198
220
|
return data;
|
|
199
221
|
}
|
|
200
222
|
|
|
201
223
|
_parseServiceDataForWoContact(buf) {
|
|
202
|
-
if (buf.length !==
|
|
224
|
+
if (buf.length !== 9) {
|
|
203
225
|
return null;
|
|
204
226
|
}
|
|
205
227
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
228
|
+
let byte1 = buf.readUInt8(1);
|
|
229
|
+
let byte2 = buf.readUInt8(2);
|
|
230
|
+
let byte3 = buf.readUInt8(3);
|
|
231
|
+
// let byte4 = buf.readUInt8(4);
|
|
232
|
+
// let byte5 = buf.readUInt8(5);
|
|
233
|
+
// let byte6 = buf.readUInt8(6);
|
|
234
|
+
// let byte7 = buf.readUInt8(7);
|
|
235
|
+
// let byte8 = buf.readUInt8(8);
|
|
214
236
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
const pir_trigger5 = byte5 & 0b01000000; //
|
|
220
|
-
const hal_trigger6 = byte6 & 0b01111111; //
|
|
221
|
-
const hal_trigger7 = byte7 & 0b01111111; //
|
|
222
|
-
const act_counter = byte8 & 0b00001111; //
|
|
237
|
+
let pirState = (byte1 & 0b01000000) ? true : false; // 1 - Movement detected
|
|
238
|
+
let battery = byte2 & 0b01111111; // %
|
|
239
|
+
let hallState = (byte3 >> 1) & 0b00000011;
|
|
240
|
+
let lightLevel = byte3 & 0b00000001;
|
|
223
241
|
|
|
224
|
-
|
|
242
|
+
let data = {
|
|
225
243
|
model: 'd',
|
|
226
244
|
modelName: 'WoContact',
|
|
227
|
-
|
|
245
|
+
movement: pirState,
|
|
228
246
|
battery: battery,
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
pir_trigger5: pir_trigger5,
|
|
232
|
-
hal_trigger6: hal_trigger6,
|
|
233
|
-
hal_trigger7: hal_trigger7,
|
|
234
|
-
act_counter: act_counter,
|
|
247
|
+
doorState: (hallState == 0) ? 'close' : ((hallState == 1) ? 'open' : 'timeout no closed'),
|
|
248
|
+
lightLevel: (lightLevel == 0) ? 'dark' : 'bright',
|
|
235
249
|
};
|
|
236
250
|
|
|
237
251
|
return data;
|
|
@@ -246,7 +260,7 @@ class SwitchbotAdvertising {
|
|
|
246
260
|
let byte3 = buf.readUInt8(3);
|
|
247
261
|
let byte4 = buf.readUInt8(4);
|
|
248
262
|
|
|
249
|
-
let calibration = byte1 & 0b01000000; // Whether the calibration is completed
|
|
263
|
+
let calibration = (byte1 & 0b01000000) ? true : false; // Whether the calibration is completed
|
|
250
264
|
let battery = byte2 & 0b01111111; // %
|
|
251
265
|
let currPosition = byte3 & 0b01111111; // current positon %
|
|
252
266
|
let lightLevel = (byte4 >> 4) & 0b00001111; // light sensor level (1-10)
|
|
@@ -254,7 +268,7 @@ class SwitchbotAdvertising {
|
|
|
254
268
|
let data = {
|
|
255
269
|
model: 'c',
|
|
256
270
|
modelName: 'WoCurtain',
|
|
257
|
-
calibration: calibration
|
|
271
|
+
calibration: calibration,
|
|
258
272
|
battery: battery,
|
|
259
273
|
position: currPosition,
|
|
260
274
|
lightLevel: lightLevel
|
|
@@ -264,4 +278,4 @@ class SwitchbotAdvertising {
|
|
|
264
278
|
}
|
|
265
279
|
}
|
|
266
280
|
|
|
267
|
-
module.exports = new SwitchbotAdvertising();
|
|
281
|
+
module.exports = new SwitchbotAdvertising();
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const SwitchbotDevice = require('./switchbot-device.js');
|
|
3
|
+
|
|
4
|
+
class SwitchbotDeviceWoHumi extends SwitchbotDevice {
|
|
5
|
+
|
|
6
|
+
/* ------------------------------------------------------------------
|
|
7
|
+
* press()
|
|
8
|
+
* - Press
|
|
9
|
+
*
|
|
10
|
+
* [Arguments]
|
|
11
|
+
* - none
|
|
12
|
+
*
|
|
13
|
+
* [Returen value]
|
|
14
|
+
* - Promise object
|
|
15
|
+
* Nothing will be passed to the `resolve()`.
|
|
16
|
+
* ---------------------------------------------------------------- */
|
|
17
|
+
press() {
|
|
18
|
+
return this._operateBot([0x57, 0x01, 0x00]);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/* ------------------------------------------------------------------
|
|
22
|
+
* turnOn()
|
|
23
|
+
* - Turn on
|
|
24
|
+
*
|
|
25
|
+
* [Arguments]
|
|
26
|
+
* - none
|
|
27
|
+
*
|
|
28
|
+
* [Returen value]
|
|
29
|
+
* - Promise object
|
|
30
|
+
* Nothing will be passed to the `resolve()`.
|
|
31
|
+
* ---------------------------------------------------------------- */
|
|
32
|
+
turnOn() {
|
|
33
|
+
return this._operateBot([0x57, 0x01, 0x01]);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/* ------------------------------------------------------------------
|
|
37
|
+
* turnOff()
|
|
38
|
+
* - Turn off
|
|
39
|
+
*
|
|
40
|
+
* [Arguments]
|
|
41
|
+
* - none
|
|
42
|
+
*
|
|
43
|
+
* [Returen value]
|
|
44
|
+
* - Promise object
|
|
45
|
+
* Nothing will be passed to the `resolve()`.
|
|
46
|
+
* ---------------------------------------------------------------- */
|
|
47
|
+
turnOff() {
|
|
48
|
+
return this._operateBot([0x57, 0x01, 0x02]);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/* ------------------------------------------------------------------
|
|
52
|
+
* down()
|
|
53
|
+
* - Down
|
|
54
|
+
*
|
|
55
|
+
* [Arguments]
|
|
56
|
+
* - none
|
|
57
|
+
*
|
|
58
|
+
* [Returen value]
|
|
59
|
+
* - Promise object
|
|
60
|
+
* Nothing will be passed to the `resolve()`.
|
|
61
|
+
* ---------------------------------------------------------------- */
|
|
62
|
+
down() {
|
|
63
|
+
return this._operateBot([0x57, 0x01, 0x03]);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/* ------------------------------------------------------------------
|
|
67
|
+
* up()
|
|
68
|
+
* - Up
|
|
69
|
+
*
|
|
70
|
+
* [Arguments]
|
|
71
|
+
* - none
|
|
72
|
+
*
|
|
73
|
+
* [Returen value]
|
|
74
|
+
* - Promise object
|
|
75
|
+
* Nothing will be passed to the `resolve()`.
|
|
76
|
+
* ---------------------------------------------------------------- */
|
|
77
|
+
up() {
|
|
78
|
+
return this._operateBot([0x57, 0x01, 0x04]);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
_operateBot(bytes) {
|
|
82
|
+
return new Promise((resolve, reject) => {
|
|
83
|
+
let req_buf = Buffer.from(bytes);
|
|
84
|
+
this._command(req_buf).then((res_buf) => {
|
|
85
|
+
let code = res_buf.readUInt8(0);
|
|
86
|
+
if (res_buf.length === 3 && (code === 0x01 || code === 0x05)) {
|
|
87
|
+
resolve();
|
|
88
|
+
} else {
|
|
89
|
+
reject(new Error('The device returned an error: 0x' + res_buf.toString('hex')));
|
|
90
|
+
}
|
|
91
|
+
}).catch((error) => {
|
|
92
|
+
reject(error);
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
module.exports = SwitchbotDeviceWoHumi;
|
package/lib/switchbot.js
CHANGED
|
@@ -8,6 +8,7 @@ const SwitchbotDeviceWoCurtain = require('./switchbot-device-wocurtain.js');
|
|
|
8
8
|
const SwitchbotDeviceWoPresence = require('./switchbot-device-wopresence.js');
|
|
9
9
|
const SwitchbotDeviceWoContact = require('./switchbot-device-wocontact.js');
|
|
10
10
|
const SwitchbotDeviceWoSensorTH = require('./switchbot-device-wosensorth.js');
|
|
11
|
+
const SwitchbotDeviceWoHumi = require('./switchbot-device-wohumi.js');
|
|
11
12
|
|
|
12
13
|
class Switchbot {
|
|
13
14
|
/* ------------------------------------------------------------------
|
|
@@ -49,12 +50,13 @@ class Switchbot {
|
|
|
49
50
|
* - duration | Integer | Optional | Duration for discovery process (msec).
|
|
50
51
|
* | | | The value must be in the range of 1 to 60000.
|
|
51
52
|
* | | | The default value is 5000 (msec).
|
|
52
|
-
* - model | String | Optional | "H", "T", "
|
|
53
|
+
* - model | String | Optional | "H", "T", "e", "s", "d", or "c".
|
|
53
54
|
* | | | If "H" is specified, this method will discover only Bots.
|
|
54
55
|
* | | | If "T" is specified, this method will discover only Meters.
|
|
55
|
-
* | | | If "
|
|
56
|
-
* | | | If "
|
|
57
|
-
* | | | If "
|
|
56
|
+
* | | | If "e" is specified, this method will discover only Humidifiers.
|
|
57
|
+
* | | | If "s" is specified, this method will discover only Motion Sensors.
|
|
58
|
+
* | | | If "d" is specified, this method will discover only Contact Sensors.
|
|
59
|
+
* | | | If "c" is specified, this method will discover only Curtains.
|
|
58
60
|
* - id | String | Optional | If this value is set, this method willl discover
|
|
59
61
|
* | | | only a device whose ID is as same as this value.
|
|
60
62
|
* | | | The ID is identical to the MAC address.
|
|
@@ -76,7 +78,7 @@ class Switchbot {
|
|
|
76
78
|
// Check the parameters
|
|
77
79
|
let valid = parameterChecker.check(params, {
|
|
78
80
|
duration: { required: false, type: 'integer', min: 1, max: 60000 },
|
|
79
|
-
model: { required: false, type: 'string', enum: ['H', '
|
|
81
|
+
model: { required: false, type: 'string', enum: ['H', 'T', 'e', 's', 'd', 'c'] },
|
|
80
82
|
id: { required: false, type: 'string', min: 12, max: 17 },
|
|
81
83
|
quick: { required: false, type: 'boolean' }
|
|
82
84
|
}, false);
|
|
@@ -183,13 +185,16 @@ class Switchbot {
|
|
|
183
185
|
case 'H':
|
|
184
186
|
device = new SwitchbotDeviceWoHand(peripheral, this.noble);
|
|
185
187
|
break;
|
|
188
|
+
case 'e':
|
|
189
|
+
device = new SwitchbotDeviceWoHumi(peripheral, this.noble);
|
|
190
|
+
break;
|
|
186
191
|
case 'T':
|
|
187
192
|
device = new SwitchbotDeviceWoSensorTH(peripheral, this.noble);
|
|
188
193
|
break;
|
|
189
|
-
case '
|
|
194
|
+
case 's':
|
|
190
195
|
device = new SwitchbotDeviceWoPresence(peripheral, this.noble);
|
|
191
196
|
break;
|
|
192
|
-
case '
|
|
197
|
+
case 'd':
|
|
193
198
|
device = new SwitchbotDeviceWoContact(peripheral, this.noble);
|
|
194
199
|
break;
|
|
195
200
|
case 'c':
|
|
@@ -229,20 +234,23 @@ class Switchbot {
|
|
|
229
234
|
*
|
|
230
235
|
* [Arguments]
|
|
231
236
|
* - params | Object | Optional |
|
|
232
|
-
* - model | String | Optional | "H", "T", "
|
|
237
|
+
* - model | String | Optional | "H", "T", "e", "s", "d", or "c".
|
|
233
238
|
* | | | If "H" is specified, the `onadvertisement`
|
|
234
239
|
* | | | event hander will be called only when advertising
|
|
235
240
|
* | | | packets comes from Bots.
|
|
236
241
|
* | | | If "T" is specified, the `onadvertisement`
|
|
237
242
|
* | | | event hander will be called only when advertising
|
|
238
243
|
* | | | packets comes from Meters.
|
|
239
|
-
* | | | If "
|
|
244
|
+
* | | | If "e" is specified, the `onadvertisement`
|
|
245
|
+
* | | | event hander will be called only when advertising
|
|
246
|
+
* | | | packets comes from Humidifiers.
|
|
247
|
+
* | | | If "s" is specified, the `onadvertisement`
|
|
240
248
|
* | | | event hander will be called only when advertising
|
|
241
249
|
* | | | packets comes from Motion Sensor.
|
|
242
|
-
* | | | If "
|
|
250
|
+
* | | | If "d" is specified, the `onadvertisement`
|
|
243
251
|
* | | | event hander will be called only when advertising
|
|
244
252
|
* | | | packets comes from Contact Sensor.
|
|
245
|
-
* | | | If "
|
|
253
|
+
* | | | If "c" is specified, the `onadvertisement`
|
|
246
254
|
* | | | event hander will be called only when advertising
|
|
247
255
|
* | | | packets comes from Curtains.
|
|
248
256
|
* - id | String | Optional | If this value is set, the `onadvertisement`
|
|
@@ -261,7 +269,7 @@ class Switchbot {
|
|
|
261
269
|
let promise = new Promise((resolve, reject) => {
|
|
262
270
|
// Check the parameters
|
|
263
271
|
let valid = parameterChecker.check(params, {
|
|
264
|
-
model: { required: false, type: 'string', enum: ['H', '
|
|
272
|
+
model: { required: false, type: 'string', enum: ['H', 'T', 'e', 's', 'd', 'c'] },
|
|
265
273
|
id: { required: false, type: 'string', min: 12, max: 17 },
|
|
266
274
|
}, false);
|
|
267
275
|
|
package/package.json
CHANGED
|
@@ -1,42 +1,42 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
2
|
+
"name": "node-switchbot",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "The node-switchbot is a Node.js module which allows you to move your Switchbot (Bot)'s arm and Switchbot Curtain(Curtain), also monitor the temperature/humidity from SwitchBot Thermometer & Hygrometer (Meter).",
|
|
5
|
+
"main": "./lib/switchbot.js",
|
|
6
|
+
"files": [
|
|
7
|
+
"lib"
|
|
8
|
+
],
|
|
9
|
+
"directories": {
|
|
10
|
+
"lib": "./lib"
|
|
11
|
+
},
|
|
12
|
+
"scripts": {
|
|
13
|
+
"check": "npm install && npm outdated",
|
|
14
|
+
"update": "ncu -u && npm update && npm install"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"switchbot",
|
|
18
|
+
"bot",
|
|
19
|
+
"meter",
|
|
20
|
+
"temperature",
|
|
21
|
+
"humidity",
|
|
22
|
+
"curtain",
|
|
23
|
+
"BLE",
|
|
24
|
+
"Bluetooth Low Energy",
|
|
25
|
+
"Bluetooth smart",
|
|
26
|
+
"Bluetooth"
|
|
27
|
+
],
|
|
28
|
+
"homepage": "https://github.com/OpenWonderLabs",
|
|
29
|
+
"author": "OpenWonderLabs (https://github.com/OpenWonderLabs)",
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "https://github.com/OpenWonderLabs/node-switchbot.git"
|
|
34
|
+
},
|
|
35
|
+
"readmeFilename": "README.md",
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"@homebridge/noble": "^1.9.3"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"npm-check-updates": "^11.8.5"
|
|
41
|
+
}
|
|
42
42
|
}
|