|
4 | 4 | */ |
5 | 5 | import type { Characteristic, Noble, Peripheral, Service } from '@stoprocent/noble' |
6 | 6 |
|
7 | | -import type { airPurifierServiceData, airPurifierTableServiceData, batteryCirculatorFanServiceData, blindTiltServiceData, botServiceData, ceilingLightProServiceData, ceilingLightServiceData, colorBulbServiceData, contactSensorServiceData, curtain3ServiceData, curtainServiceData, hub2ServiceData, hub3ServiceData, humidifier2ServiceData, humidifierServiceData, keypadDetectorServiceData, lockProServiceData, lockServiceData, meterPlusServiceData, meterProCO2ServiceData, meterProServiceData, meterServiceData, motionSensorServiceData, outdoorMeterServiceData, plugMiniJPServiceData, plugMiniUSServiceData, relaySwitch1PMServiceData, relaySwitch1ServiceData, remoteServiceData, robotVacuumCleanerServiceData, stripLightServiceData, waterLeakDetectorServiceData } from './types/ble.js' |
| 7 | +import type { airPurifierServiceData, airPurifierTableServiceData, batteryCirculatorFanServiceData, blindTiltServiceData, botServiceData, ceilingLightProServiceData, ceilingLightServiceData, colorBulbServiceData, contactSensorServiceData, curtain3ServiceData, curtainServiceData, hub2ServiceData, hub3ServiceData, humidifier2ServiceData, humidifierServiceData, keypadDetectorServiceData, lockProServiceData, lockServiceData, meterPlusServiceData, meterProCO2ServiceData, meterProServiceData, meterServiceData, motionSensorServiceData, outdoorMeterServiceData, plugMiniJPServiceData, plugMiniUSServiceData, presenceSensorServiceData, relaySwitch1PMServiceData, relaySwitch1ServiceData, remoteServiceData, robotVacuumCleanerServiceData, stripLightServiceData, waterLeakDetectorServiceData } from './types/ble.js' |
8 | 8 |
|
9 | 9 | import { Buffer } from 'node:buffer' |
10 | 10 | import * as Crypto from 'node:crypto' |
@@ -93,7 +93,7 @@ export interface ad { |
93 | 93 | id: string |
94 | 94 | address: string |
95 | 95 | rssi: number |
96 | | - serviceData: airPurifierServiceData | airPurifierTableServiceData | botServiceData | colorBulbServiceData | contactSensorServiceData | curtainServiceData | curtain3ServiceData | stripLightServiceData | lockServiceData | lockProServiceData | meterServiceData | meterPlusServiceData | meterProServiceData | meterProCO2ServiceData | motionSensorServiceData | outdoorMeterServiceData | plugMiniUSServiceData | plugMiniJPServiceData | blindTiltServiceData | ceilingLightServiceData | ceilingLightProServiceData | hub2ServiceData | hub3ServiceData | batteryCirculatorFanServiceData | waterLeakDetectorServiceData | humidifierServiceData | humidifier2ServiceData | robotVacuumCleanerServiceData | keypadDetectorServiceData | relaySwitch1PMServiceData | relaySwitch1ServiceData | remoteServiceData |
| 96 | + serviceData: airPurifierServiceData | airPurifierTableServiceData | botServiceData | colorBulbServiceData | contactSensorServiceData | curtainServiceData | curtain3ServiceData | stripLightServiceData | lockServiceData | lockProServiceData | meterServiceData | meterPlusServiceData | meterProServiceData | meterProCO2ServiceData | motionSensorServiceData | presenceSensorServiceData | outdoorMeterServiceData | plugMiniUSServiceData | plugMiniJPServiceData | blindTiltServiceData | ceilingLightServiceData | ceilingLightProServiceData | hub2ServiceData | hub3ServiceData | batteryCirculatorFanServiceData | waterLeakDetectorServiceData | humidifierServiceData | humidifier2ServiceData | robotVacuumCleanerServiceData | keypadDetectorServiceData | relaySwitch1PMServiceData | relaySwitch1ServiceData | remoteServiceData |
97 | 97 | [key: string]: unknown |
98 | 98 | } |
99 | 99 |
|
@@ -121,6 +121,7 @@ export declare interface SwitchBotBLEDevice { |
121 | 121 | Hub3: DeviceInfo |
122 | 122 | OutdoorMeter: DeviceInfo |
123 | 123 | MotionSensor: DeviceInfo |
| 124 | + PresenceSensor: DeviceInfo |
124 | 125 | ContactSensor: DeviceInfo |
125 | 126 | ColorBulb: DeviceInfo |
126 | 127 | StripLight: DeviceInfo |
@@ -154,6 +155,7 @@ export enum SwitchBotModel { |
154 | 155 | MeterProCO2 = 'W4900010', |
155 | 156 | OutdoorMeter = 'W3400010', |
156 | 157 | MotionSensor = 'W1101500', |
| 158 | + PresenceSensor = 'W8200000', |
157 | 159 | ContactSensor = 'W1201500', |
158 | 160 | ColorBulb = 'W1401400', |
159 | 161 | StripLight = 'W1701100', |
@@ -202,6 +204,7 @@ export enum SwitchBotBLEModel { |
202 | 204 | Hub3 = 'V', |
203 | 205 | OutdoorMeter = 'w', |
204 | 206 | MotionSensor = 's', |
| 207 | + PresenceSensor = 'p', |
205 | 208 | ContactSensor = 'd', |
206 | 209 | ColorBulb = 'u', |
207 | 210 | StripLight = 'r', |
@@ -237,6 +240,7 @@ export enum SwitchBotBLEModelName { |
237 | 240 | MeterProCO2 = 'WoSensorTHPc', |
238 | 241 | Lock = 'WoSmartLock', |
239 | 242 | LockPro = 'WoSmartLockPro', |
| 243 | + PresenceSensor = 'WoPresence', |
240 | 244 | PlugMini = 'WoPlugMini', |
241 | 245 | StripLight = 'WoStrip', |
242 | 246 | OutdoorMeter = 'WoIOSensorTH', |
@@ -277,6 +281,7 @@ export enum SwitchBotBLEModelFriendlyName { |
277 | 281 | OutdoorMeter = 'Outdoor Meter', |
278 | 282 | ContactSensor = 'Contact Sensor', |
279 | 283 | MotionSensor = 'Motion Sensor', |
| 284 | + PresenceSensor = 'Presence Sensor', |
280 | 285 | BlindTilt = 'Blind Tilt', |
281 | 286 | CeilingLight = 'Ceiling Light', |
282 | 287 | CeilingLightPro = 'Ceiling Light Pro', |
@@ -1066,6 +1071,8 @@ export class Advertising { |
1066 | 1071 | return WoAirPurifierTable.parseServiceData(serviceData, manufacturerData, emitLog) |
1067 | 1072 | case SwitchBotBLEModel.MotionSensor: |
1068 | 1073 | return WoPresence.parseServiceData(serviceData, emitLog) |
| 1074 | + case SwitchBotBLEModel.PresenceSensor: |
| 1075 | + return WoPresence.parsePresenceSensorServiceData(serviceData, manufacturerData, emitLog) |
1069 | 1076 | case SwitchBotBLEModel.ContactSensor: |
1070 | 1077 | return WoContact.parseServiceData(serviceData, emitLog) |
1071 | 1078 | case SwitchBotBLEModel.Remote: |
@@ -2741,6 +2748,8 @@ export class WoPlugMiniUS extends SwitchbotDevice { |
2741 | 2748 | } |
2742 | 2749 | } |
2743 | 2750 |
|
| 2751 | +const PRESENCE_SENSOR_BATTERY_RANGE_MAP = ['<10%', '10-19%', '20-59%', '>=60%'] as const |
| 2752 | + |
2744 | 2753 | /** |
2745 | 2754 | * Class representing a WoPresence device. |
2746 | 2755 | * @see https://github.com/OpenWonderLabs/SwitchBotAPI-BLE/blob/latest/devicetypes/meter.md |
@@ -2780,6 +2789,46 @@ export class WoPresence extends SwitchbotDevice { |
2780 | 2789 | return data |
2781 | 2790 | } |
2782 | 2791 |
|
| 2792 | + /** |
| 2793 | + * Parses the manufacturer data for presence sensors. |
| 2794 | + * @param {Buffer | null} serviceData - The optional service data buffer. |
| 2795 | + * @param {Buffer} manufacturerData - The manufacturer data buffer. |
| 2796 | + * @param {Function} emitLog - The function to emit log messages. |
| 2797 | + * @returns {Promise<presenceSensorServiceData | null>} - Parsed service data or null if invalid. |
| 2798 | + */ |
| 2799 | + static async parsePresenceSensorServiceData( |
| 2800 | + serviceData: Buffer | null, |
| 2801 | + manufacturerData: Buffer, |
| 2802 | + emitLog: (level: string, message: string) => void, |
| 2803 | + ): Promise<presenceSensorServiceData | null> { |
| 2804 | + if (!manufacturerData || manufacturerData.length < 12) { |
| 2805 | + emitLog('debugerror', `[parsePresenceSensorServiceData] Manufacturer buffer length ${manufacturerData?.length ?? 0} < 12!`) |
| 2806 | + return null |
| 2807 | + } |
| 2808 | + |
| 2809 | + const statusByte = manufacturerData[7] |
| 2810 | + const batteryBits = (statusByte >> 2) & 0b11 |
| 2811 | + |
| 2812 | + const data: presenceSensorServiceData = { |
| 2813 | + model: SwitchBotBLEModel.PresenceSensor, |
| 2814 | + modelName: SwitchBotBLEModelName.PresenceSensor, |
| 2815 | + modelFriendlyName: SwitchBotBLEModelFriendlyName.PresenceSensor, |
| 2816 | + sequenceNumber: manufacturerData[6], |
| 2817 | + adaptiveState: !!(statusByte & 0b10000000), |
| 2818 | + motionDetected: !!(statusByte & 0b01000000), |
| 2819 | + batteryRange: PRESENCE_SENSOR_BATTERY_RANGE_MAP[batteryBits] ?? 'Unknown', |
| 2820 | + triggerFlag: manufacturerData[10], |
| 2821 | + ledState: !!(manufacturerData[11] & 0b10000000), |
| 2822 | + lightLevel: manufacturerData[11] & 0x0F, |
| 2823 | + } |
| 2824 | + |
| 2825 | + if (serviceData && serviceData.length >= 3) { |
| 2826 | + data.battery = serviceData[2] & 0x7F |
| 2827 | + } |
| 2828 | + |
| 2829 | + return data |
| 2830 | + } |
| 2831 | + |
2783 | 2832 | constructor(peripheral: NobleTypes['peripheral'], noble: NobleTypes['noble']) { |
2784 | 2833 | super(peripheral, noble) |
2785 | 2834 | } |
|
0 commit comments