node-switchbot 3.0.2-beta.2 → 3.0.2-beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/dist/advertising.js +1 -1
  2. package/dist/advertising.js.map +1 -1
  3. package/dist/device/woblindtilt.d.ts +5 -2
  4. package/dist/device/woblindtilt.d.ts.map +1 -1
  5. package/dist/device/woblindtilt.js +6 -6
  6. package/dist/device/woblindtilt.js.map +1 -1
  7. package/dist/device/wobulb.d.ts +5 -2
  8. package/dist/device/wobulb.d.ts.map +1 -1
  9. package/dist/device/wobulb.js +14 -12
  10. package/dist/device/wobulb.js.map +1 -1
  11. package/dist/device/woceilinglight.d.ts +7 -4
  12. package/dist/device/woceilinglight.d.ts.map +1 -1
  13. package/dist/device/woceilinglight.js +15 -14
  14. package/dist/device/woceilinglight.js.map +1 -1
  15. package/dist/device/wocontact.d.ts +5 -2
  16. package/dist/device/wocontact.d.ts.map +1 -1
  17. package/dist/device/wocontact.js +6 -2
  18. package/dist/device/wocontact.js.map +1 -1
  19. package/dist/device/wocurtain.d.ts +5 -2
  20. package/dist/device/wocurtain.d.ts.map +1 -1
  21. package/dist/device/wocurtain.js +34 -20
  22. package/dist/device/wocurtain.js.map +1 -1
  23. package/dist/device/wohand.d.ts +6 -3
  24. package/dist/device/wohand.d.ts.map +1 -1
  25. package/dist/device/wohand.js +13 -14
  26. package/dist/device/wohand.js.map +1 -1
  27. package/dist/device/wohub2.d.ts +5 -2
  28. package/dist/device/wohub2.d.ts.map +1 -1
  29. package/dist/device/wohub2.js +6 -2
  30. package/dist/device/wohub2.js.map +1 -1
  31. package/dist/device/wohumi.d.ts +5 -2
  32. package/dist/device/wohumi.d.ts.map +1 -1
  33. package/dist/device/wohumi.js +6 -6
  34. package/dist/device/wohumi.js.map +1 -1
  35. package/dist/device/woiosensorth.d.ts +5 -2
  36. package/dist/device/woiosensorth.d.ts.map +1 -1
  37. package/dist/device/woiosensorth.js +6 -2
  38. package/dist/device/woiosensorth.js.map +1 -1
  39. package/dist/device/woplugmini.d.ts +8 -5
  40. package/dist/device/woplugmini.d.ts.map +1 -1
  41. package/dist/device/woplugmini.js +10 -10
  42. package/dist/device/woplugmini.js.map +1 -1
  43. package/dist/device/wopresence.d.ts +2 -0
  44. package/dist/device/wopresence.d.ts.map +1 -1
  45. package/dist/device/wopresence.js +3 -0
  46. package/dist/device/wopresence.js.map +1 -1
  47. package/dist/device/wosensorth.d.ts +2 -0
  48. package/dist/device/wosensorth.d.ts.map +1 -1
  49. package/dist/device/wosensorth.js +3 -0
  50. package/dist/device/wosensorth.js.map +1 -1
  51. package/dist/device/wostrip.d.ts +2 -0
  52. package/dist/device/wostrip.d.ts.map +1 -1
  53. package/dist/device/wostrip.js +3 -0
  54. package/dist/device/wostrip.js.map +1 -1
  55. package/dist/device.d.ts +33 -31
  56. package/dist/device.d.ts.map +1 -1
  57. package/dist/device.js +94 -90
  58. package/dist/device.js.map +1 -1
  59. package/dist/index.d.ts +17 -0
  60. package/dist/index.d.ts.map +1 -1
  61. package/dist/index.js +17 -0
  62. package/dist/index.js.map +1 -1
  63. package/dist/switchbot-ble.d.ts +22 -14
  64. package/dist/switchbot-ble.d.ts.map +1 -1
  65. package/dist/switchbot-ble.js +155 -289
  66. package/dist/switchbot-ble.js.map +1 -1
  67. package/dist/switchbot-openapi.d.ts +3 -2
  68. package/dist/switchbot-openapi.d.ts.map +1 -1
  69. package/dist/switchbot-openapi.js +4 -3
  70. package/dist/switchbot-openapi.js.map +1 -1
  71. package/dist/test/switchbot-ble.test.d.ts +2 -0
  72. package/dist/test/switchbot-ble.test.d.ts.map +1 -0
  73. package/dist/test/switchbot-ble.test.js +45 -0
  74. package/dist/test/switchbot-ble.test.js.map +1 -0
  75. package/dist/types/bledevicestatus.d.ts +5 -3
  76. package/dist/types/bledevicestatus.d.ts.map +1 -1
  77. package/package.json +1 -1
  78. package/dist/test/switchbot.test.d.ts +0 -2
  79. package/dist/test/switchbot.test.d.ts.map +0 -1
  80. package/dist/test/switchbot.test.js +0 -106
  81. package/dist/test/switchbot.test.js.map +0 -1
