New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

node-switchbot

Package Overview
Dependencies
Maintainers
2
Versions
331
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

node-switchbot - npm Package Compare versions

Comparing version 1.3.0 to 1.4.0

lib/switchbot-device-woplugmini.js

55

CHANGELOG.md

@@ -5,6 +5,15 @@ # Changelog

## [Version 1.3.0](https://github.com/OpenWonderLabs/node-switchbot/releases/tag/v1.2.0) (2022-06-25)
## [Version 1.4.0](https://github.com/OpenWonderLabs/node-switchbot/releases/tag/v1.4.0) (2022-08-19)
### Changes
## What's Changed
- Added support for Plug Mini (j) & (g)
- Housekeeping and update dependencies
**Full Changelog**: https://github.com/OpenWonderLabs/node-switchbot/compare/v1.3.0...v1.4.0
## [Version 1.3.0](https://github.com/OpenWonderLabs/node-switchbot/releases/tag/v1.3.0) (2022-06-25)
## What's Changed
- Added more Device Types, not all supported though.

@@ -17,3 +26,3 @@ - Housekeeping and update dependencies

### Changes
## What's Changed

@@ -28,3 +37,3 @@ - Added support for SwitchBot "Contact" and "Motion"

### Changes
## What's Changed

@@ -37,3 +46,3 @@ - Housekeeping and update dependencies

### Changes
## What's Changed

@@ -46,3 +55,3 @@ - Change back from @node/noble to @abandonware/noble

### Changes
## What's Changed

@@ -57,3 +66,3 @@ - Add Contact/Motion Sensor advertisement

### Changes
## What's Changed

@@ -66,3 +75,3 @@ - fix extra trace of old noble from @abandonware/noble

### Changes
## What's Changed

@@ -75,3 +84,3 @@ - Change from @abandonware/noble to @homebridge/noble

### Changes
## What's Changed

@@ -84,3 +93,3 @@ - Fixes FATAL ERROR: ad_id is not defined

### Changes
## What's Changed

@@ -94,3 +103,3 @@ - Adding code for Contact and Motion Sensors

### Changes
## What's Changed

@@ -103,3 +112,3 @@ - Support for the discover method with id on macOS

### Changes
## What's Changed

@@ -112,3 +121,3 @@ - Fixed misspelling.

### Changes
## What's Changed

@@ -121,3 +130,3 @@ - Housekeeping and update dependencies

### Changes
## What's Changed

@@ -130,5 +139,5 @@ - Fixed issue where after switching Bluetooth off and on, would not work properly.

### Changes
## What's Changed
- * fix "No device was found" in MacOS
- - fix "No device was found" in MacOS

@@ -139,3 +148,3 @@ **Full Changelog**: https://github.com/OpenWonderLabs/node-switchbot/compare/v0.2.0...v1.0.0

### Changes
## What's Changed

@@ -148,3 +157,3 @@ - Modify Curtain's action command to support group and running mode. (Thanks to [@SwitchBot-Wonderlabs](https://github.com/OpenWonderLabs/node-switchbot/pull/7/))

### Changes
## What's Changed

