@switchbot/homebridge-switchbot 1.6.4-beta.4 → 1.7.1-beta.1

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.
@@ -36,6 +36,8 @@ export class Contact {
36
36
  lightLevel!: serviceData['lightLevel'];
37
37
 
38
38
  // Config
39
+ set_minLux!: number;
40
+ set_maxLux!: number;
39
41
  scanDuration!: number;
40
42
  deviceLogging!: string;
41
43
  deviceRefreshRate!: number;
@@ -57,8 +59,8 @@ export class Contact {
57
59
 
58
60
  // Contact Config
59
61
  this.debugLog(`Contact Sensor: ${this.accessory.displayName} Config: (ble: ${device.ble}, offline: ${device.offline},`
60
- + ` hide_lightsensor: ${device.contact?.hide_lightsensor}, hide_motionsensor: ${device.contact?.hide_motionsensor})`);
61
-
62
+ + ` hide_lightsensor: ${device.contact?.hide_lightsensor}, hide_motionsensor: ${device.contact?.hide_motionsensor},`
63
+ + ` set_minLux: ${this.device.contact?.set_minLux}, set_maxLux: ${this.device.contact?.set_maxLux})`);
62
64
 
63
65
  // this is subject we use to track when we need to POST changes to the SwitchBot API
64
66
  this.doContactUpdate = new Subject();
@@ -89,7 +91,7 @@ export class Contact {
89
91
  this.service.setCharacteristic(this.platform.Characteristic.Name, accessory.displayName);
90
92
 
91
93
  // each service must implement at-minimum the "required characteristics" for the given service type
92
- // see https://developers.homebridge.io/#/service/MotionSensor
94
+ // see https://developers.homebridge.io/#/service/ContactSensor
93
95
 
94
96
  // Motion Sensor Service
95
97
  if (device.contact?.hide_motionsensor) {
@@ -125,6 +127,7 @@ export class Contact {
125
127
  this.debugLog(`Contact Sensor: ${accessory.displayName} Light Sensor Service Not Added`);
126
128
  }
127
129
 
130
+ // Battery Service
128
131
  if (device.ble) {
129
132
  (this.batteryService =
130
133
  accessory.getService(this.platform.Service.Battery) ||
@@ -191,6 +194,24 @@ export class Contact {
191
194
  }
192
195
  }
193
196
 
197
+ private minLux(): number {
198
+ if (this.device.contact?.set_minLux) {
199
+ this.set_minLux = this.device.contact!.set_minLux!;
200
+ } else {
201
+ this.set_minLux = 1;
202
+ }
203
+ return this.set_minLux;
204
+ }
205
+
206
+ private maxLux(): number {
207
+ if (this.device.contact?.set_maxLux) {
208
+ this.set_maxLux = this.device.contact!.set_maxLux!;
209
+ } else {
210
+ this.set_maxLux = 6001;
211
+ }
212
+ return this.set_maxLux;
213
+ }
214
+
194
215
  /**
195
216
  * Parse the device status from the SwitchBot api
196
217
  */
@@ -204,10 +225,6 @@ export class Contact {
204
225
 
205
226
  private async BLEparseStatus() {
206
227
  this.debugLog(`Contact Sensor: ${this.accessory.displayName} BLE parseStatus`);
207
- if (this.device.contact?.hide_motionsensor) {
208
- // Movement
209
- this.MotionDetected = Boolean(this.movement);
210
- }
211
228
  // Door State
212
229
  switch (this.doorState) {
213
230
  case 'open':
@@ -221,44 +238,107 @@ export class Contact {
221
238
  default:
222
239
  this.errorLog(`Contact Sensor: ${this.accessory.displayName} timeout no closed, doorstate: ${this.doorState}`);
223
240
  }
224
- if (this.device.contact?.hide_lightsensor) {// Light Level
225
- switch (this.lightLevel) {
226
- case 'dark':
227
- case 0:
228
- this.CurrentAmbientLightLevel = 0.0001;
229
- break;
230
- default:
231
- this.CurrentAmbientLightLevel = 100000;
241
+ // Movement
242
+ if (!this.device.contact?.hide_motionsensor) {
243
+ if (this.movement === undefined && this.platform.config.credentials?.openToken) {
244
+ this.openAPImotion();
245
+ } else if (this.movement === undefined) {
246
+ this.movement = false;
247
+ this.BLEmotion();
248
+ } else {
249
+ this.BLEmotion();
250
+ }
251
+ }
252
+ // Light Level
253
+ if (!this.device.contact?.hide_lightsensor) {
254
+ this.set_minLux = this.minLux();
255
+ this.set_maxLux = this.maxLux();
256
+ if (this.lightLevel === undefined && this.platform.config.credentials?.openToken) {
257
+ this.openAPIlux();
258
+ } else if (this.lightLevel === undefined) {
259
+ this.lightLevel = 100;
260
+ this.BLElux();
261
+ } else {
262
+ this.BLElux();
232
263
  }
233
264
  }
234
265
  // Battery
266
+ if (this.battery === undefined) {
267
+ this.battery === 100;
268
+ }
235
269
  this.BatteryLevel = Number(this.battery);
236
270
  if (this.BatteryLevel < 10) {
237
271
  this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
238
272
  } else {
239
273
  this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
240
274
  }
275
+ this.debugLog(`Contact Sensor: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}, StatusLowBattery: ${this.StatusLowBattery}`);
276
+ }
241
277
 
242
- this.debugLog(`Contact Sensor: ${this.accessory.displayName} ContactSensorState: ${this.ContactSensorState}, MotionDetected: `
243
- + `${this.MotionDetected}, CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}, BatteryLevel: ${this.BatteryLevel}`);
278
+ private BLEmotion() {
279
+ this.MotionDetected = Boolean(this.movement);
280
+ this.debugLog(`Contact Sensor: ${this.accessory.displayName} MotionDetected: ${this.MotionDetected}`);
281
+ }
282
+
283
+ private BLElux() {
284
+ switch (this.lightLevel) {
285
+ case 'dark':
286
+ case 0:
287
+ this.CurrentAmbientLightLevel = this.set_minLux;
288
+ break;
289
+ default:
290
+ this.CurrentAmbientLightLevel = this.set_maxLux;
291
+ }
292
+ this.debugLog(`Contact Sensor: ${this.accessory.displayName} LightLevel: ${this.lightLevel},`
293
+ + ` CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`);
244
294
  }
245
295
 
246
296
  private async openAPIparseStatus() {
247
297
  if (this.platform.config.credentials?.openToken) {
248
- this.debugLog(`Contact Sensor: ${this.accessory.displayName} OpenAPI parseStatus`);
249
- if (this.deviceStatus.body.openState === 'open') {
250
- this.ContactSensorState = this.platform.Characteristic.ContactSensorState.CONTACT_NOT_DETECTED;
251
- this.debugLog(`Contact Sensor: ${this.accessory.displayName} ContactSensorState: ${this.ContactSensorState}`);
252
- } else if (this.deviceStatus.body.openState === 'close') {
253
- this.ContactSensorState = this.platform.Characteristic.ContactSensorState.CONTACT_DETECTED;
254
- this.debugLog(`Contact Sensor: ${this.accessory.displayName} ContactSensorState: ${this.ContactSensorState}`);
255
- } else {
256
- this.debugLog(`Contact Sensor: ${this.accessory.displayName} openState: ${this.deviceStatus.body.openState}`);
298
+ // Contact State
299
+ this.openAPIcontact();
300
+ // Motion State
301
+ if (!this.device.contact?.hide_motionsensor) {
302
+ this.openAPImotion();
257
303
  }
258
- if (this.device.contact?.hide_motionsensor) {
259
- this.MotionDetected = Boolean(this.deviceStatus.body.moveDetected);
304
+ // Light Level
305
+ if (!this.device.contact?.hide_lightsensor) {
306
+ this.openAPIlux();
260
307
  }
261
- this.debugLog(`Contact Sensor: ${this.accessory.displayName} MotionDetected: ${this.MotionDetected}`);
308
+ }
309
+ }
310
+
311
+ private openAPIlux() {
312
+ this.set_minLux = this.minLux();
313
+ this.set_maxLux = this.maxLux();
314
+ switch (this.deviceStatus.body.brightness) {
315
+ case 'dim':
316
+ this.CurrentAmbientLightLevel = this.set_minLux;
317
+ break;
318
+ case 'bright':
319
+ default:
320
+ this.CurrentAmbientLightLevel = this.set_maxLux;
321
+ }
322
+ this.debugLog(`Contact Sensor: ${this.accessory.displayName} CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`);
323
+ }
324
+
325
+ private openAPImotion() {
326
+ if (typeof this.deviceStatus.body.moveDetected === 'boolean') {
327
+ this.MotionDetected = this.deviceStatus.body.moveDetected;
328
+ }
329
+ this.debugLog(`Contact Sensor: ${this.accessory.displayName} MotionDetected: ${this.MotionDetected}`);
330
+ }
331
+
332
+ private openAPIcontact() {
333
+ this.debugLog(`Contact Sensor: ${this.accessory.displayName} OpenAPI parseStatus`);
334
+ if (this.deviceStatus.body.openState === 'open') {
335
+ this.ContactSensorState = this.platform.Characteristic.ContactSensorState.CONTACT_NOT_DETECTED;
336
+ this.debugLog(`Contact Sensor: ${this.accessory.displayName} ContactSensorState: ${this.ContactSensorState}`);
337
+ } else if (this.deviceStatus.body.openState === 'close') {
338
+ this.ContactSensorState = this.platform.Characteristic.ContactSensorState.CONTACT_DETECTED;
339
+ this.debugLog(`Contact Sensor: ${this.accessory.displayName} ContactSensorState: ${this.ContactSensorState}`);
340
+ } else {
341
+ this.debugLog(`Contact Sensor: ${this.accessory.displayName} openState: ${this.deviceStatus.body.openState}`);
262
342
  }
263
343
  }
264
344
 
@@ -31,6 +31,7 @@ export class Curtain {
31
31
  battery: serviceData['battery'];
32
32
  position: serviceData['position'];
33
33
  lightLevel: serviceData['lightLevel'];
34
+ spaceBetweenLevels!: number;
34
35
 
35
36
  // Target
36
37
  setNewTarget!: boolean;
@@ -44,7 +45,6 @@ export class Curtain {
44
45
  scanDuration!: number;
45
46
  deviceLogging!: string;
46
47
  deviceRefreshRate!: number;
47
- spaceBetweenLevels!: number;
48
48
 
49
49
  // Updates
50
50
  curtainUpdateInProgress!: boolean;
@@ -17,9 +17,9 @@ export class Motion {
17
17
 
18
18
  // Characteristic Values
19
19
  MotionDetected!: CharacteristicValue;
20
+ CurrentAmbientLightLevel!: CharacteristicValue;
20
21
  BatteryLevel?: CharacteristicValue;
21
22
  StatusLowBattery?: CharacteristicValue;
22
- CurrentAmbientLightLevel?: CharacteristicValue;
23
23
 
24
24
  // OpenAPI Others
25
25
  deviceStatus!: deviceStatusResponse;
@@ -33,6 +33,8 @@ export class Motion {
33
33
  lightLevel!: serviceData['lightLevel'];
34
34
 
35
35
  // Config
36
+ set_minLux!: number;
37
+ set_maxLux!: number;
36
38
  scanDuration!: number;
37
39
  deviceLogging!: string;
38
40
  deviceRefreshRate!: number;
@@ -52,6 +54,11 @@ export class Motion {
52
54
  this.refreshRate();
53
55
  this.MotionDetected = false;
54
56
 
57
+ // Motion Config
58
+ this.debugLog(`Motion Sensor: ${this.accessory.displayName} Config: (ble: ${device.ble}, offline: ${device.offline},`
59
+ + ` hide_lightsensor: ${device.motion?.hide_lightsensor},`
60
+ + ` set_minLux: ${this.device.motion?.set_minLux}, set_maxLux: ${this.device.motion?.set_maxLux})`);
61
+
55
62
  // this is subject we use to track when we need to POST changes to the SwitchBot API
56
63
  this.doMotionUpdate = new Subject();
57
64
  this.motionUbpdateInProgress = false;
@@ -72,21 +79,6 @@ export class Motion {
72
79
  accessory.getService(this.platform.Service.MotionSensor) ||
73
80
  accessory.addService(this.platform.Service.MotionSensor)), `${accessory.displayName} Motion Sensor`;
74
81
 
75
- if (device.ble) {
76
- (this.lightSensorService =
77
- accessory.getService(this.platform.Service.LightSensor) ||
78
- accessory.addService(this.platform.Service.LightSensor)), `${accessory.displayName} Light Sensor`;
79
-
80
- this.lightSensorService.setCharacteristic(this.platform.Characteristic.Name, `${accessory.displayName} Light Sensor`);
81
-
82
-
83
- (this.batteryService =
84
- accessory.getService(this.platform.Service.Battery) ||
85
- accessory.addService(this.platform.Service.Battery)), `${accessory.displayName} Battery`;
86
-
87
- this.batteryService.setCharacteristic(this.platform.Characteristic.Name, `${accessory.displayName} Battery`);
88
- }
89
-
90
82
  // To avoid "Cannot add a Service with the same UUID another Service without also defining a unique 'subtype' property." error,
91
83
  // when creating multiple services of the same type, you need to use the following syntax to specify a name and subtype id:
92
84
  // accessory.getService('NAME') ?? accessory.addService(this.platform.Service.Motion, 'NAME', 'USER_DEFINED_SUBTYPE');
@@ -98,8 +90,31 @@ export class Motion {
98
90
  // each service must implement at-minimum the "required characteristics" for the given service type
99
91
  // see https://developers.homebridge.io/#/service/MotionSensor
100
92
 
101
- // create handlers for required characteristics
102
- //this.service.setCharacteristic(this.platform.Characteristic.ChargingState, 2);
93
+ // Light Sensor Service
94
+ if (device.motion?.hide_lightsensor) {
95
+ this.debugLog(`Motion Sensor: ${accessory.displayName} Removing Light Sensor Service`);
96
+ this.lightSensorService = this.accessory.getService(this.platform.Service.LightSensor);
97
+ accessory.removeService(this.lightSensorService!);
98
+ } else if (!this.lightSensorService) {
99
+ this.debugLog(`Motion Sensor: ${accessory.displayName} Add Light Sensor Service`);
100
+ (this.lightSensorService =
101
+ this.accessory.getService(this.platform.Service.LightSensor) ||
102
+ this.accessory.addService(this.platform.Service.LightSensor)), `${accessory.displayName} Light Sensor`;
103
+
104
+ this.lightSensorService.setCharacteristic(this.platform.Characteristic.Name, `${accessory.displayName} Light Sensor`);
105
+
106
+ } else {
107
+ this.debugLog(`Motion Sensor: ${accessory.displayName} Light Sensor Service Not Added`);
108
+ }
109
+
110
+ // Battery Service
111
+ if (device.ble) {
112
+ (this.batteryService =
113
+ accessory.getService(this.platform.Service.Battery) ||
114
+ accessory.addService(this.platform.Service.Battery)), `${accessory.displayName} Battery`;
115
+
116
+ this.batteryService.setCharacteristic(this.platform.Characteristic.Name, `${accessory.displayName} Battery`);
117
+ }
103
118
 
104
119
  // Retrieve initial values and updateHomekit
105
120
  this.updateHomeKitCharacteristics();
@@ -159,6 +174,24 @@ export class Motion {
159
174
  }
160
175
  }
161
176
 
177
+ private minLux(): number {
178
+ if (this.device.motion?.set_minLux) {
179
+ this.set_minLux = this.device.motion!.set_minLux!;
180
+ } else {
181
+ this.set_minLux = 1;
182
+ }
183
+ return this.set_minLux;
184
+ }
185
+
186
+ private maxLux(): number {
187
+ if (this.device.motion?.set_maxLux) {
188
+ this.set_maxLux = this.device.motion!.set_maxLux!;
189
+ } else {
190
+ this.set_maxLux = 6001;
191
+ }
192
+ return this.set_maxLux;
193
+ }
194
+
162
195
  /**
163
196
  * Parse the device status from the SwitchBot api
164
197
  */
@@ -172,49 +205,92 @@ export class Motion {
172
205
 
173
206
  private async BLEparseStatus() {
174
207
  this.debugLog(`Motion Sensor: ${this.accessory.displayName} BLE parseStatus`);
175
- this.MotionDetected = Boolean(this.movement);
176
- this.debugLog(`Motion Sensor: ${this.accessory.displayName} MotionDetected: ${this.MotionDetected}`);
208
+ // Movement
209
+ if (this.movement === undefined && this.platform.config.credentials?.openToken) {
210
+ this.openAPImotion();
211
+ } else if (this.movement === undefined) {
212
+ this.movement = false;
213
+ this.BLEmotion();
214
+ } else {
215
+ this.BLEmotion();
216
+ }
177
217
  // Light Level
178
- switch (this.lightLevel) {
179
- case 'dark':
180
- case 0:
181
- this.CurrentAmbientLightLevel = 0.0001;
182
- break;
183
- default:
184
- this.CurrentAmbientLightLevel = 100000;
218
+ if (!this.device.motion?.hide_lightsensor) {
219
+ this.set_minLux = this.minLux();
220
+ this.set_maxLux = this.maxLux();
221
+ if (this.lightLevel === undefined && this.platform.config.credentials?.openToken) {
222
+ this.openAPIlux();
223
+ } else if (this.lightLevel === undefined) {
224
+ this.lightLevel = 100;
225
+ this.BLElux();
226
+ } else {
227
+ this.BLElux();
228
+ }
185
229
  }
186
230
  // Battery
231
+ if (this.battery === undefined) {
232
+ this.battery = 100;
233
+ }
187
234
  this.BatteryLevel = Number(this.battery);
188
235
  if (this.BatteryLevel < 10) {
189
236
  this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
190
237
  } else {
191
238
  this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
192
239
  }
240
+ this.debugLog(`Motion Sensor: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}, StatusLowBattery: ${this.StatusLowBattery}`);
241
+ }
242
+
243
+ private BLEmotion() {
244
+ this.MotionDetected = Boolean(this.movement);
245
+ this.debugLog(`Motion Sensor: ${this.accessory.displayName} MotionDetected: ${this.MotionDetected}`);
246
+ }
247
+
248
+ private BLElux() {
249
+ switch (this.lightLevel) {
250
+ case 'dark':
251
+ case 1:
252
+ this.CurrentAmbientLightLevel = this.set_minLux;
253
+ break;
254
+ default:
255
+ this.CurrentAmbientLightLevel = this.set_maxLux;
256
+ }
257
+ this.debugLog(`Motion Sensor: ${this.accessory.displayName} LightLevel: ${this.lightLevel},`
258
+ + ` CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`);
193
259
  }
194
260
 
195
261
  private async openAPIparseStatus() {
196
- try {
197
- if (this.platform.config.credentials?.openToken) {
198
- this.debugLog(`Motion Sensor: ${this.accessory.displayName} OpenAPI parseStatus`);
199
- if (typeof this.deviceStatus.body.moveDetected === 'boolean') {
200
- this.MotionDetected = this.deviceStatus.body.moveDetected;
201
- }
202
- this.debugLog(`Motion Sensor: ${this.accessory.displayName} MotionDetected: ${this.MotionDetected}`);
203
- }
204
- } catch (e: any) {
205
- this.errorLog(`Motion Sensor: ${this.accessory.displayName} failed parseStatus with OpenAPI Connection`);
206
- if (this.deviceLogging === 'debug') {
207
- this.errorLog(`Motion Sensor: ${this.accessory.displayName} failed parseStatus with OpenAPI Connection,`
208
- + ` Error Message: ${JSON.stringify(e.message)}`);
209
- }
210
- if (this.platform.debugMode) {
211
- this.errorLog(`Motion Sensor: ${this.accessory.displayName} failed parseStatus with OpenAPI Connection,`
212
- + ` Error: ${JSON.stringify(e)}`);
262
+ if (this.platform.config.credentials?.openToken) {
263
+ this.debugLog(`Motion Sensor: ${this.accessory.displayName} OpenAPI parseStatus`);
264
+ // Motion State
265
+ this.openAPImotion();
266
+ // Light Level
267
+ if (!this.device.motion?.hide_lightsensor) {
268
+ this.openAPIlux();
213
269
  }
214
- this.apiError(e);
215
270
  }
216
271
  }
217
272
 
273
+ private openAPImotion() {
274
+ if (typeof this.deviceStatus.body.moveDetected === 'boolean') {
275
+ this.MotionDetected = this.deviceStatus.body.moveDetected;
276
+ }
277
+ this.debugLog(`Motion Sensor: ${this.accessory.displayName} MotionDetected: ${this.MotionDetected}`);
278
+ }
279
+
280
+ private openAPIlux() {
281
+ this.set_minLux = this.minLux();
282
+ this.set_maxLux = this.maxLux();
283
+ switch (this.deviceStatus.body.brightness) {
284
+ case 'dim':
285
+ this.CurrentAmbientLightLevel = this.set_minLux;
286
+ break;
287
+ case 'bright':
288
+ default:
289
+ this.CurrentAmbientLightLevel = this.set_maxLux;
290
+ }
291
+ this.debugLog(`Motion Sensor: ${this.accessory.displayName} CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`);
292
+ }
293
+
218
294
  /**
219
295
  * Asks the SwitchBot API for the latest device information
220
296
  */
@@ -257,7 +333,7 @@ export class Motion {
257
333
  // Start to monitor advertisement packets
258
334
  if (switchbot !== false) {
259
335
  switchbot.startScan({
260
- model: 's',
336
+ //model: 's',
261
337
  id: this.device.bleMac,
262
338
  }).then(() => {
263
339
  // Set an event hander
package/src/settings.ts CHANGED
@@ -48,6 +48,7 @@ export interface devicesConfig extends device {
48
48
  humidifier?: humidifier;
49
49
  curtain?: curtain;
50
50
  contact?: contact;
51
+ motion?: motion;
51
52
  colorbulb?: colorbulb;
52
53
  ble?: string;
53
54
  scanDuration?: number;
@@ -84,9 +85,17 @@ export type curtain = {
84
85
 
85
86
  export type contact = {
86
87
  hide_lightsensor?: boolean;
88
+ set_minLux?: number;
89
+ set_maxLux?: number;
87
90
  hide_motionsensor?: boolean;
88
91
  };
89
92
 
93
+ export type motion = {
94
+ hide_lightsensor?: boolean;
95
+ set_minLux?: number;
96
+ set_maxLux?: number;
97
+ };
98
+
90
99
  export type colorbulb = {
91
100
  set_minStep?: number;
92
101
  adaptiveLightingShift?: number;