@@ -3,10 +3,10 @@ import { EventEmitter } from 'node:events';
3
3
  import * as Noble from '@stoprocent/noble';
4
4
  import { SwitchbotDevice } from './device.js';
5
5
  /**
6
- * SwitchBot class to interact with SwitchBot devices.
6
+ * SwitchBotBLE class to interact with SwitchBot devices.
7
7
  */
8
8
  export declare class SwitchBotBLE extends EventEmitter {
9
- private ready;
9
+ ready: Promise<void>;
10
10
  noble: typeof Noble;
11
11
  ondiscover?: (device: SwitchbotDevice) => Promise<void> | void;
12
12
  onadvertisement?: (ad: Ad) => Promise<void> | void;
@@ -22,45 +22,53 @@ export declare class SwitchBotBLE extends EventEmitter {
22
22
  * @param level - The severity level of the log (e.g., 'info', 'warn', 'error').
23
23
  * @param message - The log message to be emitted.
24
24
  */
25
- emitLog(level: string, message: string): Promise<void>;
25
+ log(level: string, message: string): Promise<void>;
26
26
  /**
27
27
  * Initializes the noble object.
28
28
  *
29
29
  * @param {Params} [params] - Optional parameters
30
30
  * @returns {Promise<void>} - Resolves when initialization is complete
31
31
  */
32
- init(params?: Params): Promise<void>;
32
+ private initialize;
33
33
  /**
34
- * Discover SwitchBot devices based on the provided parameters.
34
+ * Validates the parameters.
35
35
  *
36
- * @param {Params} params - The parameters for discovery.
37
- * @returns {Promise<SwitchbotDevice[]>} - A promise that resolves with a list of discovered devices.
36
+ * @param {Params} params - The parameters to validate.
37
+ * @param {Record<string, unknown>} schema - The schema to validate against.
38
+ * @returns {Promise<void>} - Resolves if parameters are valid, otherwise throws an error.
38
39
  */
39
- discover(params?: Params): Promise<SwitchbotDevice[]>;
40
+ validate(params: Params, schema: Record<string, unknown>): Promise<void>;
40
41
  /**
41
- * Initializes the noble object and waits for it to be powered on.
42
+ * Waits for the noble object to be powered on.
42
43
  *
43
44
  * @returns {Promise<void>} - Resolves when the noble object is powered on.
44
45
  */
45
- _init(): Promise<void>;
46
+ private waitForPowerOn;
47
+ /**
48
+ * Discover SwitchBot devices based on the provided parameters.
49
+ *
50
+ * @param {Params} params - The parameters for discovery.
51
+ * @returns {Promise<SwitchbotDevice[]>} - A promise that resolves with a list of discovered devices.
52
+ */
53
+ discover(params?: Params): Promise<SwitchbotDevice[]>;
46
54
  /**
47
- * Gets the device object based on the peripheral, id, and model.
55
+ * Creates a device object based on the peripheral, id, and model.
48
56
  *
49
57
  * @param {Noble.Peripheral} peripheral - The peripheral object.
50
58
  * @param {string} id - The device id.
51
59
  * @param {string} model - The device model.
52
60
  * @returns {Promise<SwitchbotDevice | null>} - The device object or null.
53
61
  */
54
- getDeviceObject(peripheral: Noble.Peripheral, id: string, model: string): Promise<SwitchbotDevice | null>;
62
+ private createDevice;
55
63
  /**
56
64
  * Filters advertising data based on id and model.
57
65
  *
58
66
  * @param {Ad} ad - The advertising data.
59
67
  * @param {string} id - The device id.
60
68
  * @param {string} model - The device model.
61
- * @returns {boolean} - True if the advertising data matches the id and model, false otherwise.
69
+ * @returns {Promise<boolean>} - True if the advertising data matches the id and model, false otherwise.
62
70
  */
63
- filterAdvertising(ad: Ad, id: string, model: string): Promise<boolean>;
71
+ private filterAd;
64
72
  /**
65
73
  * Starts scanning for SwitchBot devices.
66
74
  *
@@ -1 +1 @@
1
- {"version":3,"file":"switchbot-ble.d.ts","sourceRoot":"","sources":["../src/switchbot-ble.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAElD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAM1C,OAAO,KAAK,KAAK,MAAM,mBAAmB,CAAA;AAG1C,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAmB7C;;GAEG;AACH,qBAAa,YAAa,SAAQ,YAAY;IAC5C,OAAO,CAAC,KAAK,CAAe;IACrB,KAAK,EAAG,OAAO,KAAK,CAAA;IAC3B,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IAC9D,eAAe,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IAElD;;;;OAIG;gBACS,MAAM,CAAC,EAAE,MAAM;IAK3B;;;;;OAKG;IACU,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAInE;;;;;OAKG;IACG,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI1C;;;;;OAKG;IACG,QAAQ,CAAC,MAAM,GAAE,MAAW,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IAoH/D;;;;OAIG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA6B5B;;;;;;;OAOG;IACG,eAAe,CAAC,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAqE/G;;;;;;;OAOG;IACG,iBAAiB,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAmB5E;;;;;OAKG;IACG,SAAS,CAAC,MAAM,GAAE,MAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAsFnD;;;;OAIG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAU/B;;;;;OAKG;IACG,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAsBxC;AAED,OAAO,EAAE,eAAe,EAAE,CAAA"}
1
+ {"version":3,"file":"switchbot-ble.d.ts","sourceRoot":"","sources":["../src/switchbot-ble.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,EAAQ,MAAM,kBAAkB,CAAA;AAExD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAE1C,OAAO,KAAK,KAAK,MAAM,mBAAmB,CAAA;AAG1C,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAoB7C;;GAEG;AACH,qBAAa,YAAa,SAAQ,YAAY;IACrC,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;IACpB,KAAK,EAAG,OAAO,KAAK,CAAA;IAC3B,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IAC9D,eAAe,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IAElD;;;;OAIG;gBACS,MAAM,CAAC,EAAE,MAAM;IAK3B;;;;;OAKG;IACU,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI/D;;;;;OAKG;YACW,UAAU;IAIxB;;;;;;OAMG;IACU,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAQrF;;;;OAIG;YACW,cAAc;IA4B5B;;;;;OAKG;IACU,QAAQ,CAAC,MAAM,GAAE,MAAW,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IA+DtE;;;;;;;OAOG;YACW,YAAY;IA6B1B;;;;;;;OAOG;YACW,QAAQ;IAatB;;;;;OAKG;IACU,SAAS,CAAC,MAAM,GAAE,MAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAgC1D;;;;OAIG;IACU,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IActC;;;;;OAKG;IACU,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAO/C;AAED,OAAO,EAAE,eAAe,EAAE,CAAA"}
@@ -1,8 +1,4 @@
1
1
  import { EventEmitter } from 'node:events';
2
- /* Copyright(C) 2024, donavanbecker (https://github.com/donavanbecker). All rights reserved.
3
- *
4
- * switchbot.ts: Switchbot BLE API registration.
5
- */
6
2
  import * as Noble from '@stoprocent/noble';
7
3
  import { Advertising } from './advertising.js';
8
4
  import { SwitchbotDevice } from './device.js';
@@ -25,7 +21,7 @@ import { parameterChecker } from './parameter-checker.js';
25
21
  import { DEFAULT_DISCOVERY_DURATION, PRIMARY_SERVICE_UUID_LIST } from './settings.js';
26
22
  import { SwitchBotBLEModel } from './types/types.js';
27
23
  /**
28
- * SwitchBot class to interact with SwitchBot devices.
24
+ * SwitchBotBLE class to interact with SwitchBot devices.
29
25
  */
30
26
  export class SwitchBotBLE extends EventEmitter {
31
27
  ready;
@@ -39,7 +35,7 @@ export class SwitchBotBLE extends EventEmitter {
39
35
  */
40
36
  constructor(params) {
41
37
  super();
42
- this.ready = this.init(params);
38
+ this.ready = this.initialize(params);
43
39
  }
44
40
  /**
45
41
  * Emits a log event with the specified log level and message.
@@ -47,7 +43,7 @@ export class SwitchBotBLE extends EventEmitter {
47
43
  * @param level - The severity level of the log (e.g., 'info', 'warn', 'error').
48
44
  * @param message - The log message to be emitted.
49
45
  */
50
- async emitLog(level, message) {
46
+ async log(level, message) {
51
47
  this.emit('log', { level, message });
52
48
  }
53
49
  /**
@@ -56,222 +52,150 @@ export class SwitchBotBLE extends EventEmitter {
56
52
  * @param {Params} [params] - Optional parameters
57
53
  * @returns {Promise<void>} - Resolves when initialization is complete
58
54
  */
59
- async init(params) {
60
- this.noble = params && params.noble ? params.noble : Noble.default;
55
+ async initialize(params) {
56
+ this.noble = params?.noble ?? Noble.default;
61
57
  }
62
58
  /**
63
- * Discover SwitchBot devices based on the provided parameters.
59
+ * Validates the parameters.
64
60
  *
65
- * @param {Params} params - The parameters for discovery.
66
- * @returns {Promise<SwitchbotDevice[]>} - A promise that resolves with a list of discovered devices.
61
+ * @param {Params} params - The parameters to validate.
62
+ * @param {Record<string, unknown>} schema - The schema to validate against.
63
+ * @returns {Promise<void>} - Resolves if parameters are valid, otherwise throws an error.
67
64
  */
68
- async discover(params = {}) {
69
- const promise = new Promise((resolve, reject) => {
70
- // Check the parameters
71
- const valid = parameterChecker.check(params, {
72
- duration: { required: false, type: 'integer', min: 1, max: 60000 },
73
- model: {
74
- required: false,
75
- type: 'string',
76
- enum: [
77
- SwitchBotBLEModel.Bot,
78
- SwitchBotBLEModel.Curtain,
79
- SwitchBotBLEModel.Curtain3,
80
- SwitchBotBLEModel.Humidifier,
81
- SwitchBotBLEModel.Meter,
82
- SwitchBotBLEModel.MeterPlus,
83
- SwitchBotBLEModel.Hub2,
84
- SwitchBotBLEModel.OutdoorMeter,
85
- SwitchBotBLEModel.MotionSensor,
86
- SwitchBotBLEModel.ContactSensor,
87
- SwitchBotBLEModel.ColorBulb,
88
- SwitchBotBLEModel.CeilingLight,
89
- SwitchBotBLEModel.CeilingLightPro,
90
- SwitchBotBLEModel.StripLight,
91
- SwitchBotBLEModel.PlugMiniUS,
92
- SwitchBotBLEModel.PlugMiniJP,
93
- SwitchBotBLEModel.Lock,
94
- SwitchBotBLEModel.LockPro,
95
- SwitchBotBLEModel.BlindTilt,
96
- ],
97
- },
98
- id: { required: false, type: 'string', min: 12, max: 17 },
99
- quick: { required: false, type: 'boolean' },
100
- }, false);
101
- if (!valid) {
102
- this.emitLog('error', `parameterChecker: ${JSON.stringify(parameterChecker.error.message)}`);
103
- reject(new Error(parameterChecker.error.message));
104
- return;
105
- }
106
- if (!params) {
107
- params = {};
108
- }
109
- // Determine the values of the parameters
110
- const p = {
111
- duration: params.duration ?? DEFAULT_DISCOVERY_DURATION,
112
- model: params.model ?? '',
113
- id: params.id ?? '',
114
- quick: !!params.quick,
115
- };
116
- // Initialize the noble object
117
- this._init()
118
- .then(() => {
119
- if (this.noble === null) {
120
- return reject(new Error('noble failed to initialize'));
121
- }
122
- const peripherals = {};
123
- let timer = setTimeout(() => { }, 0);
124
- const finishDiscovery = () => {
125
- if (timer) {
126
- clearTimeout(timer);
127
- }
128
- this.noble.removeAllListeners('discover');
129
- this.noble.stopScanningAsync();
130
- const device_list = [];
131
- for (const addr in peripherals) {
132
- device_list.push(peripherals[addr]);
133
- }
134
- resolve(device_list);
135
- };
136
- // Set a handler for the 'discover' event
137
- this.noble.on('discover', async (peripheral) => {
138
- const device = await this.getDeviceObject(peripheral, p.id, p.model);
139
- if (!device) {
140
- return;
141
- }
142
- const id = device.id;
143
- peripherals[id] = device;
144
- if (this.ondiscover && typeof this.ondiscover === 'function') {
145
- this.ondiscover(device);
146
- }
147
- if (p.quick) {
148
- finishDiscovery();
149
- }
150
- });
151
- // Start scanning
152
- this.noble.startScanningAsync(PRIMARY_SERVICE_UUID_LIST, false).then(() => {
153
- timer = setTimeout(() => {
154
- finishDiscovery();
155
- }, p.duration);
156
- }).catch((error) => {
157
- reject(error);
158
- });
159
- })
160
- .catch((error) => {
161
- reject(error);
162
- });
163
- });
164
- return promise;
65
+ async validate(params, schema) {
66
+ const valid = parameterChecker.check(params, schema, false);
67
+ if (!valid) {
68
+ this.log('error', `parameterChecker: ${JSON.stringify(parameterChecker.error.message)}`);
69
+ throw new Error(parameterChecker.error.message);
70
+ }
165
71
  }
166
72
  /**
167
- * Initializes the noble object and waits for it to be powered on.
73
+ * Waits for the noble object to be powered on.
168
74
  *
169
75
  * @returns {Promise<void>} - Resolves when the noble object is powered on.
170
76
  */
171
- async _init() {
77
+ async waitForPowerOn() {
172
78
  await this.ready;
173
- const promise = new Promise((resolve, reject) => {
174
- if (this.noble._state === 'poweredOn') {
175
- resolve();
176
- return;
177
- }
79
+ if (this.noble._state === 'poweredOn') {
80
+ return;
81
+ }
82
+ return new Promise((resolve, reject) => {
178
83
  this.noble.once('stateChange', (state) => {
179
84
  switch (state) {
180
85
  case 'unsupported':
181
86
  case 'unauthorized':
182
87
  case 'poweredOff':
183
- reject(new Error(`Failed to initialize the Noble object: ${this.noble._state}`));
184
- return;
88
+ reject(new Error(`Failed to initialize the Noble object: ${state}`));
89
+ break;
185
90
  case 'resetting':
186
91
  case 'unknown':
187
- reject(new Error(`Adapter is not ready: ${this.noble._state}`));
188
- return;
92
+ reject(new Error(`Adapter is not ready: ${state}`));
93
+ break;
189
94
  case 'poweredOn':
190
95
  resolve();
191
- return;
96
+ break;
192
97
  default:
193
- reject(new Error(`Unknown state: ${this.noble._state}`));
98
+ reject(new Error(`Unknown state: ${state}`));
194
99
  }
195
100
  });
196
101
  });
197
- return promise;
198
102
  }
199
103
  /**
200
- * Gets the device object based on the peripheral, id, and model.
104
+ * Discover SwitchBot devices based on the provided parameters.
105
+ *
106
+ * @param {Params} params - The parameters for discovery.
107
+ * @returns {Promise<SwitchbotDevice[]>} - A promise that resolves with a list of discovered devices.
108
+ */
109
+ async discover(params = {}) {
110
+ await this.ready;
111
+ await this.validate(params, {
112
+ duration: { required: false, type: 'integer', min: 1, max: 60000 },
113
+ model: { required: false, type: 'string', enum: Object.values(SwitchBotBLEModel) },
114
+ id: { required: false, type: 'string', min: 12, max: 17 },
115
+ quick: { required: false, type: 'boolean' },
116
+ });
117
+ await this.waitForPowerOn();
118
+ if (!this.noble) {
119
+ throw new Error('noble failed to initialize');
120
+ }
121
+ const p = {
122
+ duration: params.duration ?? DEFAULT_DISCOVERY_DURATION,
123
+ model: params.model ?? '',
124
+ id: params.id ?? '',
125
+ quick: !!params.quick,
126
+ };
127
+ const peripherals = {};
128
+ let timer;
129
+ const finishDiscovery = async () => {
130
+ if (timer) {
131
+ clearTimeout(timer);
132
+ }
133
+ this.noble.removeAllListeners('discover');
134
+ try {
135
+ await this.noble.stopScanningAsync();
136
+ this.log('info', 'Stopped Scanning for SwitchBot BLE devices.');
137
+ }
138
+ catch (e) {
139
+ this.log('error', `discover stopScanningAsync error: ${JSON.stringify(e.message ?? e)}`);
140
+ }
141
+ return Object.values(peripherals);
142
+ };
143
+ return new Promise((resolve, reject) => {
144
+ this.noble.on('discover', async (peripheral) => {
145
+ const device = await this.createDevice(peripheral, p.id, p.model);
146
+ if (!device) {
147
+ return;
148
+ }
149
+ peripherals[device.id] = device;
150
+ if (this.ondiscover) {
151
+ this.ondiscover(device);
152
+ }
153
+ if (p.quick) {
154
+ resolve(await finishDiscovery());
155
+ }
156
+ });
157
+ this.noble.startScanningAsync(PRIMARY_SERVICE_UUID_LIST, false)
158
+ .then(() => {
159
+ timer = setTimeout(async () => resolve(await finishDiscovery()), p.duration);
160
+ })
161
+ .catch(reject);
162
+ });
163
+ }
164
+ /**
165
+ * Creates a device object based on the peripheral, id, and model.
201
166
  *
202
167
  * @param {Noble.Peripheral} peripheral - The peripheral object.
203
168
  * @param {string} id - The device id.
204
169
  * @param {string} model - The device model.
205
170
  * @returns {Promise<SwitchbotDevice | null>} - The device object or null.
206
171
  */
207
- async getDeviceObject(peripheral, id, model) {
208
- const ad = await Advertising.parse(peripheral, this.emitLog.bind(this));
209
- if (ad && await this.filterAdvertising(ad, id, model)) {
210
- let device;
211
- if (ad && ad.serviceData && ad.serviceData.model) {
212
- switch (ad.serviceData.model) {
213
- case SwitchBotBLEModel.Bot:
214
- device = new WoHand(peripheral, this.noble);
215
- break;
216
- case SwitchBotBLEModel.Curtain:
217
- case SwitchBotBLEModel.Curtain3:
218
- device = new WoCurtain(peripheral, this.noble);
219
- break;
220
- case SwitchBotBLEModel.Humidifier:
221
- device = new WoHumi(peripheral, this.noble);
222
- break;
223
- case SwitchBotBLEModel.Meter:
224
- device = new WoSensorTH(peripheral, this.noble);
225
- break;
226
- case SwitchBotBLEModel.MeterPlus:
227
- device = new WoSensorTH(peripheral, this.noble);
228
- break;
229
- case SwitchBotBLEModel.Hub2:
230
- device = new WoHub2(peripheral, this.noble);
231
- break;
232
- case SwitchBotBLEModel.OutdoorMeter:
233
- device = new WoIOSensorTH(peripheral, this.noble);
234
- break;
235
- case SwitchBotBLEModel.MotionSensor:
236
- device = new WoPresence(peripheral, this.noble);
237
- break;
238
- case SwitchBotBLEModel.ContactSensor:
239
- device = new WoContact(peripheral, this.noble);
240
- break;
241
- case SwitchBotBLEModel.ColorBulb:
242
- device = new WoBulb(peripheral, this.noble);
243
- break;
244
- case SwitchBotBLEModel.CeilingLight:
245
- device = new WoCeilingLight(peripheral, this.noble);
246
- break;
247
- case SwitchBotBLEModel.CeilingLightPro:
248
- device = new WoCeilingLight(peripheral, this.noble);
249
- break;
250
- case SwitchBotBLEModel.StripLight:
251
- device = new WoStrip(peripheral, this.noble);
252
- break;
253
- case SwitchBotBLEModel.PlugMiniUS:
254
- case SwitchBotBLEModel.PlugMiniJP:
255
- device = new WoPlugMini(peripheral, this.noble);
256
- break;
257
- case SwitchBotBLEModel.Lock:
258
- device = new WoSmartLock(peripheral, this.noble);
259
- break;
260
- case SwitchBotBLEModel.LockPro:
261
- device = new WoSmartLockPro(peripheral, this.noble);
262
- break;
263
- case SwitchBotBLEModel.BlindTilt:
264
- device = new WoBlindTilt(peripheral, this.noble);
265
- break;
266
- default: // 'resetting', 'unknown'
267
- device = new SwitchbotDevice(peripheral, this.noble);
268
- }
172
+ async createDevice(peripheral, id, model) {
173
+ const ad = await Advertising.parse(peripheral, this.log.bind(this));
174
+ if (ad && await this.filterAd(ad, id, model)) {
175
+ switch (ad.serviceData.model) {
176
+ case SwitchBotBLEModel.Bot: return new WoHand(peripheral, this.noble);
177
+ case SwitchBotBLEModel.Curtain:
178
+ case SwitchBotBLEModel.Curtain3: return new WoCurtain(peripheral, this.noble);
179
+ case SwitchBotBLEModel.Humidifier: return new WoHumi(peripheral, this.noble);
180
+ case SwitchBotBLEModel.Meter:
181
+ case SwitchBotBLEModel.MeterPlus: return new WoSensorTH(peripheral, this.noble);
182
+ case SwitchBotBLEModel.Hub2: return new WoHub2(peripheral, this.noble);
183
+ case SwitchBotBLEModel.OutdoorMeter: return new WoIOSensorTH(peripheral, this.noble);
184
+ case SwitchBotBLEModel.MotionSensor: return new WoPresence(peripheral, this.noble);
185
+ case SwitchBotBLEModel.ContactSensor: return new WoContact(peripheral, this.noble);
186
+ case SwitchBotBLEModel.ColorBulb: return new WoBulb(peripheral, this.noble);
187
+ case SwitchBotBLEModel.CeilingLight:
188
+ case SwitchBotBLEModel.CeilingLightPro: return new WoCeilingLight(peripheral, this.noble);
189
+ case SwitchBotBLEModel.StripLight: return new WoStrip(peripheral, this.noble);
190
+ case SwitchBotBLEModel.PlugMiniUS:
191
+ case SwitchBotBLEModel.PlugMiniJP: return new WoPlugMini(peripheral, this.noble);
192
+ case SwitchBotBLEModel.Lock: return new WoSmartLock(peripheral, this.noble);
193
+ case SwitchBotBLEModel.LockPro: return new WoSmartLockPro(peripheral, this.noble);
194
+ case SwitchBotBLEModel.BlindTilt: return new WoBlindTilt(peripheral, this.noble);
195
+ default: return new SwitchbotDevice(peripheral, this.noble);
269
196
  }
270
- return device || null;
271
- }
272
- else {
273
- return null;
274
197
  }
198
+ return null;
275
199
  }
276
200
  /**
277
201
  * Filters advertising data based on id and model.
@@ -279,23 +203,17 @@ export class SwitchBotBLE extends EventEmitter {
279
203
  * @param {Ad} ad - The advertising data.
280
204
  * @param {string} id - The device id.
281
205
  * @param {string} model - The device model.
282
- * @returns {boolean} - True if the advertising data matches the id and model, false otherwise.
206
+ * @returns {Promise<boolean>} - True if the advertising data matches the id and model, false otherwise.
283
207
  */
284
- async filterAdvertising(ad, id, model) {
208
+ async filterAd(ad, id, model) {
285
209
  if (!ad) {
286
210
  return false;
287
211
  }
288
- if (id) {
289
- id = id.toLowerCase().replace(/:/g, '');
290
- const ad_id = ad.address.toLowerCase().replace(/[^a-z0-9]/g, '');
291
- if (ad_id !== id) {
292
- return false;
293
- }
212
+ if (id && ad.address.toLowerCase().replace(/[^a-z0-9]/g, '') !== id.toLowerCase().replace(/:/g, '')) {
213
+ return false;
294
214
  }
295
- if (model) {
296
- if (ad.serviceData.model !== model) {
297
- return false;
298
- }
215
+ if (model && ad.serviceData.model !== model) {
216
+ return false;
299
217
  }
300
218
  return true;
301
219
  }
@@ -306,77 +224,31 @@ export class SwitchBotBLE extends EventEmitter {
306
224
  * @returns {Promise<void>} - Resolves when scanning starts successfully.
307
225
  */
308
226
  async startScan(params = {}) {
309
- const promise = new Promise((resolve, reject) => {
310
- // Check the parameters
311
- const valid = parameterChecker.check(params, {
312
- model: {
313
- required: false,
314
- type: 'string',
315
- enum: [
316
- SwitchBotBLEModel.Bot,
317
- SwitchBotBLEModel.Curtain,
318
- SwitchBotBLEModel.Curtain3,
319
- SwitchBotBLEModel.Humidifier,
320
- SwitchBotBLEModel.Meter,
321
- SwitchBotBLEModel.MeterPlus,
322
- SwitchBotBLEModel.Hub2,
323
- SwitchBotBLEModel.OutdoorMeter,
324
- SwitchBotBLEModel.MotionSensor,
325
- SwitchBotBLEModel.ContactSensor,
326
- SwitchBotBLEModel.ColorBulb,
327
- SwitchBotBLEModel.CeilingLight,
328
- SwitchBotBLEModel.CeilingLightPro,
329
- SwitchBotBLEModel.StripLight,
330
- SwitchBotBLEModel.PlugMiniUS,
331
- SwitchBotBLEModel.PlugMiniJP,
332
- SwitchBotBLEModel.Lock,
333
- SwitchBotBLEModel.LockPro,
334
- SwitchBotBLEModel.BlindTilt,
335
- ],
336
- },
337
- id: { required: false, type: 'string', min: 12, max: 17 },
338
- }, false);
339
- if (!valid) {
340
- this.emitLog('error', `parameterChecker: ${JSON.stringify(parameterChecker.error.message)}`);
341
- reject(new Error(parameterChecker.error.message));
342
- return;
343
- }
344
- // Initialize the noble object
345
- this._init()
346
- .then(() => {
347
- if (this.noble === null) {
348
- return reject(new Error('noble object failed to initialize'));
227
+ await this.ready;
228
+ await this.validate(params, {
229
+ model: { required: false, type: 'string', enum: Object.values(SwitchBotBLEModel) },
230
+ id: { required: false, type: 'string', min: 12, max: 17 },
231
+ });
232
+ await this.waitForPowerOn();
233
+ if (!this.noble) {
234
+ throw new Error('noble object failed to initialize');
235
+ }
236
+ const p = { model: params.model || '', id: params.id || '' };
237
+ this.noble.on('discover', async (peripheral) => {
238
+ const ad = await Advertising.parse(peripheral, this.log.bind(this));
239
+ if (ad && await this.filterAd(ad, p.id, p.model)) {
240
+ if (this.onadvertisement) {
241
+ this.onadvertisement(ad);
349
242
  }
350
- // Determine the values of the parameters
351
- const p = {
352
- model: params.model || '',
353
- id: params.id || '',
354
- };
355
- // Set a handler for the 'discover' event
356
- this.noble.on('discover', async (peripheral) => {
357
- const ad = await Advertising.parse(peripheral, this.emitLog.bind(this));
358
- if (ad && await this.filterAdvertising(ad, p.id, p.model)) {
359
- if (this.onadvertisement
360
- && typeof this.onadvertisement === 'function') {
361
- this.onadvertisement(ad);
362
- }
363
- }
364
- });
365
- // Start scanning
366
- this.noble.startScanningAsync(PRIMARY_SERVICE_UUID_LIST, true).then(() => {
367
- this.emitLog('info', 'Started Scanning for SwitchBot BLE devices.');
368
- resolve();
369
- }).catch((error) => {
370
- this.emitLog('error', `startScanning error: ${JSON.stringify(error.message)}`);
371
- reject(error);
372
- });
373
- })
374
- .catch((error) => {
375
- this.emitLog('error', `startScanning error: ${JSON.stringify(error.message)}`);
376
- reject(error);
377
- });
243
+ }
378
244
  });
379
- return promise;
245
+ try {
246
+ await this.noble.startScanningAsync(PRIMARY_SERVICE_UUID_LIST, true);
247
+ this.log('info', 'Started Scanning for SwitchBot BLE devices.');
248
+ }
249
+ catch (e) {
250
+ this.log('error', `startScanningAsync error: ${JSON.stringify(e.message ?? e)}`);
251
+ }
380
252
  }
381
253
  /**
382
254
  * Stops scanning for SwitchBot devices.
@@ -384,12 +256,17 @@ export class SwitchBotBLE extends EventEmitter {
384
256
  * @returns {Promise<void>} - Resolves when scanning stops successfully.
385
257
  */
386
258
  async stopScan() {
387
- if (this.noble === null) {
259
+ if (!this.noble) {
388
260
  return;
389
261
  }
390
262
  this.noble.removeAllListeners('discover');
391
- this.noble.stopScanningAsync();
392
- this.emitLog('info', 'Stopped Scanning for SwitchBot BLE devices.');
263
+ try {
264
+ await this.noble.stopScanningAsync();
265
+ this.log('info', 'Stopped Scanning for SwitchBot BLE devices.');
266
+ }
267
+ catch (e) {
268
+ this.log('error', `stopScanningAsync error: ${JSON.stringify(e.message ?? e)}`);
269
+ }
393
270
  }
394
271
  /**
395
272
  * Waits for the specified time.
@@ -398,21 +275,10 @@ export class SwitchBotBLE extends EventEmitter {
398
275
  * @returns {Promise<void>} - Resolves after the specified time.
399
276
  */
400
277
  async wait(msec) {
401
- return new Promise((resolve, reject) => {
402
- // Check the parameters
403
- const valid = parameterChecker.check({
404
- msec,
405
- }, {
406
- msec: { required: true, type: 'integer', min: 0 },
407
- }, true);
408
- if (!valid) {
409
- this.emitLog('error', `parameterChecker: ${JSON.stringify(parameterChecker.error.message)}`);
410
- reject(new Error(parameterChecker.error.message));
411
- return;
412
- }
413
- // Set a timer
414
- setTimeout(resolve, msec);
415
- });
278
+ if (typeof msec !== 'number' || msec < 0) {
279
+ throw new Error('Invalid parameter: msec must be a non-negative integer.');
280
+ }
281
+ return new Promise(resolve => setTimeout(resolve, msec));
416
282
  }
417
283
  }
418
284
  export { SwitchbotDevice };