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 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.8](https://github.com/OpenWonderLabs/homebridge-switchbot/releases/tag/v1.0.48) (2021-09-30)
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 === 'P') { // WoPresence
87
+ } else if (model === 's') { // WoMotion
86
88
  sd = this._parseServiceDataForWoPresence(buf);
87
- } else if (model === 'C') { // WoContact
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
- const byte1 = buf.readUInt8(1);
177
- const byte2 = buf.readUInt8(2);
178
- const byte3 = buf.readUInt8(3);
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
- const data = {
212
+ let data = {
189
213
  model: 's',
190
- modelName: 'WoPresence',
191
- motion: motion ? true : false,
214
+ modelName: 'WoMotion',
215
+ movement: pirState,
192
216
  battery: battery,
193
- pir_trigger3: pir_trigger3,
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 !== 6) {
224
+ if (buf.length !== 9) {
203
225
  return null;
204
226
  }
205
227
 
206
- const byte1 = buf.readUInt8(1);
207
- const byte2 = buf.readUInt8(2);
208
- const byte3 = buf.readUInt8(3);
209
- const byte4 = buf.readUInt8(4);
210
- const byte5 = buf.readUInt8(5);
211
- const byte6 = buf.readUInt8(6);
212
- const byte7 = buf.readUInt8(7);
213
- const byte8 = buf.readUInt8(8);
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
- const motion = byte1 & 0b01000000; // Whether there is motion
216
- const battery = byte2 & 0b01111111; // %
217
- const state = byte3 & 0b01111111; // current state
218
- const pir_trigger4 = byte4 & 0b00001111; //
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
- const data = {
242
+ let data = {
225
243
  model: 'd',
226
244
  modelName: 'WoContact',
227
- motion: motion ? true : false,
245
+ movement: pirState,
228
246
  battery: battery,
229
- state: state ? true : false,
230
- pir_trigger4: pir_trigger4,
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 ? true : false,
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", "M", "D", or "S".
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 "S" is specified, this method will discover only Motion Sensors.
56
- * | | | If "D" is specified, this method will discover only Contact Sensors.
57
- * | | | If "C" is specified, this method will discover only Curtains.
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', 'h','T', 'P', 'S', 'D', 'C', 'c'] },
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 'S':
194
+ case 's':
190
195
  device = new SwitchbotDeviceWoPresence(peripheral, this.noble);
191
196
  break;
192
- case 'D':
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", "M", "CS", or "C".
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 "S" is specified, the `onadvertisement`
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 "D" is specified, the `onadvertisement`
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 "C" is specified, the `onadvertisement`
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', 'h','T', 'P', 'S', 'D', 'C', 'c'] },
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
- "name": "node-switchbot",
3
- "version": "1.0.9-beta.4",
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/futomi/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
- }
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
  }