@@ -158,3 +167,3 @@ - Added support for SwitchBot Curtain. (Thanks to [@SwitchBot-Wonderlabs](https://github.com/OpenWonderLabs/node-switchbot/pull/6/))

### Changes
## What's Changed

@@ -167,3 +176,3 @@ - Improved the stability of discovering the BLE characteristics. (Thanks to [@dnicolson](https://github.com/OpenWonderLabs/node-switchbot/issues/3))

### Changes
## What's Changed

@@ -176,3 +185,3 @@ - Fixed the bug that temperature value lower than 0 degC could not be handled. (Thanks to [@musimasami](https://github.com/OpenWonderLabs/node-switchbot/issues/2))

### Changes
## What's Changed

@@ -186,4 +195,4 @@ - Now the characteristic UUID `0x2a00` (Device Name) is not mandatory. Some models of Bot don't seem to support the characteristic. (Thanks to [@dnicolson](https://github.com/OpenWonderLabs/node-switchbot/issues/1))

### Changes
## What's Changed
- First public release
- First public release

@@ -1,2 +0,2 @@

'use strict';
"use strict";

@@ -15,3 +15,3 @@ class ParameterChecker {

// name: 'age',
// }
// }
// ---------------------------------

@@ -22,38 +22,38 @@ return this._error;

isSpecified(value) {
return (value === void 0) ? false : true;
return value === void 0 ? false : true;
}
/* ------------------------------------------------------------------
* check(obj, rule, required)
* - Check if the specified object contains valid values
*
* [Arguments]
* - obj | Object | Required | Object including parameters you want to check
* - rules | Object | Required | Object including rules for the parameters
* - required | Boolean | Optional | Flag whther the `obj` is required or not.
* | | | The default is `false`
*
* [Return value]
* - If the value is valid, this method will return `true`.
* - If the value is invalid, this method will return `false` and
* an `Error` object will be set to `this._error`.
*
* [Usage]
* let valid = parameterChecker.check(params, {
* level: {
* required: false,
* type: 'integer',
* max: 100
* },
* greeting: {
* required: true, // But an empty string is allowed.
* type: 'string',
* max: 20 // the number of characters must be up to 20.
* }
* });
* if(!valid) {
* let e = parameterChecker.error.message;
* throw new Error(message);
* }
* ---------------------------------------------------------------- */
* check(obj, rule, required)
* - Check if the specified object contains valid values
*
* [Arguments]
* - obj | Object | Required | Object including parameters you want to check
* - rules | Object | Required | Object including rules for the parameters
* - required | Boolean | Optional | Flag whther the `obj` is required or not.
* | | | The default is `false`
*
* [Return value]
* - If the value is valid, this method will return `true`.
* - If the value is invalid, this method will return `false` and
* an `Error` object will be set to `this._error`.
*
* [Usage]
* let valid = parameterChecker.check(params, {
* level: {
* required: false,
* type: 'integer',
* max: 100
* },
* greeting: {
* required: true, // But an empty string is allowed.
* type: 'string',
* max: 20 // the number of characters must be up to 20.
* }
* });
* if(!valid) {
* let e = parameterChecker.error.message;
* throw new Error(message);
* }
* ---------------------------------------------------------------- */
check(obj, rules, required = false) {

@@ -64,4 +64,4 @@ this._error = null;

this._error = {
code: 'MISSING_REQUIRED',
message: 'The first argument is missing.'
code: "MISSING_REQUIRED",
message: "The first argument is missing.",
};

@@ -78,4 +78,4 @@ return false;

this._error = {
code: 'MISSING_REQUIRED',
message: 'The first argument is missing.'
code: "MISSING_REQUIRED",
message: "The first argument is missing.",
};

@@ -100,4 +100,4 @@ return false;

this._error = {
code: 'MISSING_REQUIRED',
message: 'The `' + name + '` is required.'
code: "MISSING_REQUIRED",
message: "The `" + name + "` is required.",
};

@@ -110,13 +110,13 @@ break;

if (rule.type === 'float') {
if (rule.type === "float") {
result = this.isFloat(v, rule, name);
} else if (rule.type === 'integer') {
} else if (rule.type === "integer") {
result = this.isInteger(v, rule, name);
} else if (rule.type === 'boolean') {
} else if (rule.type === "boolean") {
result = this.isBoolean(v, rule, name);
} else if (rule.type === 'array') {
} else if (rule.type === "array") {
result = this.isArray(v, rule, name);
} else if (rule.type === 'object') {
} else if (rule.type === "object") {
result = this.isObject(v, rule, name);
} else if (rule.type === 'string') {
} else if (rule.type === "string") {
result = this.isString(v, rule, name);

@@ -126,4 +126,8 @@ } else {

this._error = {
code: 'TYPE_UNKNOWN',
message: 'The rule specified for the `' + name + '` includes an unknown type: ' + rule.type,
code: "TYPE_UNKNOWN",
message:
"The rule specified for the `" +
name +
"` includes an unknown type: " +
rule.type,
};

@@ -142,23 +146,23 @@ }

/* ------------------------------------------------------------------
* isFloat(value, rule, name)
* - Check if the value is a float
*
* [Arguments]
* - value | Any | Required | The value you want to check
* - rule | Object | Optional |
* - required | Boolean | Optional | Required or not. Default is `false`.
* - min | Float | Optional | Minimum number
* - max | Float | Optional | Maximum number
* - enum | Array | Optional | list of possible values
* - name | String | Optional | Parameter name
*
* If non-number value is specified to the `min` or `max`,
* they will be ignored.
*
* [Return value]
* - If the value is valid, this method will return `true`.
* - If the value is invalid, this method will return `false` and
* an `Error` object will be set to `this._error`.
* ---------------------------------------------------------------- */
isFloat(value, rule = {}, name = 'value') {
* isFloat(value, rule, name)
* - Check if the value is a float
*
* [Arguments]
* - value | Any | Required | The value you want to check
* - rule | Object | Optional |
* - required | Boolean | Optional | Required or not. Default is `false`.
* - min | Float | Optional | Minimum number
* - max | Float | Optional | Maximum number
* - enum | Array | Optional | list of possible values
* - name | String | Optional | Parameter name
*
* If non-number value is specified to the `min` or `max`,
* they will be ignored.
*
* [Return value]
* - If the value is valid, this method will return `true`.
* - If the value is invalid, this method will return `false` and
* an `Error` object will be set to `this._error`.
* ---------------------------------------------------------------- */
isFloat(value, rule = {}, name = "value") {
this._error = null;

@@ -170,6 +174,6 @@

if (typeof (value) !== 'number') {
if (typeof value !== "number") {
this._error = {
code: 'TYPE_INVALID',
message: 'The `' + name + '` must be a number (integer or float).'
code: "TYPE_INVALID",
message: "The `" + name + "` must be a number (integer or float).",
};

@@ -179,7 +183,12 @@ return false;

if (typeof (rule.min) === 'number') {
if (typeof rule.min === "number") {
if (value < rule.min) {
this._error = {
code: 'VALUE_UNDERFLOW',
message: 'The `' + name + '` must be grater than or equal to ' + rule.min + '.'
code: "VALUE_UNDERFLOW",
message:
"The `" +
name +
"` must be grater than or equal to " +
rule.min +
".",
};

@@ -189,7 +198,12 @@ return false;

}
if (typeof (rule.max) === 'number') {
if (typeof rule.max === "number") {
if (value > rule.max) {
this._error = {
code: 'VALUE_OVERFLOW',
message: 'The `' + name + '` must be less than or equal to ' + rule.max + '.'
code: "VALUE_OVERFLOW",
message:
"The `" +
name +
"` must be less than or equal to " +
rule.max +
".",
};

@@ -202,4 +216,9 @@ return false;

this._error = {
code: 'ENUM_UNMATCH',
message: 'The `' + name + '` must be any one of ' + JSON.stringify(rule.enum) + '.'
code: "ENUM_UNMATCH",
message:
"The `" +
name +
"` must be any one of " +
JSON.stringify(rule.enum) +
".",
};

@@ -214,23 +233,23 @@ return false;

/* ------------------------------------------------------------------
* isInteger(value, rule)
* - Check if the value is an integer
*
* [Arguments]
* - value | Any | Required | The value you want to check
* - rule | Object | Optional |
* - required | Boolean | Optional | Required or not. Default is `false`.|
* - min | Float | Optional | Minimum number
* - max | Float | Optional | Maximum number
* - enum | Array | Optional | list of possible values
* - name | String | Optional | Parameter name
*
* If non-number value is specified to the `min` or `max`,
* they will be ignored.
*
* [Return value]
* - If the value is valid, this method will return `true`.
* - If the value is invalid, this method will return `false` and
* an `Error` object will be set to `this._error`.
* ---------------------------------------------------------------- */
isInteger(value, rule = {}, name = 'value') {
* isInteger(value, rule)
* - Check if the value is an integer
*
* [Arguments]
* - value | Any | Required | The value you want to check
* - rule | Object | Optional |
* - required | Boolean | Optional | Required or not. Default is `false`.|
* - min | Float | Optional | Minimum number
* - max | Float | Optional | Maximum number
* - enum | Array | Optional | list of possible values
* - name | String | Optional | Parameter name
*
* If non-number value is specified to the `min` or `max`,
* they will be ignored.
*
* [Return value]
* - If the value is valid, this method will return `true`.
* - If the value is invalid, this method will return `false` and
* an `Error` object will be set to `this._error`.
* ---------------------------------------------------------------- */
isInteger(value, rule = {}, name = "value") {
this._error = null;

@@ -247,4 +266,4 @@

this._error = {
code: 'TYPE_INVALID',
message: 'The `' + name + '` must be an integer.'
code: "TYPE_INVALID",
message: "The `" + name + "` must be an integer.",
};

@@ -259,17 +278,17 @@ return false;

/* ------------------------------------------------------------------
* isBoolean(value, rule, name)
* - Check if the value is a boolean.
*
* [Arguments]
* - value | Any | Required | The value you want to check
* - rule | Object | Optional |
* - required | Boolean | Optional | Required or not. Default is `false`.
* - name | String | Optional | Parameter name
*
* [Return value]
* - If the value is valid, this method will return `true`.
* - If the value is invalid, this method will return `false` and
* an `Error` object will be set to `this._error`.
* ---------------------------------------------------------------- */
isBoolean(value, rule = {}, name = 'value') {
* isBoolean(value, rule, name)
* - Check if the value is a boolean.
*
* [Arguments]
* - value | Any | Required | The value you want to check
* - rule | Object | Optional |
* - required | Boolean | Optional | Required or not. Default is `false`.
* - name | String | Optional | Parameter name
*
* [Return value]
* - If the value is valid, this method will return `true`.
* - If the value is invalid, this method will return `false` and
* an `Error` object will be set to `this._error`.
* ---------------------------------------------------------------- */
isBoolean(value, rule = {}, name = "value") {
this._error = null;

@@ -281,6 +300,6 @@

if (typeof (value) !== 'boolean') {
if (typeof value !== "boolean") {
this._error = {
code: 'TYPE_INVALID',
message: 'The `' + name + '` must be boolean.'
code: "TYPE_INVALID",
message: "The `" + name + "` must be boolean.",
};

@@ -293,17 +312,17 @@ return false;

/* ------------------------------------------------------------------
* isObject(value)
* - Check if the value is an object
*
* [Arguments]
* - value | Any | Required | The value you want to check
* - rule | Object | Optional |
* - required | Boolean | Optional | Required or not. Default is `false`.
* - name | String | Optional | Parameter name
*
* [Return value]
* - If the value is valid, this method will return `true`.
* - If the value is invalid, this method will return `false` and
* an `Error` object will be set to `this._error`.
* ---------------------------------------------------------------- */
isObject(value, rule = {}, name = 'value') {
* isObject(value)
* - Check if the value is an object
*
* [Arguments]
* - value | Any | Required | The value you want to check
* - rule | Object | Optional |
* - required | Boolean | Optional | Required or not. Default is `false`.
* - name | String | Optional | Parameter name
*
* [Return value]
* - If the value is valid, this method will return `true`.
* - If the value is invalid, this method will return `false` and
* an `Error` object will be set to `this._error`.
* ---------------------------------------------------------------- */
isObject(value, rule = {}, name = "value") {
this._error = null;

@@ -314,6 +333,6 @@ if (!rule.required && !this.isSpecified(value)) {

if (typeof (value) !== 'object' || value === null || Array.isArray(value)) {
if (typeof value !== "object" || value === null || Array.isArray(value)) {
this._error = {
code: 'TYPE_INVALID',
message: 'The `' + name + '` must be an object.'
code: "TYPE_INVALID",
message: "The `" + name + "` must be an object.",
};

@@ -326,22 +345,22 @@ return false;

/* ------------------------------------------------------------------
* isArray(value, rule, name)
* - Check if the value is an `Array` object
*
* [Arguments]
* - value | Any | Required | The value you want to check
* - rule | Object | Optional |
* - required | Boolean | Optional | Required or not. Default is `false`.
* - min | Integer | Optional | Minimum number of elements in the array
* - max | Integer | Optional | Maximum number of elements in the array
* - name | String | Optional | Parameter name
*
* If non-number value is specified to the `min` or `max`,
* they will be ignored.
*
* [Return value]
* - If the value is valid, this method will return `true`.
* - If the value is invalid, this method will return `false` and
* an `Error` object will be set to `this._error`.
* ---------------------------------------------------------------- */
isArray(value, rule = {}, name = 'value') {
* isArray(value, rule, name)
* - Check if the value is an `Array` object
*
* [Arguments]
* - value | Any | Required | The value you want to check
* - rule | Object | Optional |
* - required | Boolean | Optional | Required or not. Default is `false`.
* - min | Integer | Optional | Minimum number of elements in the array
* - max | Integer | Optional | Maximum number of elements in the array
* - name | String | Optional | Parameter name
*
* If non-number value is specified to the `min` or `max`,
* they will be ignored.
*
* [Return value]
* - If the value is valid, this method will return `true`.
* - If the value is invalid, this method will return `false` and
* an `Error` object will be set to `this._error`.
* ---------------------------------------------------------------- */
isArray(value, rule = {}, name = "value") {
this._error = null;

@@ -355,4 +374,4 @@

this._error = {
code: 'TYPE_INVALID',
message: 'The value must be an array.'
code: "TYPE_INVALID",
message: "The value must be an array.",
};

@@ -362,7 +381,12 @@ return false;

if (typeof (rule.min) === 'number') {
if (typeof rule.min === "number") {
if (value.length < rule.min) {
this._error = {
code: 'LENGTH_UNDERFLOW',
message: 'The number of characters in the `' + name + '` must be grater than or equal to ' + rule.min + '.'
code: "LENGTH_UNDERFLOW",
message:
"The number of characters in the `" +
name +
"` must be grater than or equal to " +
rule.min +
".",
};

@@ -372,7 +396,12 @@ return false;

}
if (typeof (rule.max) === 'number') {
if (typeof rule.max === "number") {
if (value.length > rule.max) {
this._error = {
code: 'LENGTH_OVERFLOW',
message: 'The number of characters in the `' + name + '` must be less than or equal to ' + rule.max + '.'
code: "LENGTH_OVERFLOW",
message:
"The number of characters in the `" +
name +
"` must be less than or equal to " +
rule.max +
".",
};

@@ -387,26 +416,26 @@ return false;

/* ------------------------------------------------------------------
* isString(value, rule, name)
* - Check if the value is an `Array` object
*
* [Arguments]
* - value | Any | Required | The value you want to check
* - rule | Object | Optional |
* - required | Boolean | Optional | Required or not. Default is `false`.
* - min | Integer | Optional | Minimum number of characters in the string
* - max | Integer | Optional | Maximum number of characters in the string
* - minBytes | Integer | Optional | Minimum bytes of the string (UTF-8)
* - maxBytes | Integer | Optional | Maximum bytes of the string (UTF-8)
* - pattern | RegExp | Optional | Pattern of the string
* - enum | Array | Optional | list of possible values
* - name | String | Optional | Parameter name
*
* If non-number value is specified to the `min` or `max`,
* they will be ignored.
*
* [Return value]
* - If the value is valid, this method will return `true`.
* - If the value is invalid, this method will return `false` and
* an `Error` object will be set to `this._error`.
* ---------------------------------------------------------------- */
isString(value, rule = {}, name = 'value') {
* isString(value, rule, name)
* - Check if the value is an `Array` object
*
* [Arguments]
* - value | Any | Required | The value you want to check
* - rule | Object | Optional |
* - required | Boolean | Optional | Required or not. Default is `false`.
* - min | Integer | Optional | Minimum number of characters in the string
* - max | Integer | Optional | Maximum number of characters in the string
* - minBytes | Integer | Optional | Minimum bytes of the string (UTF-8)
* - maxBytes | Integer | Optional | Maximum bytes of the string (UTF-8)
* - pattern | RegExp | Optional | Pattern of the string
* - enum | Array | Optional | list of possible values
* - name | String | Optional | Parameter name
*
* If non-number value is specified to the `min` or `max`,
* they will be ignored.
*
* [Return value]
* - If the value is valid, this method will return `true`.
* - If the value is invalid, this method will return `false` and
* an `Error` object will be set to `this._error`.
* ---------------------------------------------------------------- */
isString(value, rule = {}, name = "value") {
this._error = null;

@@ -418,6 +447,6 @@

if (typeof (value) !== 'string') {
if (typeof value !== "string") {
this._error = {
code: 'TYPE_INVALID',
message: 'The value must be a string.'
code: "TYPE_INVALID",
message: "The value must be a string.",
};

@@ -427,7 +456,12 @@ return false;

if (typeof (rule.min) === 'number') {
if (typeof rule.min === "number") {
if (value.length < rule.min) {
this._error = {
code: 'LENGTH_UNDERFLOW',
message: 'The number of characters in the `' + name + '` must be grater than or equal to ' + rule.min + '.'
code: "LENGTH_UNDERFLOW",
message:
"The number of characters in the `" +
name +
"` must be grater than or equal to " +
rule.min +
".",
};

@@ -437,7 +471,12 @@ return false;

}
if (typeof (rule.max) === 'number') {
if (typeof rule.max === "number") {
if (value.length > rule.max) {
this._error = {
code: 'LENGTH_OVERFLOW',
message: 'The number of characters in the `' + name + '` must be less than or equal to ' + rule.max + '.'
code: "LENGTH_OVERFLOW",
message:
"The number of characters in the `" +
name +
"` must be less than or equal to " +
rule.max +
".",
};

@@ -447,8 +486,15 @@ return false;

}
if (typeof (rule.minBytes) === 'number') {
let blen = Buffer.from(value, 'utf8').length;
if (typeof rule.minBytes === "number") {
let blen = Buffer.from(value, "utf8").length;
if (blen < rule.minBytes) {
this._error = {
code: 'LENGTH_UNDERFLOW',
message: 'The byte length of the `' + name + '` (' + blen + ' bytes) must be grater than or equal to ' + rule.minBytes + ' bytes.'
code: "LENGTH_UNDERFLOW",
message:
"The byte length of the `" +
name +
"` (" +
blen +
" bytes) must be grater than or equal to " +
rule.minBytes +
" bytes.",
};

@@ -458,8 +504,15 @@ return false;

}
if (typeof (rule.maxBytes) === 'number') {
let blen = Buffer.from(value, 'utf8').length;
if (typeof rule.maxBytes === "number") {
let blen = Buffer.from(value, "utf8").length;
if (blen > rule.maxBytes) {
this._error = {
code: 'LENGTH_OVERFLOW',
message: 'The byte length of the `' + name + '` (' + blen + ' bytes) must be less than or equal to ' + rule.maxBytes + ' bytes.'
code: "LENGTH_OVERFLOW",
message:
"The byte length of the `" +
name +
"` (" +
blen +
" bytes) must be less than or equal to " +
rule.maxBytes +
" bytes.",
};

@@ -472,4 +525,4 @@ return false;

this._error = {
code: 'PATTERN_UNMATCH',
message: 'The `' + name + '` does not conform with the pattern.'
code: "PATTERN_UNMATCH",
message: "The `" + name + "` does not conform with the pattern.",
};

@@ -482,4 +535,9 @@ return false;

this._error = {
code: 'ENUM_UNMATCH',
message: 'The `' + name + '` must be any one of ' + JSON.stringify(rule.enum) + '.'
code: "ENUM_UNMATCH",
message:
"The `" +
name +
"` must be any one of " +
JSON.stringify(rule.enum) +
".",
};

@@ -486,0 +544,0 @@ return false;

@@ -1,63 +0,63 @@

'use strict';
"use strict";
class SwitchbotAdvertising {
constructor() { }
constructor() {}
/* ------------------------------------------------------------------
* parse(peripheral)
* - Parse advertising packets coming from switchbot devices
*
* [Arguments]
* - peripheral | Object | Required | A `Peripheral` object of noble
*
* [Return value]
* - An object as follows:
*
* WoHand
* {
* id: 'c12e453e2008',
* address: 'c1:2e:45:3e:20:08',
* rssi: -43,
* serviceData: {
* model: 'H',
* modelName: 'WoHand',
* mode: false,
* state: false,
* battery: 95
* }
* }
*
* WoSensorTH
* {
* id: 'cb4eb903c96d',
* address: 'cb:4e:b9:03:c9:6d',
* rssi: -54,
* serviceData: {
* model: 'T',
* modelName: 'WoSensorTH',
* temperature: { c: 26.2, f: 79.2 },
* fahrenheit: false,
* humidity: 45,
* battery: 100
* }
* }
*
* WoCurtain
* {
* id: 'ec58c5d00111',
* address: 'ec:58:c5:d0:01:11',
* rssi: -39,
* serviceData: {
* model: 'c',
* modelName: 'WoCurtain',
* calibration: true,
* battery: 91,
* position: 1,
* lightLevel: 1
* }
* }
*
* If the specified `Peripheral` does not represent any switchbot
* device, this method will return `null`.
* ---------------------------------------------------------------- */
* parse(peripheral)
* - Parse advertising packets coming from switchbot devices
*
* [Arguments]
* - peripheral | Object | Required | A `Peripheral` object of noble
*
* [Return value]
* - An object as follows:
*
* WoHand
* {
* id: 'c12e453e2008',
* address: 'c1:2e:45:3e:20:08',
* rssi: -43,
* serviceData: {
* model: 'H',
* modelName: 'WoHand',
* mode: false,
* state: false,
* battery: 95
* }
* }
*
* WoSensorTH
* {
* id: 'cb4eb903c96d',
* address: 'cb:4e:b9:03:c9:6d',
* rssi: -54,
* serviceData: {
* model: 'T',
* modelName: 'WoSensorTH',
* temperature: { c: 26.2, f: 79.2 },
* fahrenheit: false,
* humidity: 45,
* battery: 100
* }
* }
*
* WoCurtain
* {
* id: 'ec58c5d00111',
* address: 'ec:58:c5:d0:01:11',
* rssi: -39,
* serviceData: {
* model: 'c',
* modelName: 'WoCurtain',
* calibration: true,
* battery: 91,
* position: 1,
* lightLevel: 1
* }
* }
*
* If the specified `Peripheral` does not represent any switchbot
* device, this method will return `null`.
* ---------------------------------------------------------------- */
parse(peripheral, onlog) {

@@ -69,35 +69,59 @@ let ad = peripheral.advertisement;

let serviceData = ad.serviceData[0] || ad.serviceData;
let manufacturerData = ad.manufacturerData;
let buf = serviceData.data;
if (!buf || !Buffer.isBuffer(buf) || buf.length < 3) {
const bufIsInvalid = !buf || !Buffer.isBuffer(buf) || buf.length < 3;
const manufacturerDataIsInvalid =
!manufacturerData ||
!Buffer.isBuffer(manufacturerData) ||
manufacturerData.length < 3;
if (bufIsInvalid && manufacturerDataIsInvalid) {
return null;
}
let model = buf.slice(0, 1).toString('utf8');
let model = buf.slice(0, 1).toString("utf8");
let sd = null;
if (model === 'H') { // WoHand
if (model === "H") {
// WoHand
sd = this._parseServiceDataForWoHand(buf, onlog);
} else if (model === 'T') { // WoSensorTH
} else if (model === "T") {
// WoSensorTH
sd = this._parseServiceDataForWoSensorTH(buf, onlog);
} else if (model === 'e') { // WoHumi
} else if (model === "e") {
// WoHumi
sd = this._parseServiceDataForWoHumi(buf, onlog);
} else if (model === 's') { // WoMotion
} else if (model === "s") {
// WoMotion
sd = this._parseServiceDataForWoPresence(buf, onlog);
} else if (model === 'd') { // WoContact
} else if (model === "d") {
// WoContact
sd = this._parseServiceDataForWoContact(buf, onlog);
} else if (model === 'c') { // WoCurtain
} else if (model === "c") {
// WoCurtain
sd = this._parseServiceDataForWoCurtain(buf, onlog);
} else if (model === 'u') { // WoColorBulb
} else if (model === "u") {
// WoColorBulb
sd = this._parseServiceDataForWoColorBulb(buf, onlog);
} else if (model === 'g') { // WoPlugMini
} else if (model === "g") {
// WoPlugMini
sd = this._parseServiceDataForWoPlugMini(buf, onlog);
} else if (model === 'o') { // WoSmartLock
} else if (model === "j") {
// WoPlugMini (JP) ??
sd = this._parseServiceDataForWoPlugMini(manufacturerData, onlog);
} else if (model === "o") {
// WoSmartLock
sd = this._parseServiceDataForWoSmartLock(buf, onlog);
} else if (model === 'i') { // WoMeterPlus
} else if (model === "i") {
// WoMeterPlus
sd = this._parseServiceDataForWoSensorTHPlus(buf, onlog);
} else if (model === 'r') { // WoLEDStripLight
} else if (model === "r") {
// WoLEDStripLight
sd = this._parseServiceDataForWoLEDStripLight(buf, onlog);
} else {
if (onlog && typeof onlog === 'function') {
onlog(`[parseAdvertising.${peripheral.id}] return null, model "${model}" not available!`);
if (onlog && typeof onlog === "function") {
onlog(
`[parseAdvertising.${peripheral.id}] return null, model "${model}" not available!`
);
}

@@ -108,12 +132,16 @@ return null;

if (!sd) {
if (onlog && typeof onlog === 'function') {
onlog(`[parseAdvertising.${peripheral.id}.${model}] return null, parsed serviceData empty!`);
if (onlog && typeof onlog === "function") {
onlog(
`[parseAdvertising.${peripheral.id}.${model}] return null, parsed serviceData empty!`
);
}
return null;
}
let address = peripheral.address || '';
if (address === '') {
address = peripheral.advertisement.manufacturerData || '';
if (address !== '') {
const str = peripheral.advertisement.manufacturerData.toString('hex').slice(4);
let address = peripheral.address || "";
if (address === "") {
address = peripheral.advertisement.manufacturerData || "";
if (address !== "") {
const str = peripheral.advertisement.manufacturerData
.toString("hex")
.slice(4, 16);
address = str.substr(0, 2);

@@ -125,6 +153,5 @@ for (var i = 2; i < str.length; i += 2) {

}
} else {
address = address.replace(/-/g, ":");
}
else {
address = address.replace(/-/g, ':');
}
let data = {

@@ -134,7 +161,11 @@ id: peripheral.id,

rssi: peripheral.rssi,
serviceData: sd
serviceData: sd,
};
if (onlog && typeof onlog === 'function') {
onlog(`[parseAdvertising.${peripheral.id}.${model}] return ${JSON.stringify(data)}`);
if (onlog && typeof onlog === "function") {
onlog(
`[parseAdvertising.${peripheral.id}.${model}] return ${JSON.stringify(
data
)}`
);
}

@@ -146,4 +177,6 @@ return data;

if (buf.length !== 3) {
if (onlog && typeof onlog === 'function') {
onlog(`[_parseServiceDataForWoHand] Buffer length ${buf.length} !== 3!`);
if (onlog && typeof onlog === "function") {
onlog(
`[_parseServiceDataForWoHand] Buffer length ${buf.length} !== 3!`
);
}

@@ -155,12 +188,12 @@ return null;

let mode = (byte1 & 0b10000000) ? true : false; // Whether the light switch Add-on is used or not
let state = (byte1 & 0b01000000) ? true : false; // Whether the switch status is ON or OFF
let mode = byte1 & 0b10000000 ? true : false; // Whether the light switch Add-on is used or not
let state = byte1 & 0b01000000 ? true : false; // Whether the switch status is ON or OFF
let battery = byte2 & 0b01111111; // %
let data = {
model: 'H',
modelName: 'WoHand',
model: "H",
modelName: "WoHand",
mode: mode,
state: state,
battery: battery
battery: battery,
};

@@ -173,4 +206,6 @@

if (buf.length !== 6) {
if (onlog && typeof onlog === 'function') {
onlog(`[_parseServiceDataForWoSensorTH] Buffer length ${buf.length} !== 6!`);
if (onlog && typeof onlog === "function") {
onlog(
`[_parseServiceDataForWoSensorTH] Buffer length ${buf.length} !== 6!`
);
}

@@ -184,17 +219,17 @@ return null;

let temp_sign = (byte4 & 0b10000000) ? 1 : -1;
let temp_c = temp_sign * ((byte4 & 0b01111111) + (byte3 / 10));
let temp_f = (temp_c * 9 / 5) + 32;
let temp_sign = byte4 & 0b10000000 ? 1 : -1;
let temp_c = temp_sign * ((byte4 & 0b01111111) + byte3 / 10);
let temp_f = (temp_c * 9) / 5 + 32;
temp_f = Math.round(temp_f * 10) / 10;
let data = {
model: 'T',
modelName: 'WoSensorTH',
model: "T",
modelName: "WoSensorTH",
temperature: {
c: temp_c,
f: temp_f
f: temp_f,
},
fahrenheit: (byte5 & 0b10000000) ? true : false,
fahrenheit: byte5 & 0b10000000 ? true : false,
humidity: byte5 & 0b01111111,
battery: (byte2 & 0b01111111)
battery: byte2 & 0b01111111,
};

@@ -207,4 +242,6 @@

if (buf.length !== 8) {
if (onlog && typeof onlog === 'function') {
onlog(`[_parseServiceDataForWoHumi] Buffer length ${buf.length} !== 8!`);
if (onlog && typeof onlog === "function") {
onlog(
`[_parseServiceDataForWoHumi] Buffer length ${buf.length} !== 8!`
);
}

@@ -219,9 +256,9 @@ return null;

let onState = (byte1 & 0b10000000) ? true : false; // 1 - on
let autoMode = (byte4 & 0b10000000) ? true : false; // 1 - auto
let onState = byte1 & 0b10000000 ? true : false; // 1 - on
let autoMode = byte4 & 0b10000000 ? true : false; // 1 - auto
let percentage = byte4 & 0b01111111; // 0-100%, 101/102/103 - Quick gear 1/2/3
let data = {
model: 'e',
modelName: 'WoHumi',
model: "e",
modelName: "WoHumi",
onState: onState,

@@ -237,4 +274,6 @@ autoMode: autoMode,

if (buf.length !== 6) {
if (onlog && typeof onlog === 'function') {
onlog(`[_parseServiceDataForWoPresence] Buffer length ${buf.length} !== 6!`);
if (onlog && typeof onlog === "function") {
onlog(
`[_parseServiceDataForWoPresence] Buffer length ${buf.length} !== 6!`
);
}

@@ -249,3 +288,3 @@ return null;

let pirState = (byte1 & 0b01000000) ? true : false; // 1 - Movement detected
let pirState = byte1 & 0b01000000 ? true : false; // 1 - Movement detected
let battery = byte2 & 0b01111111; // %

@@ -255,7 +294,8 @@ let lightLevel = byte5 & 0b00000011;

let data = {
model: 's',
modelName: 'WoMotion',
model: "s",
modelName: "WoMotion",
movement: pirState,
battery: battery,
lightLevel: (lightLevel == 1) ? 'dark' : ((lightLevel == 2) ? 'bright' : 'unknown'),
lightLevel:
lightLevel == 1 ? "dark" : lightLevel == 2 ? "bright" : "unknown",
};

@@ -268,4 +308,6 @@

if (buf.length !== 9) {
if (onlog && typeof onlog === 'function') {
onlog(`[_parseServiceDataForWoContact] Buffer length ${buf.length} !== 9!`);
if (onlog && typeof onlog === "function") {
onlog(
`[_parseServiceDataForWoContact] Buffer length ${buf.length} !== 9!`
);
}

@@ -284,3 +326,3 @@ return null;

let pirState = (byte1 & 0b01000000) ? true : false; // 1 - Movement detected
let pirState = byte1 & 0b01000000 ? true : false; // 1 - Movement detected
let battery = byte2 & 0b01111111; // %

@@ -291,8 +333,13 @@ let hallState = (byte3 >> 1) & 0b00000011;

let data = {
model: 'd',
modelName: 'WoContact',
model: "d",
modelName: "WoContact",
movement: pirState,
battery: battery,
doorState: (hallState == 0) ? 'close' : ((hallState == 1) ? 'open' : 'timeout no closed'),
lightLevel: (lightLevel == 0) ? 'dark' : 'bright',
doorState:
hallState == 0
? "close"
: hallState == 1
? "open"
: "timeout no closed",
lightLevel: lightLevel == 0 ? "dark" : "bright",
};

@@ -305,4 +352,6 @@

if (buf.length !== 5 && buf.length !== 6) {
if (onlog && typeof onlog === 'function') {
onlog(`[_parseServiceDataForWoCurtain] Buffer length ${buf.length} !== 5 or 6!`);
if (onlog && typeof onlog === "function") {
onlog(
`[_parseServiceDataForWoCurtain] Buffer length ${buf.length} !== 5 or 6!`
);
}

@@ -317,3 +366,3 @@ return null;

let calibration = (byte1 & 0b01000000) ? true : false; // Whether the calibration is completed
let calibration = byte1 & 0b01000000 ? true : false; // Whether the calibration is completed
let battery = byte2 & 0b01111111; // %

@@ -324,8 +373,8 @@ let currPosition = byte3 & 0b01111111; // current positon %

let data = {
model: 'c',
modelName: 'WoCurtain',
model: "c",
modelName: "WoCurtain",
calibration: calibration,
battery: battery,
position: currPosition,
lightLevel: lightLevel
lightLevel: lightLevel,
};

@@ -338,4 +387,6 @@

if (buf.length !== 6) {
if (onlog && typeof onlog === 'function') {
onlog(`[_parseServiceDataForWoColorBulb] Buffer length ${buf.length} !== 6!`);
if (onlog && typeof onlog === "function") {
onlog(
`[_parseServiceDataForWoColorBulb] Buffer length ${buf.length} !== 6!`
);
}

@@ -351,4 +402,4 @@ return null;

let data = {
model: 'u',
modelName: 'WoColorBulb',
model: "u",
modelName: "WoColorBulb",
};

@@ -360,17 +411,35 @@

_parseServiceDataForWoPlugMini(buf, onlog) {
if (buf.length !== 6) {
if (onlog && typeof onlog === 'function') {
onlog(`[_parseServiceDataForWoPlugMini] Buffer length ${buf.length} !== 6!`);
if (buf.length !== 14) {
if (onlog && typeof onlog === "function") {
onlog(
`[_parseServiceDataForWoPlugMini] Buffer length ${buf.length} should be 14`
);
}
return null;
}
let byte1 = buf.readUInt8(1);
let byte2 = buf.readUInt8(2);
// let byte3 = buf.readUInt8(3);
// let byte4 = buf.readUInt8(4);
let byte5 = buf.readUInt8(5);
const byte9 = buf.readUInt8(9); // byte9: plug mini state; 0x00=off, 0x80=on
const byte10 = buf.readUInt8(10); // byte10: bit0: 0=no delay,1=delay, bit1:0=no timer, 1=timer; bit2:0=no sync time, 1=sync'ed time
const byte11 = buf.readUInt8(11); // byte11: wifi rssi
const byte12 = buf.readUInt8(12); // byte12: bit7: overload?
const byte13 = buf.readUInt8(13); // byte12[bit0~6] + byte13: current power value
let data = {
model: 'g',
modelName: 'WoPlugMini',
const state = byte9 === 0x00 ? "off" : byte9 === 0x80 ? "on" : null;
const delay = !!(byte10 & 0b00000001);
const timer = !!(byte10 & 0b00000010);
const syncUtcTime = !!(byte10 & 0b00000100);
const wifiRssi = byte11;
const overload = !!(byte12 & 0b10000000);
const currentPower = (((byte12 & 0b01111111) << 8) + byte13) / 10; // in watt
// TODO: voltage ???
const data = {
model: "j",
modelName: "WoPlugMini",
state: state,
delay: delay,
timer: timer,
syncUtcTime: syncUtcTime,
wifiRssi: wifiRssi,
overload: overload,
currentPower: currentPower,
};

@@ -383,4 +452,6 @@

if (buf.length !== 6) {
if (onlog && typeof onlog === 'function') {
onlog(`[_parseServiceDataForWoSmartLock] Buffer length ${buf.length} !== 6!`);
if (onlog && typeof onlog === "function") {
onlog(
`[_parseServiceDataForWoSmartLock] Buffer length ${buf.length} !== 6!`
);
}

@@ -400,4 +471,4 @@ return null;

let data = {
model: 'o',
modelName: 'WoSmartLock',
model: "o",
modelName: "WoSmartLock",
//movement: pirState,

@@ -413,4 +484,6 @@ battery: battery,

if (buf.length !== 6) {
if (onlog && typeof onlog === 'function') {
onlog(`[_parseServiceDataForWoSensorTHPlus] Buffer length ${buf.length} !== 6!`);
if (onlog && typeof onlog === "function") {
onlog(
`[_parseServiceDataForWoSensorTHPlus] Buffer length ${buf.length} !== 6!`
);
}

@@ -424,17 +497,17 @@ return null;

let temp_sign = (byte4 & 0b10000000) ? 1 : -1;
let temp_c = temp_sign * ((byte4 & 0b01111111) + (byte3 / 10));
let temp_f = (temp_c * 9 / 5) + 32;
let temp_sign = byte4 & 0b10000000 ? 1 : -1;
let temp_c = temp_sign * ((byte4 & 0b01111111) + byte3 / 10);
let temp_f = (temp_c * 9) / 5 + 32;
temp_f = Math.round(temp_f * 10) / 10;
let data = {
model: 'i',
modelName: 'WoSensorTHPlus',
model: "i",
modelName: "WoSensorTHPlus",
temperature: {
c: temp_c,
f: temp_f
f: temp_f,
},
fahrenheit: (byte5 & 0b10000000) ? true : false,
fahrenheit: byte5 & 0b10000000 ? true : false,
humidity: byte5 & 0b01111111,
battery: (byte2 & 0b01111111)
battery: byte2 & 0b01111111,
};

@@ -447,4 +520,6 @@

if (buf.length !== 6) {
if (onlog && typeof onlog === 'function') {
onlog(`[_parseServiceDataForWoLEDStripLight] Buffer length ${buf.length} !== 6!`);
if (onlog && typeof onlog === "function") {
onlog(
`[_parseServiceDataForWoLEDStripLight] Buffer length ${buf.length} !== 6!`
);
}

@@ -460,4 +535,4 @@ return null;

let data = {
model: 'r',
modelName: 'WoLEDStripLight',
model: "r",
modelName: "WoLEDStripLight",
};

@@ -464,0 +539,0 @@

@@ -1,9 +0,6 @@

'use strict';
const SwitchbotDevice = require('./switchbot-device.js');
"use strict";
const SwitchbotDevice = require("./switchbot-device.js");
class SwitchbotDeviceWoContact extends SwitchbotDevice {
class SwitchbotDeviceWoContact extends SwitchbotDevice {}
}
module.exports = SwitchbotDeviceWoContact;
module.exports = SwitchbotDeviceWoContact;

@@ -1,102 +0,117 @@

'use strict';
const SwitchbotDevice = require('./switchbot-device.js');
"use strict";
const SwitchbotDevice = require("./switchbot-device.js");
class SwitchbotDeviceWoCurtain extends SwitchbotDevice {
/* ------------------------------------------------------------------
* open()
* - Open the curtain
*
* [Arguments]
* - none
*
* [Return value]
* - Promise object
* Nothing will be passed to the `resolve()`.
* ---------------------------------------------------------------- */
open() {
return this._operateCurtain([0x57, 0x0f, 0x45, 0x01, 0x05, 0xff, 0x00]);
}
/* ------------------------------------------------------------------
* open()
* - Open the curtain
*
* [Arguments]
* - none
*
* [Return value]
* - Promise object
* Nothing will be passed to the `resolve()`.
* ---------------------------------------------------------------- */
open() {
return this._operateCurtain([0x57, 0x0f, 0x45, 0x01, 0x05, 0xff, 0x00]);
}
/* ------------------------------------------------------------------
* close()
* - close the curtain
*
* [Arguments]
* - none
*
* [Return value]
* - Promise object
* Nothing will be passed to the `resolve()`.
* ---------------------------------------------------------------- */
close() {
return this._operateCurtain([0x57, 0x0f, 0x45, 0x01, 0x05, 0xff, 0x64]);
}
/* ------------------------------------------------------------------
* close()
* - close the curtain
*
* [Arguments]
* - none
*
* [Return value]
* - Promise object
* Nothing will be passed to the `resolve()`.
* ---------------------------------------------------------------- */
close() {
return this._operateCurtain([0x57, 0x0f, 0x45, 0x01, 0x05, 0xff, 0x64]);
}
/* ------------------------------------------------------------------
* pause()
* - pause the curtain
*
* [Arguments]
* - none
*
* [Return value]
* - Promise object
* Nothing will be passed to the `resolve()`.
* ---------------------------------------------------------------- */
pause() {
return this._operateCurtain([0x57, 0x0f, 0x45, 0x01, 0x00, 0xff]);
}
/* ------------------------------------------------------------------
* pause()
* - pause the curtain
*
* [Arguments]
* - none
*
* [Return value]
* - Promise object
* Nothing will be passed to the `resolve()`.
* ---------------------------------------------------------------- */
pause() {
return this._operateCurtain([0x57, 0x0f, 0x45, 0x01, 0x00, 0xff]);
/* ------------------------------------------------------------------
* runToPos()
* - run to the targe position
*
* [Arguments]
* - percent | number | Required | the percentage of target position
*
* [Return value]
* - Promise object
* Nothing will be passed to the `resolve()`.
* ---------------------------------------------------------------- */
runToPos(percent, mode) {
if (typeof percent != "number") {
return new Promise((resolve, reject) => {
reject(
new Error(
"The type of target position percentage is incorrent: " +
typeof percent
)
);
});
}
/* ------------------------------------------------------------------
* runToPos()
* - run to the targe position
*
* [Arguments]
* - percent | number | Required | the percentage of target position
*
* [Return value]
* - Promise object
* Nothing will be passed to the `resolve()`.
* ---------------------------------------------------------------- */
runToPos(percent, mode) {
if (typeof percent != 'number') {
return new Promise((resolve, reject) => {
reject(new Error('The type of target position percentage is incorrent: ' + typeof percent));
});
}
if (mode == null) {
mode = 0xff;
}
else {
if (typeof mode != 'number') {
return new Promise((resolve, reject) => {
reject(new Error('The type of running mode is incorrent: ' + typeof mode));
});
}
if (mode > 1) { mode = 0xff; }
}
if (percent > 100) { percent = 100; }
else if (percent < 0) { percent = 0; }
return this._operateCurtain([0x57, 0x0f, 0x45, 0x01, 0x05, mode, percent]);
if (mode == null) {
mode = 0xff;
} else {
if (typeof mode != "number") {
return new Promise((resolve, reject) => {
reject(
new Error("The type of running mode is incorrent: " + typeof mode)
);
});
}
if (mode > 1) {
mode = 0xff;
}
}
if (percent > 100) {
percent = 100;
} else if (percent < 0) {
percent = 0;
}
return this._operateCurtain([0x57, 0x0f, 0x45, 0x01, 0x05, mode, percent]);
}
_operateCurtain(bytes) {
return new Promise((resolve, reject) => {
let req_buf = Buffer.from(bytes);
this._command(req_buf).then((res_buf) => {
let code = res_buf.readUInt8(0);
if (res_buf.length === 3 && code === 0x01) {
resolve();
} else {
reject(new Error('The device returned an error: 0x' + res_buf.toString('hex')));
}
}).catch((error) => {
reject(error);
});
_operateCurtain(bytes) {
return new Promise((resolve, reject) => {
let req_buf = Buffer.from(bytes);
this._command(req_buf)
.then((res_buf) => {
let code = res_buf.readUInt8(0);
if (res_buf.length === 3 && code === 0x01) {
resolve();
} else {
reject(
new Error(
"The device returned an error: 0x" + res_buf.toString("hex")
)
);
}
})
.catch((error) => {
reject(error);
});
}
});
}
}
module.exports = SwitchbotDeviceWoCurtain;
module.exports = SwitchbotDeviceWoCurtain;

@@ -1,17 +0,16 @@

'use strict';
const SwitchbotDevice = require('./switchbot-device.js');
"use strict";
const SwitchbotDevice = require("./switchbot-device.js");
class SwitchbotDeviceWoHand extends SwitchbotDevice {
/* ------------------------------------------------------------------
* press()
* - Press
*
* [Arguments]
* - none
*
* [Return value]
* - Promise object
* Nothing will be passed to the `resolve()`.
* ---------------------------------------------------------------- */
* press()
* - Press
*
* [Arguments]
* - none
*
* [Return value]
* - Promise object
* Nothing will be passed to the `resolve()`.
* ---------------------------------------------------------------- */
press() {

@@ -22,12 +21,12 @@ return this._operateBot([0x57, 0x01, 0x00]);

/* ------------------------------------------------------------------
* turnOn()
* - Turn on
*
* [Arguments]
* - none
*
* [Return value]
* - Promise object
* Nothing will be passed to the `resolve()`.
* ---------------------------------------------------------------- */
* turnOn()
* - Turn on
*
* [Arguments]
* - none
*
* [Return value]
* - Promise object
* Nothing will be passed to the `resolve()`.
* ---------------------------------------------------------------- */
turnOn() {

@@ -38,12 +37,12 @@ return this._operateBot([0x57, 0x01, 0x01]);

/* ------------------------------------------------------------------
* turnOff()
* - Turn off
*
* [Arguments]
* - none
*
* [Return value]
* - Promise object
* Nothing will be passed to the `resolve()`.
* ---------------------------------------------------------------- */
* turnOff()
* - Turn off
*
* [Arguments]
* - none
*
* [Return value]
* - Promise object
* Nothing will be passed to the `resolve()`.
* ---------------------------------------------------------------- */
turnOff() {

@@ -54,12 +53,12 @@ return this._operateBot([0x57, 0x01, 0x02]);

/* ------------------------------------------------------------------
* down()
* - Down
*
* [Arguments]
* - none
*
* [Return value]
* - Promise object
* Nothing will be passed to the `resolve()`.
* ---------------------------------------------------------------- */
* down()
* - Down
*
* [Arguments]
* - none
*
* [Return value]
* - Promise object
* Nothing will be passed to the `resolve()`.
* ---------------------------------------------------------------- */
down() {

@@ -70,12 +69,12 @@ return this._operateBot([0x57, 0x01, 0x03]);

/* ------------------------------------------------------------------
* up()
* - Up
*
* [Arguments]
* - none
*
* [Return value]
* - Promise object
* Nothing will be passed to the `resolve()`.
* ---------------------------------------------------------------- */
* up()
* - Up
*
* [Arguments]
* - none
*
* [Return value]
* - Promise object
* Nothing will be passed to the `resolve()`.
* ---------------------------------------------------------------- */
up() {

@@ -88,17 +87,22 @@ return this._operateBot([0x57, 0x01, 0x04]);

let req_buf = Buffer.from(bytes);
this._command(req_buf).then((res_buf) => {
let code = res_buf.readUInt8(0);
if (res_buf.length === 3 && (code === 0x01 || code === 0x05)) {
resolve();
} else {
reject(new Error('The device returned an error: 0x' + res_buf.toString('hex')));
}
}).catch((error) => {
reject(error);
});
this._command(req_buf)
.then((res_buf) => {
let code = res_buf.readUInt8(0);
if (res_buf.length === 3 && (code === 0x01 || code === 0x05)) {
resolve();
} else {
reject(
new Error(
"The device returned an error: 0x" + res_buf.toString("hex")
)
);
}
})
.catch((error) => {
reject(error);
});
});
}
}
module.exports = SwitchbotDeviceWoHand;
module.exports = SwitchbotDeviceWoHand;

@@ -1,17 +0,16 @@

'use strict';
const SwitchbotDevice = require('./switchbot-device.js');
"use strict";
const SwitchbotDevice = require("./switchbot-device.js");
class SwitchbotDeviceWoHumi extends SwitchbotDevice {
/* ------------------------------------------------------------------
* press()
* - Press
*
* [Arguments]
* - none
*
* [Return value]
* - Promise object
* Nothing will be passed to the `resolve()`.
* ---------------------------------------------------------------- */
* press()
* - Press
*
* [Arguments]
* - none
*
* [Return value]
* - Promise object
* Nothing will be passed to the `resolve()`.
* ---------------------------------------------------------------- */
press() {

@@ -22,12 +21,12 @@ return this._operateBot([0x57, 0x01, 0x00]);

/* ------------------------------------------------------------------
* turnOn()
* - Turn on
*
* [Arguments]
* - none
*
* [Return value]
* - Promise object
* Nothing will be passed to the `resolve()`.
* ---------------------------------------------------------------- */
* turnOn()
* - Turn on
*
* [Arguments]
* - none
*
* [Return value]
* - Promise object
* Nothing will be passed to the `resolve()`.
* ---------------------------------------------------------------- */
turnOn() {

@@ -38,12 +37,12 @@ return this._operateBot([0x57, 0x01, 0x01]);

/* ------------------------------------------------------------------
* turnOff()
* - Turn off
*
* [Arguments]
* - none
*
* [Return value]
* - Promise object
* Nothing will be passed to the `resolve()`.
* ---------------------------------------------------------------- */
* turnOff()
* - Turn off
*
* [Arguments]
* - none
*
* [Return value]
* - Promise object
* Nothing will be passed to the `resolve()`.
* ---------------------------------------------------------------- */
turnOff() {

@@ -54,12 +53,12 @@ return this._operateBot([0x57, 0x01, 0x02]);

/* ------------------------------------------------------------------
* down()
* - Down
*
* [Arguments]
* - none
*
* [Return value]
* - Promise object
* Nothing will be passed to the `resolve()`.
* ---------------------------------------------------------------- */
* down()
* - Down
*
* [Arguments]
* - none
*
* [Return value]
* - Promise object
* Nothing will be passed to the `resolve()`.
* ---------------------------------------------------------------- */
down() {

@@ -70,12 +69,12 @@ return this._operateBot([0x57, 0x01, 0x03]);

/* ------------------------------------------------------------------
* up()
* - Up
*
* [Arguments]
* - none
*
* [Return value]
* - Promise object
* Nothing will be passed to the `resolve()`.
* ---------------------------------------------------------------- */
* up()
* - Up
*
* [Arguments]
* - none
*
* [Return value]
* - Promise object
* Nothing will be passed to the `resolve()`.
* ---------------------------------------------------------------- */
up() {

@@ -88,17 +87,22 @@ return this._operateBot([0x57, 0x01, 0x04]);

let req_buf = Buffer.from(bytes);
this._command(req_buf).then((res_buf) => {
let code = res_buf.readUInt8(0);
if (res_buf.length === 3 && (code === 0x01 || code === 0x05)) {
resolve();
} else {
reject(new Error('The device returned an error: 0x' + res_buf.toString('hex')));
}
}).catch((error) => {
reject(error);
});
this._command(req_buf)
.then((res_buf) => {
let code = res_buf.readUInt8(0);
if (res_buf.length === 3 && (code === 0x01 || code === 0x05)) {
resolve();
} else {
reject(
new Error(
"The device returned an error: 0x" + res_buf.toString("hex")
)
);
}
})
.catch((error) => {
reject(error);
});
});
}
}
module.exports = SwitchbotDeviceWoHumi;
module.exports = SwitchbotDeviceWoHumi;

@@ -1,9 +0,6 @@

'use strict';
const SwitchbotDevice = require('./switchbot-device.js');
"use strict";
const SwitchbotDevice = require("./switchbot-device.js");
class SwitchbotDeviceWoPresence extends SwitchbotDevice {
class SwitchbotDeviceWoPresence extends SwitchbotDevice {}
}
module.exports = SwitchbotDeviceWoPresence;
module.exports = SwitchbotDeviceWoPresence;

@@ -1,9 +0,6 @@

'use strict';
const SwitchbotDevice = require('./switchbot-device.js');
"use strict";
const SwitchbotDevice = require("./switchbot-device.js");
class SwitchbotDeviceWoSensorTH extends SwitchbotDevice {
class SwitchbotDeviceWoSensorTH extends SwitchbotDevice {}
}
module.exports = SwitchbotDeviceWoSensorTH;
module.exports = SwitchbotDeviceWoSensorTH;

@@ -1,14 +0,14 @@

'use strict';
const parameterChecker = require('./parameter-checker.js');
const switchbotAdvertising = require('./switchbot-advertising.js');
"use strict";
const parameterChecker = require("./parameter-checker.js");
const switchbotAdvertising = require("./switchbot-advertising.js");
class SwitchbotDevice {
/* ------------------------------------------------------------------
* Constructor
*
* [Arguments]
* - peripheral | Object | Required | The `peripheral` object of noble,
* | | | which represents this device
* - noble | Noble | Required | The Nobel object created by the noble module.
* ---------------------------------------------------------------- */
* Constructor
*
* [Arguments]
* - peripheral | Object | Required | The `peripheral` object of noble,
* | | | which represents this device
* - noble | Noble | Required | The Nobel object created by the noble module.
* ---------------------------------------------------------------- */
constructor(peripheral, noble) {

@@ -19,6 +19,6 @@ this._peripheral = peripheral;

this._SERV_UUID_PRIMARY = 'cba20d00224d11e69fb80002a5d5c51b';
this._CHAR_UUID_WRITE = 'cba20002224d11e69fb80002a5d5c51b';
this._CHAR_UUID_NOTIFY = 'cba20003224d11e69fb80002a5d5c51b';
this._CHAR_UUID_DEVICE = '2a00';
this._SERV_UUID_PRIMARY = "cba20d00224d11e69fb80002a5d5c51b";
this._CHAR_UUID_WRITE = "cba20002224d11e69fb80002a5d5c51b";
this._CHAR_UUID_NOTIFY = "cba20003224d11e69fb80002a5d5c51b";
this._CHAR_UUID_DEVICE = "2a00";

@@ -39,6 +39,6 @@ this._READ_TIMEOUT_MSEC = 3000;

this._onconnect = () => { };
this._ondisconnect = () => { };
this._ondisconnect_internal = () => { };
this._onnotify_internal = () => { };
this._onconnect = () => {};
this._ondisconnect = () => {};
this._ondisconnect_internal = () => {};
this._onnotify_internal = () => {};
}

@@ -60,4 +60,4 @@

get connectionState() {
if (!this._connected && this._peripheral.state === 'disconnecting') {
return 'disconnected';
if (!this._connected && this._peripheral.state === "disconnecting") {
return "disconnected";
} else {

@@ -70,4 +70,4 @@ return this._peripheral.state;

set onconnect(func) {
if (!func || typeof (func) !== 'function') {
throw new Error('The `onconnect` must be a function.');
if (!func || typeof func !== "function") {
throw new Error("The `onconnect` must be a function.");
}

@@ -77,4 +77,4 @@ this._onconnect = func;

set ondisconnect(func) {
if (!func || typeof (func) !== 'function') {
throw new Error('The `ondisconnect` must be a function.');
if (!func || typeof func !== "function") {
throw new Error("The `ondisconnect` must be a function.");
}

@@ -85,12 +85,12 @@ this._ondisconnect = func;

/* ------------------------------------------------------------------
* connect()
* - Connect the device
*
* [Arguments]
* - none
*
* [Return value]
* - Promise object
* Nothing will be passed to the `resolve()`.
* ---------------------------------------------------------------- */
* connect()
* - Connect the device
*
* [Arguments]
* - none
*
* [Return value]
* - Promise object
* Nothing will be passed to the `resolve()`.
* ---------------------------------------------------------------- */
connect() {

@@ -104,4 +104,8 @@ this._was_connected_explicitly = true;

// Check the bluetooth state
if (this._noble.state !== 'poweredOn') {
reject(new Error('The Bluetooth status is ' + this._noble.state + ', not poweredOn.'));
if (this._noble.state !== "poweredOn") {
reject(
new Error(
"The Bluetooth status is " + this._noble.state + ", not poweredOn."
)
);
return;

@@ -112,7 +116,9 @@ }

let state = this.connectionState;
if (state === 'connected') {
if (state === "connected") {
resolve();
return;
} else if (state === 'connecting' || state === 'disconnecting') {
reject(new Error('Now ' + state + '. Wait for a few seconds then try again.'));
} else if (state === "connecting" || state === "disconnecting") {
reject(
new Error("Now " + state + ". Wait for a few seconds then try again.")
);
return;

@@ -122,3 +128,3 @@ }

// Set event handlers for events fired on the `Peripheral` object
this._peripheral.once('connect', () => {
this._peripheral.once("connect", () => {
this._connected = true;

@@ -128,3 +134,3 @@ this._onconnect();

this._peripheral.once('disconnect', () => {
this._peripheral.once("disconnect", () => {
this._connected = false;

@@ -143,11 +149,14 @@ this._chars = null;

}
this._getCharacteristics().then((chars) => {
this._chars = chars;
return this._subscribe();
}).then(() => {
resolve();
}).catch((error) => {
this._peripheral.disconnect();
reject(error);
});
this._getCharacteristics()
.then((chars) => {
this._chars = chars;
return this._subscribe();
})
.then(() => {
resolve();
})
.catch((error) => {
this._peripheral.disconnect();
reject(error);
});
});

@@ -161,5 +170,7 @@ });

let timer = setTimeout(() => {
this._ondisconnect_internal = () => { };
this._ondisconnect_internal = () => {};
timer = null;
reject(new Error('Failed to discover services and characteristics: TIMEOUT'));
reject(
new Error("Failed to discover services and characteristics: TIMEOUT")
);
}, 5000);

@@ -172,5 +183,9 @@

timer = null;
this._ondisconnect_internal = () => { };
this._ondisconnect_internal = () => {};
}
reject(new Error('Failed to discover services and characteristics: DISCONNECTED'));
reject(
new Error(
"Failed to discover services and characteristics: DISCONNECTED"
)
);
};

@@ -182,3 +197,3 @@

if (!timer) {
throw new Error('');
throw new Error("");
}

@@ -189,3 +204,3 @@

notify: null,
device: null
device: null,
};

@@ -210,5 +225,4 @@

} else {
reject(new Error('No characteristic was found.'));
reject(new Error("No characteristic was found."));
}
})().catch((error) => {

@@ -218,3 +232,3 @@ if (timer) {

timer = null;
this._ondisconnect_internal = () => { };
this._ondisconnect_internal = () => {};
reject(error);

@@ -246,3 +260,3 @@ } else {

} else {
reject(new Error('No service was found.'));
reject(new Error("No service was found."));
}

@@ -269,3 +283,3 @@ });

if (!char) {
reject(new Error('No notify characteristic was found.'));
reject(new Error("No notify characteristic was found."));
return;

@@ -278,7 +292,7 @@ }

}
char.on('data', (buf) => {
char.on("data", (buf) => {
this._onnotify_internal(buf);
});
resolve();
})
});
});

@@ -302,12 +316,12 @@ }

/* ------------------------------------------------------------------
* disconnect()
* - Disconnect the device
*
* [Arguments]
* - none
*
* [Return value]
* - Promise object
* Nothing will be passed to the `resolve()`.
* ---------------------------------------------------------------- */
* disconnect()
* - Disconnect the device
*
* [Arguments]
* - none
*
* [Return value]
* - Promise object
* Nothing will be passed to the `resolve()`.
* ---------------------------------------------------------------- */
disconnect() {

@@ -318,7 +332,9 @@ return new Promise((resolve, reject) => {

let state = this._peripheral.state;
if (state === 'disconnected') {
if (state === "disconnected") {
resolve();
return;
} else if (state === 'connecting' || state === 'disconnecting') {
reject(new Error('Now ' + state + '. Wait for a few seconds then try again.'));
} else if (state === "connecting" || state === "disconnecting") {
reject(
new Error("Now " + state + ". Wait for a few seconds then try again.")
);
return;

@@ -348,29 +364,37 @@ }

/* ------------------------------------------------------------------
* getDeviceName()
* - Retrieve the device name
*
* [Arguments]
* - none
*
* [Return value]
* - Promise object
* The device name will be passed to the `resolve()`.
* ---------------------------------------------------------------- */
* getDeviceName()
* - Retrieve the device name
*
* [Arguments]
* - none
*
* [Return value]
* - Promise object
* The device name will be passed to the `resolve()`.
* ---------------------------------------------------------------- */
getDeviceName() {
return new Promise((resolve, reject) => {
let name = '';
this._connect().then(() => {
if (!this._chars.device) {
// Some models of Bot don't seem to support this characteristic UUID
throw new Error('The device does not support the characteristic UUID 0x' + this._CHAR_UUID_DEVICE + '.');
}
return this._read(this._chars.device);
}).then((buf) => {
name = buf.toString('utf8');
return this._disconnect();
}).then(() => {
resolve(name);
}).catch((error) => {
reject(error);
});
let name = "";
this._connect()
.then(() => {
if (!this._chars.device) {
// Some models of Bot don't seem to support this characteristic UUID
throw new Error(
"The device does not support the characteristic UUID 0x" +
this._CHAR_UUID_DEVICE +
"."
);
}
return this._read(this._chars.device);
})
.then((buf) => {
name = buf.toString("utf8");
return this._disconnect();
})
.then(() => {
resolve(name);
})
.catch((error) => {
reject(error);
});
});

@@ -380,19 +404,22 @@ }

/* ------------------------------------------------------------------
* setDeviceName(name)
* - Set the device name
*
* [Arguments]
* - name | String | Required | Device name. The bytes length of the name
* | | | must be in the range of 1 to 20 bytes.
*
* [Return value]
* - Promise object
* Nothing will be passed to the `resolve()`.
* ---------------------------------------------------------------- */
* setDeviceName(name)
* - Set the device name
*
* [Arguments]
* - name | String | Required | Device name. The bytes length of the name
* | | | must be in the range of 1 to 20 bytes.
*
* [Return value]
* - Promise object
* Nothing will be passed to the `resolve()`.
* ---------------------------------------------------------------- */
setDeviceName(name) {
return new Promise((resolve, reject) => {
// Check the parameters
let valid = parameterChecker.check({ name: name }, {
name: { required: true, type: 'string', minBytes: 1, maxBytes: 100 }
});
let valid = parameterChecker.check(
{ name: name },
{
name: { required: true, type: "string", minBytes: 1, maxBytes: 100 },
}
);

@@ -404,16 +431,24 @@ if (!valid) {

let buf = Buffer.from(name, 'utf8');
this._connect().then(() => {
if (!this._chars.device) {
// Some models of Bot don't seem to support this characteristic UUID
throw new Error('The device does not support the characteristic UUID 0x' + this._CHAR_UUID_DEVICE + '.');
}
return this._write(this._chars.device, buf);
}).then(() => {
return this._disconnect();
}).then(() => {
resolve();
}).catch((error) => {
reject(error);
});
let buf = Buffer.from(name, "utf8");
this._connect()
.then(() => {
if (!this._chars.device) {
// Some models of Bot don't seem to support this characteristic UUID
throw new Error(
"The device does not support the characteristic UUID 0x" +
this._CHAR_UUID_DEVICE +
"."
);
}
return this._write(this._chars.device, buf);
})
.then(() => {
return this._disconnect();
})
.then(() => {
resolve();
})
.catch((error) => {
reject(error);
});
});

@@ -428,3 +463,3 @@ }

if (!Buffer.isBuffer(req_buf)) {
reject(new Error('The specified data is not acceptable for writing.'));
reject(new Error("The specified data is not acceptable for writing."));
return;

@@ -435,14 +470,19 @@ }

this._connect().then(() => {
return this._write(this._chars.write, req_buf);
}).then(() => {
return this._waitCommandResponse();
}).then((buf) => {
res_buf = buf;
return this._disconnect();
}).then(() => {
resolve(res_buf);
}).catch((error) => {
reject(error);
});
this._connect()
.then(() => {
return this._write(this._chars.write, req_buf);
})
.then(() => {
return this._waitCommandResponse();
})
.then((buf) => {
res_buf = buf;
return this._disconnect();
})
.then(() => {
resolve(res_buf);
})
.catch((error) => {
reject(error);
});
});

@@ -455,4 +495,4 @@ }

timer = null;
this._onnotify_internal = () => { };
reject(new Error('COMMAND_TIMEOUT'));
this._onnotify_internal = () => {};
reject(new Error("COMMAND_TIMEOUT"));
}, this._COMMAND_TIMEOUT_MSEC);

@@ -465,3 +505,3 @@

}
this._onnotify_internal = () => { };
this._onnotify_internal = () => {};
resolve(buf);

@@ -477,3 +517,3 @@ };

let timer = setTimeout(() => {
reject('READ_TIMEOUT');
reject("READ_TIMEOUT");
}, this._READ_TIMEOUT_MSEC);

@@ -501,3 +541,3 @@

let timer = setTimeout(() => {
reject('WRITE_TIMEOUT');
reject("WRITE_TIMEOUT");
}, this._WRITE_TIMEOUT_MSEC);

@@ -519,5 +559,4 @@

}
}
module.exports = SwitchbotDevice;
module.exports = SwitchbotDevice;

@@ -1,24 +0,25 @@

'use strict';
const parameterChecker = require('./parameter-checker.js');
const switchbotAdvertising = require('./switchbot-advertising.js');
"use strict";
const parameterChecker = require("./parameter-checker.js");
const switchbotAdvertising = require("./switchbot-advertising.js");
const SwitchbotDevice = require('./switchbot-device.js');
const SwitchbotDeviceWoHand = require('./switchbot-device-wohand.js');
const SwitchbotDeviceWoCurtain = require('./switchbot-device-wocurtain.js');
const SwitchbotDeviceWoPresence = require('./switchbot-device-wopresence.js');
const SwitchbotDeviceWoContact = require('./switchbot-device-wocontact.js');
const SwitchbotDeviceWoSensorTH = require('./switchbot-device-wosensorth.js');
const SwitchbotDeviceWoHumi = require('./switchbot-device-wohumi.js');
const SwitchbotDevice = require("./switchbot-device.js");
const SwitchbotDeviceWoHand = require("./switchbot-device-wohand.js");
const SwitchbotDeviceWoCurtain = require("./switchbot-device-wocurtain.js");
const SwitchbotDeviceWoPresence = require("./switchbot-device-wopresence.js");
const SwitchbotDeviceWoContact = require("./switchbot-device-wocontact.js");
const SwitchbotDeviceWoSensorTH = require("./switchbot-device-wosensorth.js");
const SwitchbotDeviceWoHumi = require("./switchbot-device-wohumi.js");
const SwitchbotDeviceWoPlugMini = require("./switchbot-device-woplugmini.js");
class Switchbot {
/* ------------------------------------------------------------------
* Constructor
*
* [Arguments]
* - params | Object | Optional |
* - noble | Noble | Optional | The Nobel object created by the noble module.
* | | | This parameter is optional.
* | | | If you don't specify this parameter, this
* | | | module automatically creates it.
* ---------------------------------------------------------------- */
* Constructor
*
* [Arguments]
* - params | Object | Optional |
* - noble | Noble | Optional | The Nobel object created by the noble module.
* | | | This parameter is optional.
* | | | If you don't specify this parameter, this
* | | | module automatically creates it.
* ---------------------------------------------------------------- */
constructor(params) {

@@ -30,3 +31,3 @@ // Check parameters

} else {
noble = require('@abandonware/noble');
noble = require("@abandonware/noble");
}

@@ -42,52 +43,60 @@

this._scanning = false;
this._DEFAULT_DISCOVERY_DURATION = 5000
this._DEFAULT_DISCOVERY_DURATION = 5000;
this._PRIMARY_SERVICE_UUID_LIST = [];
};
}
/* ------------------------------------------------------------------
* discover([params])
* - Discover switchbot devices
*
* [Arguments]
* - params | Object | Optional |
* - duration | Integer | Optional | Duration for discovery process (msec).
* | | | The value must be in the range of 1 to 60000.
* | | | The default value is 5000 (msec).
* - model | String | Optional | "H", "T", "e", "s", "d", "c", "u", "g", "o", "i", or "r".
* | | | If "H" is specified, this method will discover only Bots.
* | | | If "T" is specified, this method will discover only Meters.
* | | | If "e" is specified, this method will discover only Humidifiers.
* | | | If "s" is specified, this method will discover only Motion Sensors.
* | | | If "d" is specified, this method will discover only Contact Sensors.
* | | | If "c" is specified, this method will discover only Curtains.
* | | | If "u" is specified, this method will discover only Color Bulbs.
* | | | If "g" is specified, this method will discover only Plugs.
* | | | If "o" is specified, this method will discover only Locks.
* | | | If "i" is specified, this method will discover only Meter Pluses.
* | | | If "r" is specified, this method will discover only Locks.
* - id | String | Optional | If this value is set, this method will discover
* | | | only a device whose ID is as same as this value.
* | | | The ID is identical to the MAC address.
* | | | This parameter is case-insensitive, and
* | | | colons are ignored.
* - quick | Boolean | Optional | If this value is true, this method finishes
* | | | the discovery process when the first device
* | | | is found, then calls the resolve() function
* | | | without waiting the specified duration.
* | | | The default value is false.
*
* [Return value]
* - Promise object
* An array will be passed to the `resolve()`, which includes
* `SwitchbotDevice` objects representing the found devices.
* ---------------------------------------------------------------- */
* discover([params])
* - Discover switchbot devices
*
* [Arguments]
* - params | Object | Optional |
* - duration | Integer | Optional | Duration for discovery process (msec).
* | | | The value must be in the range of 1 to 60000.
* | | | The default value is 5000 (msec).
* - model | String | Optional | "H", "T", "e", "s", "d", "c", "u", "g", "o", "i", or "r".
* | | | If "H" is specified, this method will discover only Bots.
* | | | If "T" is specified, this method will discover only Meters.
* | | | If "e" is specified, this method will discover only Humidifiers.
* | | | If "s" is specified, this method will discover only Motion Sensors.
* | | | If "d" is specified, this method will discover only Contact Sensors.
* | | | If "c" is specified, this method will discover only Curtains.
* | | | If "u" is specified, this method will discover only Color Bulbs.
* | | | If "g" is specified, this method will discover only Plugs.
* | | | If "o" is specified, this method will discover only Locks.
* | | | If "i" is specified, this method will discover only Meter Pluses.
* | | | If "r" is specified, this method will discover only Locks.
* - id | String | Optional | If this value is set, this method will discover
* | | | only a device whose ID is as same as this value.
* | | | The ID is identical to the MAC address.
* | | | This parameter is case-insensitive, and
* | | | colons are ignored.
* - quick | Boolean | Optional | If this value is true, this method finishes
* | | | the discovery process when the first device
* | | | is found, then calls the resolve() function
* | | | without waiting the specified duration.
* | | | The default value is false.
*
* [Return value]
* - Promise object
* An array will be passed to the `resolve()`, which includes
* `SwitchbotDevice` objects representing the found devices.
* ---------------------------------------------------------------- */
discover(params = {}) {
let promise = new Promise((resolve, reject) => {
// Check the parameters
let valid = parameterChecker.check(params, {
duration: { required: false, type: 'integer', min: 1, max: 60000 },
model: { required: false, type: 'string', enum: ['H', 'T', 'e', 's', 'd', 'c', 'u', 'g', 'o', 'i', 'r'] },
id: { required: false, type: 'string', min: 12, max: 17 },
quick: { required: false, type: 'boolean' }
}, false);
let valid = parameterChecker.check(
params,
{
duration: { required: false, type: "integer", min: 1, max: 60000 },
model: {
required: false,
type: "string",
enum: ["H", "T", "e", "s", "d", "c", "u", "g", "j", "o", "i", "r"],
},
id: { required: false, type: "string", min: 12, max: 17 },
quick: { required: false, type: "boolean" },
},
false
);

@@ -106,56 +115,62 @@ if (!valid) {

duration: params.duration || this._DEFAULT_DISCOVERY_DURATION,
model: params.model || '',
id: params.id || '',
quick: params.quick ? true : false
model: params.model || "",
id: params.id || "",
quick: params.quick ? true : false,
};
// Initialize the noble object
this._init().then(() => {
let peripherals = {};
let timer = null;
let finishDiscovery = () => {
if (timer) {
clearTimeout(timer);
}
this.noble.removeAllListeners('discover');
this.noble.stopScanning();
let device_list = [];
for (let addr in peripherals) {
device_list.push(peripherals[addr]);
}
resolve(device_list);
};
this._init()
.then(() => {
let peripherals = {};
let timer = null;
let finishDiscovery = () => {
if (timer) {
clearTimeout(timer);
}
this.noble.removeAllListeners("discover");
this.noble.stopScanning();
let device_list = [];
for (let addr in peripherals) {
device_list.push(peripherals[addr]);
}
resolve(device_list);
};
// Set a handler for the 'discover' event
this.noble.on('discover', (peripheral) => {
let device = this._getDeviceObject(peripheral, p.id, p.model);
if (!device) {
return;
}
let id = device.id;
peripherals[id] = device;
// Set a handler for the 'discover' event
this.noble.on("discover", (peripheral) => {
let device = this._getDeviceObject(peripheral, p.id, p.model);
if (!device) {
return;
}
let id = device.id;
peripherals[id] = device;
if (this.ondiscover && typeof (this.ondiscover) === 'function') {
this.ondiscover(device);
}
if (this.ondiscover && typeof this.ondiscover === "function") {
this.ondiscover(device);
}
if (p.quick) {
finishDiscovery();
return;
}
});
if (p.quick) {
finishDiscovery();
return;
}
});
// Start scanning
this.noble.startScanning(this._PRIMARY_SERVICE_UUID_LIST, false, (error) => {
if (error) {
reject(error);
return;
}
timer = setTimeout(() => {
finishDiscovery();
}, p.duration);
// Start scanning
this.noble.startScanning(
this._PRIMARY_SERVICE_UUID_LIST,
false,
(error) => {
if (error) {
reject(error);
return;
}
timer = setTimeout(() => {
finishDiscovery();
}, p.duration);
}
);
})
.catch((error) => {
reject(error);
});
}).catch((error) => {
reject(error);
});
});

@@ -168,15 +183,19 @@ return promise;

switch (this.noble.state) {
case 'poweredOn':
case "poweredOn":
resolve();
return;
case 'unsupported', 'unauthorized', 'poweredOff':
let err = new Error('Failed to initialize the Noble object: ' + this.noble.state);
case ("unsupported", "unauthorized", "poweredOff"):
let err = new Error(
"Failed to initialize the Noble object: " + this.noble.state
);
reject(err);
return;
default: // 'resetting', 'unknown'
this.noble.once('stateChange', (state) => {
if (state === 'poweredOn') {
this.noble.once("stateChange", (state) => {
if (state === "poweredOn") {
resolve();
} else {
let err = new Error('Failed to initialize the Noble object: ' + state);
let err = new Error(
"Failed to initialize the Noble object: " + state
);
reject(err);

@@ -195,33 +214,34 @@ }

switch (ad.serviceData.model) {
case 'H':
case "H":
device = new SwitchbotDeviceWoHand(peripheral, this.noble);
break;
case 'T':
case "T":
device = new SwitchbotDeviceWoSensorTH(peripheral, this.noble);
break;
case 'e':
case "e":
device = new SwitchbotDeviceWoHumi(peripheral, this.noble);
break;
case 's':
case "s":
device = new SwitchbotDeviceWoPresence(peripheral, this.noble);
break;
case 'd':
case "d":
device = new SwitchbotDeviceWoContact(peripheral, this.noble);
break;
case 'c':
case "c":
device = new SwitchbotDeviceWoCurtain(peripheral, this.noble);
break;
case 'u':
case "u":
device = new SwitchbotDeviceWoColorBulb(peripheral, this.noble);
break;
case 'g':
case "g":
case "j":
device = new SwitchbotDeviceWoPlugMini(peripheral, this.noble);
break;
case 'o':
case "o":
device = new SwitchbotDeviceWoSmartLock(peripheral, this.noble);
break;
case 'i':
case "i":
device = new SwitchbotDeviceWoSensorTHPlus(peripheral, this.noble);
break;
case 'r':
case "r":
device = new SwitchbotDeviceWoLEDStripLight(peripheral, this.noble);

@@ -243,4 +263,4 @@ break;

if (id) {
id = id.toLowerCase().replace(/\:/g, '');
let ad_id = ad.address.toLowerCase().replace(/[^a-z0-9]/g, '');
id = id.toLowerCase().replace(/\:/g, "");
let ad_id = ad.address.toLowerCase().replace(/[^a-z0-9]/g, "");
if (ad_id !== id) {

@@ -259,60 +279,68 @@ return false;

/* ------------------------------------------------------------------
* startScan([params])
* - Start to monitor advertising packets coming from switchbot devices
*
* [Arguments]
* - params | Object | Optional |
* - model | String | Optional | "H", "T", "e", "s", "d", "c", "u", "g", "o", "i", or "r".
* | | | If "H" is specified, the `onadvertisement`
* | | | event handler will be called only when advertising
* | | | packets comes from Bots.
* | | | If "T" is specified, the `onadvertisement`
* | | | event handler will be called only when advertising
* | | | packets comes from Meters.
* | | | If "e" is specified, the `onadvertisement`
* | | | event handler will be called only when advertising
* | | | packets comes from Humidifiers.
* | | | If "s" is specified, the `onadvertisement`
* | | | event handler will be called only when advertising
* | | | packets comes from Motion Sensor.
* | | | If "d" is specified, the `onadvertisement`
* | | | event handler will be called only when advertising
* | | | packets comes from Contact Sensor.
* | | | If "c" is specified, the `onadvertisement`
* | | | event handler will be called only when advertising
* | | | packets comes from Curtains.
* | | | If "u" is specified, the `onadvertisement`
* | | | event handler will be called only when advertising
* | | | packets comes from Color Bulb.
* | | | If "g" is specified, the `onadvertisement`
* | | | event handler will be called only when advertising
* | | | packets comes from Plug Mini.
* | | | If "o" is specified, the `onadvertisement`
* | | | event handler will be called only when advertising
* | | | packets comes from Smart Lock.
* | | | If "i" is specified, the `onadvertisement`
* | | | event handler will be called only when advertising
* | | | packets comes from Meter Plus.
* | | | If "r" is specified, the `onadvertisement`
* | | | event handler will be called only when advertising
* | | | packets comes from LED Strip Light.
* - id | String | Optional | If this value is set, the `onadvertisement`
* | | | event handler will be called only when advertising
* | | | packets comes from devices whose ID is as same as
* | | | this value.
* | | | The ID is identical to the MAC address.
* | | | This parameter is case-insensitive, and
* | | | colons are ignored.
*
* [Return value]
* - Promise object
* Nothing will be passed to the `resolve()`.
* ---------------------------------------------------------------- */
* startScan([params])
* - Start to monitor advertising packets coming from switchbot devices
*
* [Arguments]
* - params | Object | Optional |
* - model | String | Optional | "H", "T", "e", "s", "d", "c", "u", "g", "o", "i", or "r".
* | | | If "H" is specified, the `onadvertisement`
* | | | event handler will be called only when advertising
* | | | packets comes from Bots.
* | | | If "T" is specified, the `onadvertisement`
* | | | event handler will be called only when advertising
* | | | packets comes from Meters.
* | | | If "e" is specified, the `onadvertisement`
* | | | event handler will be called only when advertising
* | | | packets comes from Humidifiers.
* | | | If "s" is specified, the `onadvertisement`
* | | | event handler will be called only when advertising
* | | | packets comes from Motion Sensor.
* | | | If "d" is specified, the `onadvertisement`
* | | | event handler will be called only when advertising
* | | | packets comes from Contact Sensor.
* | | | If "c" is specified, the `onadvertisement`
* | | | event handler will be called only when advertising
* | | | packets comes from Curtains.
* | | | If "u" is specified, the `onadvertisement`
* | | | event handler will be called only when advertising
* | | | packets comes from Color Bulb.
* | | | If "g" is specified, the `onadvertisement`
* | | | event handler will be called only when advertising
* | | | packets comes from Plug Mini.
* | | | If "o" is specified, the `onadvertisement`
* | | | event handler will be called only when advertising
* | | | packets comes from Smart Lock.
* | | | If "i" is specified, the `onadvertisement`
* | | | event handler will be called only when advertising
* | | | packets comes from Meter Plus.
* | | | If "r" is specified, the `onadvertisement`
* | | | event handler will be called only when advertising
* | | | packets comes from LED Strip Light.
* - id | String | Optional | If this value is set, the `onadvertisement`
* | | | event handler will be called only when advertising
* | | | packets comes from devices whose ID is as same as
* | | | this value.
* | | | The ID is identical to the MAC address.
* | | | This parameter is case-insensitive, and
* | | | colons are ignored.
*
* [Return value]
* - Promise object
* Nothing will be passed to the `resolve()`.
* ---------------------------------------------------------------- */
startScan(params) {
let promise = new Promise((resolve, reject) => {
// Check the parameters
let valid = parameterChecker.check(params, {
model: { required: false, type: 'string', enum: ['H', 'T', 'e', 's', 'd', 'c', 'u', 'g', 'o', 'i', 'r'] },
id: { required: false, type: 'string', min: 12, max: 17 },
}, false);
let valid = parameterChecker.check(
params,
{
model: {
required: false,
type: "string",
enum: ["H", "T", "e", "s", "d", "c", "u", "g", "j", "o", "i", "r"],
},
id: { required: false, type: "string", min: 12, max: 17 },
},
false
);

@@ -329,31 +357,39 @@ if (!valid) {

// Initialize the noble object
this._init().then(() => {
this._init()
.then(() => {
// Determine the values of the parameters
let p = {
model: params.model || "",
id: params.id || "",
};
// Determine the values of the parameters
let p = {
model: params.model || '',
id: params.id || ''
};
// Set a handler for the 'discover' event
this.noble.on("discover", (peripheral) => {
let ad = switchbotAdvertising.parse(peripheral, this.onlog);
if (this._filterAdvertising(ad, p.id, p.model)) {
if (
this.onadvertisement &&
typeof this.onadvertisement === "function"
) {
this.onadvertisement(ad);
}
}
});
// Set a handler for the 'discover' event
this.noble.on('discover', (peripheral) => {
let ad = switchbotAdvertising.parse(peripheral, this.onlog);
if (this._filterAdvertising(ad, p.id, p.model)) {
if (this.onadvertisement && typeof (this.onadvertisement) === 'function') {
this.onadvertisement(ad);
// Start scanning
this.noble.startScanning(
this._PRIMARY_SERVICE_UUID_LIST,
true,
(error) => {
if (error) {
reject(error);
} else {
resolve();
}
}
}
);
})
.catch((error) => {
reject(error);
});
// Start scanning
this.noble.startScanning(this._PRIMARY_SERVICE_UUID_LIST, true, (error) => {
if (error) {
reject(error);
} else {
resolve();
}
});
}).catch((error) => {
reject(error);
});
});

@@ -364,13 +400,13 @@ return promise;

/* ------------------------------------------------------------------
* stopScan()
* - Stop to monitor advertising packets coming from switchbot devices
*
* [Arguments]
* - none
*
* [Return value]
* - none
* ---------------------------------------------------------------- */
* stopScan()
* - Stop to monitor advertising packets coming from switchbot devices
*
* [Arguments]
* - none
*
* [Return value]
* - none
* ---------------------------------------------------------------- */
stopScan() {
this.noble.removeAllListeners('discover');
this.noble.removeAllListeners("discover");
this.noble.stopScanning();

@@ -380,18 +416,21 @@ }

/* ------------------------------------------------------------------
* wait(msec) {
* - Wait for the specified time (msec)
*
* [Arguments]
* - msec | Integer | Required | Msec.
*
* [Return value]
* - Promise object
* Nothing will be passed to the `resolve()`.
* ---------------------------------------------------------------- */
* wait(msec) {
* - Wait for the specified time (msec)
*
* [Arguments]
* - msec | Integer | Required | Msec.
*
* [Return value]
* - Promise object
* Nothing will be passed to the `resolve()`.
* ---------------------------------------------------------------- */
wait(msec) {
return new Promise((resolve, reject) => {
// Check the parameters
let valid = parameterChecker.check({ msec: msec }, {
msec: { required: true, type: 'integer', min: 0 }
});
let valid = parameterChecker.check(
{ msec: msec },
{
msec: { required: true, type: "integer", min: 0 },
}
);

@@ -406,5 +445,4 @@ if (!valid) {

}
}
module.exports = Switchbot;
{
"name": "node-switchbot",
"version": "1.3.0",
"version": "1.4.0",
"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).",

@@ -40,4 +40,4 @@ "main": "./lib/switchbot.js",

"devDependencies": {
"npm-check-updates": "^14.1.1"
"npm-check-updates": "^16.0.5"
}
}
}

@@ -19,3 +19,4 @@ <span align="center">

---------------------------------------
---
## Table of Contents

@@ -73,6 +74,5 @@

* [Node.js](https://nodejs.org/en/) 10 +
* [@abandonware/noble](https://github.com/abandonware/noble)
- [Node.js](https://nodejs.org/en/) 10 +
- [@abandonware/noble](https://github.com/abandonware/noble)
See the document of the [@abandonware/noble](https://github.com/abandonware/noble) for details on installing the [@abandonware/noble](https://github.com/abandonware/noble).

@@ -100,3 +100,4 @@

---------------------------------------
---
## Quick Start

@@ -137,3 +138,3 @@

// Load the node-switchbot and get a `Switchbot` constructor object
const Switchbot = require('node-switchbot');
const Switchbot = require("node-switchbot");
// Create an `Switchbot` object

@@ -143,14 +144,17 @@ let switchbot = new Switchbot();

// Start to monitor advertisement packets
switchbot.startScan().then(() => {
// Set an event hander
switchbot.onadvertisement = (ad) => {
console.log(JSON.stringify(ad, null, ' '));
};
// Wait 10 seconds
return switchbot.wait(10000);
}).then(() => {
// Stop to monitor
switchbot.stopScan();
process.exit();
});
switchbot
.startScan()
.then(() => {
// Set an event hander
switchbot.onadvertisement = (ad) => {
console.log(JSON.stringify(ad, null, " "));
};
// Wait 10 seconds
return switchbot.wait(10000);
})
.then(() => {
// Stop to monitor
switchbot.stopScan();
process.exit();
});
```

@@ -212,3 +216,3 @@

// Load the node-switchbot and get a `Switchbot` constructor object
const Switchbot = require('node-switchbot');
const Switchbot = require("node-switchbot");
// Create an `Switchbot` object

@@ -219,5 +223,5 @@ const switchbot = new Switchbot();

// Find a Bot (WoHand)
const bot_list = await switchbot.discover({ model: 'H', quick: true });
const bot_list = await switchbot.discover({ model: "H", quick: true });
if (bot_list.length === 0) {
throw new Error('No device was found.');
throw new Error("No device was found.");
}

@@ -240,3 +244,4 @@ // The `SwitchbotDeviceWoHand` object representing the found Bot.

---------------------------------------
---
## `Switchbot` object

@@ -258,5 +263,5 @@

Property | Type | Required | Description
:--------|:-------|:---------|:-----------
`noble` | Noble | option | a Noble object of the [`@abandonware/noble`](https://github.com/abandonware/noble) module
| Property | Type | Required | Description |
| :------- | :---- | :------- | :---------------------------------------------------------------------------------------- |
| `noble` | Noble | option | a Noble object of the [`@abandonware/noble`](https://github.com/abandonware/noble) module |

@@ -282,8 +287,8 @@ The node-switchbot module uses the [`@abandonware/noble`](https://github.com/abandonware/noble) module in order to interact with BLE devices. If you want to interact other BLE devices using the `@abandonware/noble` module, you can create an `Noble` object by yourself, then pass it to this module. If you don't specify a `Noble` object to the `noble` property, this module automatically create a `Noble` object internally.

Property | Type | Required | Description
:------------|:--------|:---------|:------------
`duration` | Integer | Optional | Duration for discovery process (msec). The default value is 5000 (msec).
`model` | String | Optional | `"H"`, `"T"` or `"c"`. If `"H"` is specified, this method will discover only Bots. If `"T"` is specified, this method will discover only Meters. If `"c"` is specified, this method will discover only Curtains.
`id` | String | Optional | If this value is set, this method will discover only a device whose ID is as same as this value. The ID is identical to the MAC address. This parameter is case-insensitive, and colons are ignored.
`quick` | Boolean | Optional | If this value is `true`, this method finishes the discovery process when the first device is found, then calls the `resolve()` function without waiting the specified `duration`. The default value is `false`.
| Property | Type | Required | Description |
| :--------- | :------ | :------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `duration` | Integer | Optional | Duration for discovery process (msec). The default value is 5000 (msec). |
| `model` | String | Optional | `"H"`, `"T"` or `"c"`. If `"H"` is specified, this method will discover only Bots. If `"T"` is specified, this method will discover only Meters. If `"c"` is specified, this method will discover only Curtains. |
| `id` | String | Optional | If this value is set, this method will discover only a device whose ID is as same as this value. The ID is identical to the MAC address. This parameter is case-insensitive, and colons are ignored. |
| `quick` | Boolean | Optional | If this value is `true`, this method finishes the discovery process when the first device is found, then calls the `resolve()` function without waiting the specified `duration`. The default value is `false`. |

@@ -300,3 +305,3 @@ In the code snippet below, no parameter is passed to the method:

If no parameter is passed to the method as the code above, an `Array` object will be passed to the `resolve()` function in 5 seconds. The `Array` object contains [`SwitchbotDevice`](#SwitchbotDevice-object) objects representing the found devices. See the section "[`SwitchbotDevice`](#SwitchbotDevice-object) objects" for more details.
If no parameter is passed to the method as the code above, an `Array` object will be passed to the `resolve()` function in 5 seconds. The `Array` object contains [`SwitchbotDevice`](#SwitchbotDevice-object) objects representing the found devices. See the section "[`SwitchbotDevice`](#SwitchbotDevice-object) objects" for more details.

@@ -347,6 +352,6 @@ If you want a quick response, you can set the `quick` property to `true`.

Property | Type | Required | Description
:------------|:-------|:---------|:------------
`model` | String | Optional | `"H"`, `"T"` or `"c"`. If `"H"` is specified, this method will discover only Bots. If `"T"` is specified, this method will discover only Meters. If `"c"` is specified, this method will discover only Curtains.
`id` | String | Optional | If this value is set, this method will discover only a device whose ID is as same as this value. The ID is identical to the MAC address. This value is case-insensitive, and colons are ignored.
| Property | Type | Required | Description |
| :------- | :----- | :------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `model` | String | Optional | `"H"`, `"T"` or `"c"`. If `"H"` is specified, this method will discover only Bots. If `"T"` is specified, this method will discover only Meters. If `"c"` is specified, this method will discover only Curtains. |
| `id` | String | Optional | If this value is set, this method will discover only a device whose ID is as same as this value. The ID is identical to the MAC address. This value is case-insensitive, and colons are ignored. |

@@ -399,3 +404,3 @@ Whenever a packet is received, the callback function set to the [`onadvertisement`](#Switchbot-onadvertisement-event-handler) property of the [`Switchbot`](#Switchbot-object) object will be called. When a packet is received, a hash object representing the packet will be passed to the callback function.

The `stopScan()` method stops to scan advertising packets coming from devices. This method returns nothing. Note that this method is *not* asynchronous but synchronous unlike the other methods. See the section "[`startScan()` method](#startscan-method)" for details.
The `stopScan()` method stops to scan advertising packets coming from devices. This method returns nothing. Note that this method is _not_ asynchronous but synchronous unlike the other methods. See the section "[`startScan()` method](#startscan-method)" for details.

@@ -414,3 +419,4 @@ ### `onadvertisement` event handler

---------------------------------------
---
## `SwitchbotDevice` object

@@ -428,11 +434,11 @@

Property | Type | Description
:----------------|:---------|:-----------
`id` | String | ID of the device. (e.g., `"cb4eb903c96d"`)
`address` | String | MAC address of the device. Basically it is as same as the value of the `id` except that this value includes `:` in the string. (e.g., `"cb:4e:b9:03:c9:6d"`)
`model` | String | This value is `"H"` "Bot (WoHand)", `"T"` "Meter (WoSensorTH)", `"c"` "Curtain (WoCurtain)", `"d"` "Contact (WoContact)" or `"s"` "Motion (WoMotion)".
`modelName` | String | This value is `"WoHand"`, `"WoSensorTH"`, `WoCurtain`, `WoContect` or `WoMotion`.
`connectionState` | String | This value indicates the BLE connection state. `"connecting"`, `"connected"`, `"disconnecting"`, or `"disconnected"`.
`onconnect` | Function | See the section "[`onconnect` event handler](#SwitchbotDevice-onconnect-event-handler)" for details.
`ondisconnect` | Function | See the section "[`ondisconnect` event handler](#SwitchbotDevice-ondisconnect-event-handler)" for details.
| Property | Type | Description |
| :---------------- | :------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id` | String | ID of the device. (e.g., `"cb4eb903c96d"`) |
| `address` | String | MAC address of the device. Basically it is as same as the value of the `id` except that this value includes `:` in the string. (e.g., `"cb:4e:b9:03:c9:6d"`) |
| `model` | String | This value is `"H"` "Bot (WoHand)", `"T"` "Meter (WoSensorTH)", `"c"` "Curtain (WoCurtain)", `"d"` "Contact (WoContact)" or `"s"` "Motion (WoMotion)". |
| `modelName` | String | This value is `"WoHand"`, `"WoSensorTH"`, `WoCurtain`, `WoContect` or `WoMotion`. |
| `connectionState` | String | This value indicates the BLE connection state. `"connecting"`, `"connected"`, `"disconnecting"`, or `"disconnected"`. |
| `onconnect` | Function | See the section "[`onconnect` event handler](#SwitchbotDevice-onconnect-event-handler)" for details. |
| `ondisconnect` | Function | See the section "[`ondisconnect` event handler](#SwitchbotDevice-ondisconnect-event-handler)" for details. |

@@ -448,11 +454,15 @@ ### `getDeviceName()` method

```javascript
switchbot.discover({ model: 'H', quick: true }).then((device_list) => {
return device_list[0].getDeviceName();
}).then((name) => {
console.log(name);
process.exit();
}).catch((error) => {
console.error(error);
process.exit();
});
switchbot
.discover({ model: "H", quick: true })
.then((device_list) => {
return device_list[0].getDeviceName();
})
.then((name) => {
console.log(name);
process.exit();
})
.catch((error) => {
console.error(error);
process.exit();
});
```

@@ -463,3 +473,3 @@

```javascript
WoHand
WoHand;
```

@@ -476,11 +486,15 @@

```javascript
switchbot.discover({ model: 'H', quick: true }).then((device_list) => {
return device_list[0].setDeviceName('Bot in kitchen');
}).then(() => {
console.log('Done.');
process.exit();
}).catch((error) => {
console.error(error);
process.exit();
});
switchbot
.discover({ model: "H", quick: true })
.then((device_list) => {
return device_list[0].setDeviceName("Bot in kitchen");
})
.then(() => {
console.log("Done.");
process.exit();
})
.catch((error) => {
console.error(error);
process.exit();
});
```

@@ -501,30 +515,38 @@

switchbot.discover({ model: 'H', quick: true }).then((device_list) => {
device = device_list[0];
if (!device) {
console.log('No device was found.');
switchbot
.discover({ model: "H", quick: true })
.then((device_list) => {
device = device_list[0];
if (!device) {
console.log("No device was found.");
process.exit();
}
console.log(device.modelName + " (" + device.address + ") was found.");
console.log("Connecting...");
return device.connect();
})
.then(() => {
console.log("Putting the arm down...");
return device.down();
})
.then(() => {
console.log("Waiting for 5 seconds...");
return switchbot.wait(5000);
})
.then(() => {
console.log("Putting the arm up...");
return device.up();
})
.then(() => {
console.log("Disconnecting...");
return device.disconnect();
})
.then(() => {
console.log("Done.");
process.exit();
}
console.log(device.modelName + ' (' + device.address + ') was found.');
console.log('Connecting...');
return device.connect();
}).then(() => {
console.log('Putting the arm down...');
return device.down();
}).then(() => {
console.log('Waiting for 5 seconds...');
return switchbot.wait(5000);
}).then(() => {
console.log('Putting the arm up...');
return device.up();
}).then(() => {
console.log('Disconnecting...');
return device.disconnect();
}).then(() => {
console.log('Done.');
process.exit();
}).catch((error) => {
console.error(error);
process.exit();
});
})
.catch((error) => {
console.error(error);
process.exit();
});
```

@@ -557,27 +579,31 @@

```javascript
switchbot.discover({ model: 'H', quick: true }).then((device_list) => {
let device = device_list[0];
if (!device) {
console.log('No device was found.');
process.exit();
}
console.log(device.modelName + ' (' + device.address + ') was found.');
switchbot
.discover({ model: "H", quick: true })
.then((device_list) => {
let device = device_list[0];
if (!device) {
console.log("No device was found.");
process.exit();
}
console.log(device.modelName + " (" + device.address + ") was found.");
// Set event handers
device.onconnect = () => {
console.log('Connected.');
};
device.ondisconnect = () => {
console.log('Disconnected.');
};
// Set event handers
device.onconnect = () => {
console.log("Connected.");
};
device.ondisconnect = () => {
console.log("Disconnected.");
};
console.log('Pressing the switch...');
return device.press();
}).then(() => {
console.log('Done.');
process.exit();
}).catch((error) => {
console.error(error);
process.exit();
});
console.log("Pressing the switch...");
return device.press();
})
.then(() => {
console.log("Done.");
process.exit();
})
.catch((error) => {
console.error(error);
process.exit();
});
```

@@ -601,3 +627,4 @@

---------------------------------------
---
## `SwitchbotDeviceWoHand` object

@@ -616,9 +643,13 @@

```javascript
switchbot.discover({ model: 'H', quick: true }).then((device_list) => {
return device_list[0].press();
}).then(() => {
console.log('Done.');
}).catch((error) => {
console.error(error);
});
switchbot
.discover({ model: "H", quick: true })
.then((device_list) => {
return device_list[0].press();
})
.then(() => {
console.log("Done.");
})
.catch((error) => {
console.error(error);
});
```

@@ -636,16 +667,20 @@

Mode | Inverse the on/off direction | Physical position of the arm
:-------------------|:-----------------------------|:----------------------------
Press mode | N/A | Down (stretched), then Up (retracted)
Switch mode | Disabled | Down (stretched)
&nbsp; | Enabled | Up (retracted)
| Mode | Inverse the on/off direction | Physical position of the arm |
| :---------- | :--------------------------- | :------------------------------------ |
| Press mode | N/A | Down (stretched), then Up (retracted) |
| Switch mode | Disabled | Down (stretched) |
| &nbsp; | Enabled | Up (retracted) |
```javascript
switchbot.discover({ model: 'H', quick: true }).then((device_list) => {
return device_list[0].turnOn();
}).then(() => {
console.log('Done.');
}).catch((error) => {
console.error(error);
});
switchbot
.discover({ model: "H", quick: true })
.then((device_list) => {
return device_list[0].turnOn();
})
.then(() => {
console.log("Done.");
})
.catch((error) => {
console.error(error);
});
```

@@ -661,16 +696,20 @@

Mode | Inverse the on/off direction | Physical position of the arm
:-------------------|:-----------------------------|:----------------------------
Press mode | N/A | Down (stretched), then Up (retracted)
Switch mode | Disabled | Up (retracted)
&nbsp; | Enabled | Down (stretched)
| Mode | Inverse the on/off direction | Physical position of the arm |
| :---------- | :--------------------------- | :------------------------------------ |
| Press mode | N/A | Down (stretched), then Up (retracted) |
| Switch mode | Disabled | Up (retracted) |
| &nbsp; | Enabled | Down (stretched) |
```javascript
switchbot.discover({ model: 'H', quick: true }).then((device_list) => {
return device_list[0].turnOff();
}).then(() => {
console.log('Done.');
}).catch((error) => {
console.error(error);
});
switchbot
.discover({ model: "H", quick: true })
.then((device_list) => {
return device_list[0].turnOff();
})
.then(() => {
console.log("Done.");
})
.catch((error) => {
console.error(error);
});
```

@@ -687,9 +726,13 @@

```javascript
switchbot.discover({ model: 'H', quick: true }).then((device_list) => {
return device_list[0].down();
}).then(() => {
console.log('Done.');
}).catch((error) => {
console.error(error);
});
switchbot
.discover({ model: "H", quick: true })
.then((device_list) => {
return device_list[0].down();
})
.then(() => {
console.log("Done.");
})
.catch((error) => {
console.error(error);
});
```

@@ -706,12 +749,17 @@

```javascript
switchbot.discover({ model: 'H', quick: true }).then((device_list) => {
return device_list[0].up();
}).then(() => {
console.log('Done.');
}).catch((error) => {
console.error(error);
});
switchbot
.discover({ model: "H", quick: true })
.then((device_list) => {
return device_list[0].up();
})
.then(() => {
console.log("Done.");
})
.catch((error) => {
console.error(error);
});
```
---------------------------------------
---
## `SwitchbotDeviceWoCurtain` object

@@ -726,9 +774,13 @@

```javascript
switchbot.discover({ model: 'c', quick: true }).then((device_list) => {
return device_list[0].open();
}).then(() => {
console.log('Done.');
}).catch((error) => {
console.error(error);
});
switchbot
.discover({ model: "c", quick: true })
.then((device_list) => {
return device_list[0].open();
})
.then(() => {
console.log("Done.");
})
.catch((error) => {
console.error(error);
});
```

@@ -745,9 +797,13 @@

```javascript
switchbot.discover({ model: 'c', quick: true }).then((device_list) => {
return device_list[0].close();
}).then(() => {
console.log('Done.');
}).catch((error) => {
console.error(error);
});
switchbot
.discover({ model: "c", quick: true })
.then((device_list) => {
return device_list[0].close();
})
.then(() => {
console.log("Done.");
})
.catch((error) => {
console.error(error);
});
```

@@ -764,9 +820,13 @@

```javascript
switchbot.discover({ model: 'c', quick: true }).then((device_list) => {
return device_list[0].pause();
}).then(() => {
console.log('Done.');
}).catch((error) => {
console.error(error);
});
switchbot
.discover({ model: "c", quick: true })
.then((device_list) => {
return device_list[0].pause();
})
.then(() => {
console.log("Done.");
})
.catch((error) => {
console.error(error);
});
```

@@ -782,3 +842,2 @@

The `open()` method sends an open command to the Curtain. This method returns a `Promise` object. Nothing will be passed to the `resove()`.

@@ -790,18 +849,23 @@

Property | Type | Required | Description
:------------|:--------|:---------|:------------
`percent` | Integer | Required | The percentage of target position (`0-100`). (e.g., `50`)
`mode` | Integer | Optional | The running mode of Curtain. <br/>`0x00` - Performance mode.<br/> `0x01` - Silent mode. <br/>`0xff` - Default. Unspecified, from Curtain's settings.
| Property | Type | Required | Description |
| :-------- | :------ | :------- | :--------------------------------------------------------------------------------------------------------------------------------------------------- |
| `percent` | Integer | Required | The percentage of target position (`0-100`). (e.g., `50`) |
| `mode` | Integer | Optional | The running mode of Curtain. <br/>`0x00` - Performance mode.<br/> `0x01` - Silent mode. <br/>`0xff` - Default. Unspecified, from Curtain's settings. |
```javascript
switchbot.discover({ model: 'c', quick: true }).then((device_list) => {
return device_list[0].runToPos(50);
}).then(() => {
console.log('Done.');
}).catch((error) => {
console.error(error);
});
switchbot
.discover({ model: "c", quick: true })
.then((device_list) => {
return device_list[0].runToPos(50);
})
.then(() => {
console.log("Done.");
})
.catch((error) => {
console.error(error);
});
```
---------------------------------------
---
## Advertisement data

@@ -811,8 +875,8 @@

Property | Type | Description
:-------------|:--------|:-----------
`id` | String | ID of the device. (e.g., `"cb4eb903c96d"`)
`address` | String | MAC address of the device. Basically it is as same as the value of the `id` except that this value includes `:` in the string. (e.g., `"cb:4e:b9:03:c9:6d"`)
`rssi` | Integer | RSSI. (e.g., `-62`)
`serviceData` | Object | An object including the device-specific data.
| Property | Type | Description |
| :------------ | :------ | :----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id` | String | ID of the device. (e.g., `"cb4eb903c96d"`) |
| `address` | String | MAC address of the device. Basically it is as same as the value of the `id` except that this value includes `:` in the string. (e.g., `"cb:4e:b9:03:c9:6d"`) |
| `rssi` | Integer | RSSI. (e.g., `-62`) |
| `serviceData` | Object | An object including the device-specific data. |

@@ -842,24 +906,23 @@ The structures of the `serviceData` are described in the following sections.

Property | Type | Description
:-----------|:--------|:-----------
`model` | String | This value is always `"H"`, which means "Bot (WoHand)".
`modelName` | String | This value is always `"WoHand"`, which means "Bot".
`mode` | Boolean | This indicates the mode setting. When the mode is "Switch mode", this value is `true`. When the mode is "Press mode", this value is `false`.
`state` | Boolean | This value indicates whether the switch status is ON or OFF.
`battery` | Integer | (**experimental**) This value indicates the battery level (`%`).
| Property | Type | Description |
| :---------- | :------ | :------------------------------------------------------------------------------------------------------------------------------------------- |
| `model` | String | This value is always `"H"`, which means "Bot (WoHand)". |
| `modelName` | String | This value is always `"WoHand"`, which means "Bot". |
| `mode` | Boolean | This indicates the mode setting. When the mode is "Switch mode", this value is `true`. When the mode is "Press mode", this value is `false`. |
| `state` | Boolean | This value indicates whether the switch status is ON or OFF. |
| `battery` | Integer | (**experimental**) This value indicates the battery level (`%`). |
The `mode` can be changed only using the official smartphone app. The node-switchbot does not support changing the mode because the BLE protocol is non-public.
If the `mode` is `false`, which means the "Press mode" is selected, the `state` is always `false`. If the `mode` is `true`, which means the "Switch mode" is selected, the `state` represents the logical state (ON or OFF). Note that it does *not* mean the physical arm position. The physical arm position depends on the setting "Inverse the on/off direction" on the official smartphone app.
If the `mode` is `false`, which means the "Press mode" is selected, the `state` is always `false`. If the `mode` is `true`, which means the "Switch mode" is selected, the `state` represents the logical state (ON or OFF). Note that it does _not_ mean the physical arm position. The physical arm position depends on the setting "Inverse the on/off direction" on the official smartphone app.
"Inverse the on/off direction" | Value of the `state` | Logical state | Physical arm position
:------------------------------|:---------------------|:--------------|:------------
disabled | `true` | OFF | Up (retracted)
&nbsp; | `false` | ON | Down (stretched)
enabled | `true` | OFF | Down (stretched)
&nbsp; | `false` | ON | Up (retracted)
| "Inverse the on/off direction" | Value of the `state` | Logical state | Physical arm position |
| :----------------------------- | :------------------- | :------------ | :-------------------- |
| disabled | `true` | OFF | Up (retracted) |
| &nbsp; | `false` | ON | Down (stretched) |
| enabled | `true` | OFF | Down (stretched) |
| &nbsp; | `false` | ON | Up (retracted) |
The `battery` is *experimental* for now. I'm not sure whether the value is correct or not. Never trust this value for now.
The `battery` is _experimental_ for now. I'm not sure whether the value is correct or not. Never trust this value for now.
### Meter (WoSensorTH)

@@ -890,16 +953,16 @@

Property | Type | Description
:-------------|:--------|:-----------
`model` | String | This value is always `"T"`, which means "Meter (WoSensorTH)".
`modelName` | String | This value is always `"WoSensorTH"`, which means "Meter".
`temperature` | Object |
&nbsp;&nbsp; `c` | Float | Temperature (degree Celsius/°C)
&nbsp;&nbsp; `f` | Float | Temperature (degree Fahrenheit/℉)
`fahrenheit` | Boolean | The flag whether the Meter shows Fahrenheit (`true`) or Celsius (`false`) for the temperature on the display
`humidity` | Integer | Humidity (`%`)
`battery` | Integer | (**experimental**) This value indicates the battery level (`%`).
| Property | Type | Description |
| :--------------- | :------ | :----------------------------------------------------------------------------------------------------------- |
| `model` | String | This value is always `"T"`, which means "Meter (WoSensorTH)". |
| `modelName` | String | This value is always `"WoSensorTH"`, which means "Meter". |
| `temperature` | Object |
| &nbsp;&nbsp; `c` | Float | Temperature (degree Celsius/°C) |
| &nbsp;&nbsp; `f` | Float | Temperature (degree Fahrenheit/℉) |
| `fahrenheit` | Boolean | The flag whether the Meter shows Fahrenheit (`true`) or Celsius (`false`) for the temperature on the display |
| `humidity` | Integer | Humidity (`%`) |
| `battery` | Integer | (**experimental**) This value indicates the battery level (`%`). |
The `fahrenheit` indicates the setting on the device. Note that it does *not* indicate the setting on the official smartphone app. The setting of the temperature unit on the device and the setting on the app are independent.
The `fahrenheit` indicates the setting on the device. Note that it does _not_ indicate the setting on the official smartphone app. The setting of the temperature unit on the device and the setting on the app are independent.
The `battery` is *experimental* for now. I'm not sure whether the value is correct or not. Never trust this value for now.
The `battery` is _experimental_ for now. I'm not sure whether the value is correct or not. Never trust this value for now.

@@ -928,10 +991,10 @@ ### Curtain (WoCurtain)

Property | Type | Description
:-------------|:--------|:-----------
`model` | String | This value is always `"c"`, which means "Curtain (WoCurtain)".
`modelName` | String | This value is always `"WoCurtain"`, which means "Curtain".
`calibration` | Boolean | This value indicates the calibration status (`true` or `false`).
`battery` | Integer | This value indicates the battery level (`1-100`, `%`).
`position` | Integer | This value indicates the percentage of current position (`0-100`, 0 is open, `%`).
`lightLevel` | Integer | This value indicates the light level of the light source currently set (`1-10`).
| Property | Type | Description |
| :------------ | :------ | :--------------------------------------------------------------------------------- |
| `model` | String | This value is always `"c"`, which means "Curtain (WoCurtain)". |
| `modelName` | String | This value is always `"WoCurtain"`, which means "Curtain". |
| `calibration` | Boolean | This value indicates the calibration status (`true` or `false`). |
| `battery` | Integer | This value indicates the battery level (`1-100`, `%`). |
| `position` | Integer | This value indicates the percentage of current position (`0-100`, 0 is open, `%`). |
| `lightLevel` | Integer | This value indicates the light level of the light source currently set (`1-10`). |

@@ -960,10 +1023,10 @@ ### Contact (WoContact)

Property | Type | Description
:-------------|:--------|:-----------
`model` | String | This value is always `"c"`, which means "Contact (WoContact)".
`modelName` | String | This value is always `"WoContact"`, which means "Contact".
`movement` | Boolean | This value indicates the motion status (`true` or `false`).
`battery` | Integer | This value indicates the battery level (`1-100`, `%`).
`doorState` | String | This value indicates the door Status (`close`, `open`, `timeout no closed`).
`lightLevel` | String | This value indicates the light level (`dark`, `bright`).
| Property | Type | Description |
| :----------- | :------ | :--------------------------------------------------------------------------- |
| `model` | String | This value is always `"c"`, which means "Contact (WoContact)". |
| `modelName` | String | This value is always `"WoContact"`, which means "Contact". |
| `movement` | Boolean | This value indicates the motion status (`true` or `false`). |
| `battery` | Integer | This value indicates the battery level (`1-100`, `%`). |
| `doorState` | String | This value indicates the door Status (`close`, `open`, `timeout no closed`). |
| `lightLevel` | String | This value indicates the light level (`dark`, `bright`). |

@@ -991,14 +1054,15 @@ ### Motion (WoMotion)

Property | Type | Description
:-------------|:--------|:-----------
`model` | String | This value is always `"s"`, which means "Motion (WoMotion)".
`modelName` | String | This value is always `"WoMotion"`, which means "Motion".
`movement` | Boolean | This value indicates the motion status (`true` or `false`).
`battery` | Integer | This value indicates the battery level (`1-100`, `%`).
`lightLevel` | String | This value indicates the light level (`dark`, `bright`).
| Property | Type | Description |
| :----------- | :------ | :----------------------------------------------------------- |
| `model` | String | This value is always `"s"`, which means "Motion (WoMotion)". |
| `modelName` | String | This value is always `"WoMotion"`, which means "Motion". |
| `movement` | Boolean | This value indicates the motion status (`true` or `false`). |
| `battery` | Integer | This value indicates the battery level (`1-100`, `%`). |
| `lightLevel` | String | This value indicates the light level (`dark`, `bright`). |
---------------------------------------
---
## References
* [Switchbot official global site](https://www.switch-bot.com/)
* [GitHub - OpenWonderLabs/SwitchBotAPI-BLE](https://github.com/OpenWonderLabs/SwitchBotAPI-BLE)
- [Switchbot official global site](https://www.switch-bot.com/)
- [GitHub - OpenWonderLabs/SwitchBotAPI-BLE](https://github.com/OpenWonderLabs/SwitchBotAPI-BLE)

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc