node-switchbot 4.0.0-beta.1 → 4.0.0-beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/copilot-instructions.md +19 -5
- package/BLE.md +117 -4
- package/CHANGELOG.md +45 -0
- package/README.md +7 -1
- package/dist/api.d.ts +3 -3
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +9 -6
- package/dist/api.js.map +1 -1
- package/dist/ble.d.ts +38 -4
- package/dist/ble.d.ts.map +1 -1
- package/dist/ble.js +409 -53
- package/dist/ble.js.map +1 -1
- package/dist/devices/base.d.ts +83 -5
- package/dist/devices/base.d.ts.map +1 -1
- package/dist/devices/base.js +371 -34
- package/dist/devices/base.js.map +1 -1
- package/dist/devices/device-override-state-during-connection.d.ts +27 -0
- package/dist/devices/device-override-state-during-connection.d.ts.map +1 -0
- package/dist/devices/device-override-state-during-connection.js +45 -0
- package/dist/devices/device-override-state-during-connection.js.map +1 -0
- package/dist/devices/index.d.ts +4 -0
- package/dist/devices/index.d.ts.map +1 -1
- package/dist/devices/index.js +4 -0
- package/dist/devices/index.js.map +1 -1
- package/dist/devices/sequence-device.d.ts +36 -0
- package/dist/devices/sequence-device.d.ts.map +1 -0
- package/dist/devices/sequence-device.js +75 -0
- package/dist/devices/sequence-device.js.map +1 -0
- package/dist/devices/wo-air-purifier.d.ts +2 -2
- package/dist/devices/wo-air-purifier.d.ts.map +1 -1
- package/dist/devices/wo-air-purifier.js +2 -2
- package/dist/devices/wo-air-purifier.js.map +1 -1
- package/dist/devices/wo-bulb.d.ts +10 -0
- package/dist/devices/wo-bulb.d.ts.map +1 -1
- package/dist/devices/wo-bulb.js +69 -0
- package/dist/devices/wo-bulb.js.map +1 -1
- package/dist/devices/wo-curtain.d.ts +3 -3
- package/dist/devices/wo-curtain.d.ts.map +1 -1
- package/dist/devices/wo-curtain.js +12 -9
- package/dist/devices/wo-curtain.js.map +1 -1
- package/dist/devices/wo-hand.d.ts +53 -2
- package/dist/devices/wo-hand.d.ts.map +1 -1
- package/dist/devices/wo-hand.js +121 -3
- package/dist/devices/wo-hand.js.map +1 -1
- package/dist/devices/wo-lock-pro.d.ts +11 -2
- package/dist/devices/wo-lock-pro.d.ts.map +1 -1
- package/dist/devices/wo-lock-pro.js +65 -3
- package/dist/devices/wo-lock-pro.js.map +1 -1
- package/dist/devices/wo-lock.d.ts +7 -2
- package/dist/devices/wo-lock.d.ts.map +1 -1
- package/dist/devices/wo-lock.js +58 -3
- package/dist/devices/wo-lock.js.map +1 -1
- package/dist/devices/wo-plug-mini-us.d.ts +2 -2
- package/dist/devices/wo-plug-mini-us.d.ts.map +1 -1
- package/dist/devices/wo-plug-mini-us.js +2 -2
- package/dist/devices/wo-plug-mini-us.js.map +1 -1
- package/dist/devices/wo-relay-switch-1.d.ts +4 -2
- package/dist/devices/wo-relay-switch-1.d.ts.map +1 -1
- package/dist/devices/wo-relay-switch-1.js +36 -4
- package/dist/devices/wo-relay-switch-1.js.map +1 -1
- package/dist/devices/wo-relay-switch-2pm.d.ts +21 -0
- package/dist/devices/wo-relay-switch-2pm.d.ts.map +1 -0
- package/dist/devices/wo-relay-switch-2pm.js +39 -0
- package/dist/devices/wo-relay-switch-2pm.js.map +1 -0
- package/dist/devices/wo-rgbic-bulb.d.ts +29 -0
- package/dist/devices/wo-rgbic-bulb.d.ts.map +1 -0
- package/dist/devices/wo-rgbic-bulb.js +84 -0
- package/dist/devices/wo-rgbic-bulb.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/settings.d.ts +17 -0
- package/dist/settings.d.ts.map +1 -1
- package/dist/settings.js +18 -1
- package/dist/settings.js.map +1 -1
- package/dist/switchbot.d.ts.map +1 -1
- package/dist/switchbot.js +31 -8
- package/dist/switchbot.js.map +1 -1
- package/dist/types/ble.d.ts +20 -1
- package/dist/types/ble.d.ts.map +1 -1
- package/dist/types/ble.js.map +1 -1
- package/dist/types/device.d.ts +30 -3
- package/dist/types/device.d.ts.map +1 -1
- package/dist/types/index.d.ts +22 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js.map +1 -1
- package/dist/utils/bot-ble.d.ts +36 -0
- package/dist/utils/bot-ble.d.ts.map +1 -0
- package/dist/utils/bot-ble.js +109 -0
- package/dist/utils/bot-ble.js.map +1 -0
- package/dist/utils/circuit-breaker.d.ts +98 -0
- package/dist/utils/circuit-breaker.d.ts.map +1 -0
- package/dist/utils/circuit-breaker.js +187 -0
- package/dist/utils/circuit-breaker.js.map +1 -0
- package/dist/utils/connection-tracker.d.ts +66 -0
- package/dist/utils/connection-tracker.d.ts.map +1 -0
- package/dist/utils/connection-tracker.js +184 -0
- package/dist/utils/connection-tracker.js.map +1 -0
- package/dist/utils/fallback-handler.d.ts +68 -0
- package/dist/utils/fallback-handler.d.ts.map +1 -0
- package/dist/utils/fallback-handler.js +131 -0
- package/dist/utils/fallback-handler.js.map +1 -0
- package/dist/utils/index.d.ts +10 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +41 -4
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/retry.d.ts +55 -0
- package/dist/utils/retry.d.ts.map +1 -0
- package/dist/utils/retry.js +95 -0
- package/dist/utils/retry.js.map +1 -0
- package/docs/assets/hierarchy.js +1 -1
- package/docs/assets/navigation.js +1 -1
- package/docs/assets/search.js +1 -1
- package/docs/classes/APIError.html +2 -2
- package/docs/classes/APINotAvailableError.html +2 -2
- package/docs/classes/BLEConnection.html +16 -10
- package/docs/classes/BLENotAvailableError.html +2 -2
- package/docs/classes/BLEScanner.html +11 -9
- package/docs/classes/CommandFailedError.html +2 -2
- package/docs/classes/ConnectionTimeoutError.html +2 -2
- package/docs/classes/DeviceManager.html +13 -13
- package/docs/classes/DeviceNotFoundError.html +2 -2
- package/docs/classes/DeviceOverrideStateDuringConnection.html +56 -0
- package/docs/classes/DiscoveryError.html +2 -2
- package/docs/classes/OpenAPIClient.html +24 -24
- package/docs/classes/SequenceDevice.html +58 -0
- package/docs/classes/SwitchBot.html +11 -11
- package/docs/classes/SwitchBotDevice.html +43 -15
- package/docs/classes/SwitchBotError.html +2 -2
- package/docs/classes/ValidationError.html +2 -2
- package/docs/classes/WoAirPurifier.html +48 -18
- package/docs/classes/WoAirPurifierTable.html +48 -18
- package/docs/classes/WoBlindTilt.html +48 -20
- package/docs/classes/WoBulb.html +52 -19
- package/docs/classes/WoCeilingLight.html +52 -19
- package/docs/classes/WoContact.html +42 -14
- package/docs/classes/WoCurtain.html +46 -18
- package/docs/classes/WoHand.html +63 -19
- package/docs/classes/WoHub2.html +42 -14
- package/docs/classes/WoHub3.html +42 -14
- package/docs/classes/WoHumi.html +46 -18
- package/docs/classes/WoHumi2.html +46 -18
- package/docs/classes/WoIOSensorTH.html +42 -14
- package/docs/classes/WoKeypad.html +42 -14
- package/docs/classes/WoLeak.html +42 -14
- package/docs/classes/WoPlugMiniJP.html +45 -17
- package/docs/classes/WoPlugMiniUS.html +45 -17
- package/docs/classes/WoPresence.html +42 -14
- package/docs/classes/WoRelaySwitch1.html +47 -17
- package/docs/classes/WoRelaySwitch1PM.html +47 -17
- package/docs/classes/WoRemote.html +42 -14
- package/docs/classes/WoSensorTH.html +42 -14
- package/docs/classes/WoSensorTHPlus.html +42 -14
- package/docs/classes/WoSensorTHPro.html +42 -14
- package/docs/classes/WoSensorTHProCO2.html +42 -14
- package/docs/classes/WoSmartLock.html +49 -16
- package/docs/classes/WoSmartLockPro.html +52 -17
- package/docs/classes/WoStrip.html +52 -19
- package/docs/enums/LogLevel.html +2 -2
- package/docs/enums/SwitchBotBLEModel.html +2 -2
- package/docs/enums/SwitchBotBLEModelName.html +2 -2
- package/docs/functions/updateBaseURL.html +1 -1
- package/docs/hierarchy.html +1 -1
- package/docs/index.html +2 -2
- package/docs/interfaces/APICommandRequest.html +2 -2
- package/docs/interfaces/APICommandResponse.html +2 -2
- package/docs/interfaces/APIDevice.html +2 -2
- package/docs/interfaces/APIDeviceStatus.html +2 -2
- package/docs/interfaces/APIErrorResponse.html +2 -2
- package/docs/interfaces/APIResponse.html +2 -2
- package/docs/interfaces/AirPurifierCommands.html +2 -2
- package/docs/interfaces/AirPurifierServiceData.html +20 -5
- package/docs/interfaces/AirPurifierStatus.html +7 -7
- package/docs/interfaces/BLEAdvertisement.html +3 -2
- package/docs/interfaces/BLEScanOptions.html +5 -5
- package/docs/interfaces/BLEServiceData.html +22 -5
- package/docs/interfaces/BlindTiltCommands.html +2 -2
- package/docs/interfaces/BlindTiltServiceData.html +21 -5
- package/docs/interfaces/BlindTiltStatus.html +6 -6
- package/docs/interfaces/BotCommands.html +6 -2
- package/docs/interfaces/BotServiceData.html +20 -5
- package/docs/interfaces/BotStatus.html +6 -6
- package/docs/interfaces/BulbCommands.html +4 -2
- package/docs/interfaces/BulbServiceData.html +21 -5
- package/docs/interfaces/BulbStatus.html +6 -6
- package/docs/interfaces/CeilingLightCommands.html +4 -2
- package/docs/interfaces/CeilingLightServiceData.html +21 -5
- package/docs/interfaces/CeilingLightStatus.html +6 -6
- package/docs/interfaces/CommandResult.html +6 -6
- package/docs/interfaces/ContactServiceData.html +22 -5
- package/docs/interfaces/ContactStatus.html +6 -6
- package/docs/interfaces/CurtainCommands.html +2 -2
- package/docs/interfaces/CurtainServiceData.html +22 -5
- package/docs/interfaces/CurtainStatus.html +6 -6
- package/docs/interfaces/DeviceInfo.html +23 -13
- package/docs/interfaces/DeviceListResponse.html +2 -2
- package/docs/interfaces/DeviceStatus.html +6 -6
- package/docs/interfaces/DiscoveryOptions.html +7 -7
- package/docs/interfaces/HubServiceData.html +22 -5
- package/docs/interfaces/HubStatus.html +6 -6
- package/docs/interfaces/HumidifierCommands.html +2 -2
- package/docs/interfaces/HumidifierServiceData.html +23 -6
- package/docs/interfaces/HumidifierStatus.html +6 -6
- package/docs/interfaces/KeypadStatus.html +6 -6
- package/docs/interfaces/LeakServiceData.html +22 -5
- package/docs/interfaces/LeakStatus.html +6 -6
- package/docs/interfaces/LockCommands.html +6 -2
- package/docs/interfaces/LockServiceData.html +20 -6
- package/docs/interfaces/LockStatus.html +6 -6
- package/docs/interfaces/MeterServiceData.html +22 -5
- package/docs/interfaces/MeterStatus.html +6 -6
- package/docs/interfaces/MotionServiceData.html +22 -5
- package/docs/interfaces/MotionStatus.html +6 -6
- package/docs/interfaces/PlugCommands.html +2 -2
- package/docs/interfaces/PlugServiceData.html +21 -5
- package/docs/interfaces/PlugStatus.html +6 -6
- package/docs/interfaces/PresenceServiceData.html +22 -5
- package/docs/interfaces/PresenceStatus.html +6 -6
- package/docs/interfaces/RelaySwitchCommands.html +2 -2
- package/docs/interfaces/RelaySwitchServiceData.html +21 -5
- package/docs/interfaces/RelaySwitchStatus.html +6 -6
- package/docs/interfaces/RemoteStatus.html +6 -6
- package/docs/interfaces/SceneListResponse.html +2 -2
- package/docs/interfaces/StripCommands.html +4 -2
- package/docs/interfaces/StripServiceData.html +21 -5
- package/docs/interfaces/StripStatus.html +6 -6
- package/docs/interfaces/SwitchBotConfig.html +21 -9
- package/docs/interfaces/WebhookConfig.html +2 -2
- package/docs/interfaces/WebhookDetails.html +2 -2
- package/docs/interfaces/WebhookQueryResponse.html +2 -2
- package/docs/interfaces/WebhookSetupResponse.html +2 -2
- package/docs/media/BLE.md +117 -4
- package/docs/modules.html +1 -1
- package/docs/types/ConnectionType.html +1 -1
- package/docs/types/PhysicalDeviceType.html +1 -1
- package/docs/types/VirtualDeviceType.html +1 -1
- package/docs/variables/urls.html +1 -1
- package/package.json +11 -7
- package/tmp-switchbot-scan.mjs +79 -0
- package/todo/PYSWITCHBOT_COMPARISON.md +484 -0
- package/todo/README.md +68 -0
- package/todo/completed.md +134 -0
- package/todo/todo.md +296 -0
- package/tsconfig.build.json +17 -0
- package/PRODUCTION_READY.md +0 -135
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { ConnectionType } from '../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Statistics for a single connection type
|
|
4
|
+
*/
|
|
5
|
+
export interface ConnectionStats {
|
|
6
|
+
connectionType: ConnectionType;
|
|
7
|
+
successCount: number;
|
|
8
|
+
failureCount: number;
|
|
9
|
+
totalAttempts: number;
|
|
10
|
+
successRate: number;
|
|
11
|
+
averageLatencyMs: number;
|
|
12
|
+
lastAttemptTime?: Date;
|
|
13
|
+
lastSuccessTime?: Date;
|
|
14
|
+
lastFailureTime?: Date;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Tracks connection success/failure statistics per device per connection type
|
|
18
|
+
*/
|
|
19
|
+
export declare class ConnectionTracker {
|
|
20
|
+
private deviceId;
|
|
21
|
+
private stats;
|
|
22
|
+
private logger;
|
|
23
|
+
constructor(deviceId: string, logLevel?: number);
|
|
24
|
+
/**
|
|
25
|
+
* Record a successful attempt
|
|
26
|
+
*/
|
|
27
|
+
recordSuccess(connectionType: ConnectionType, latencyMs?: number): void;
|
|
28
|
+
/**
|
|
29
|
+
* Record a failed attempt
|
|
30
|
+
*/
|
|
31
|
+
recordFailure(connectionType: ConnectionType): void;
|
|
32
|
+
/**
|
|
33
|
+
* Get statistics for a connection type
|
|
34
|
+
*/
|
|
35
|
+
getStats(connectionType: ConnectionType): ConnectionStats | undefined;
|
|
36
|
+
/**
|
|
37
|
+
* Get all statistics
|
|
38
|
+
*/
|
|
39
|
+
getAllStats(): ConnectionStats[];
|
|
40
|
+
/**
|
|
41
|
+
* Get the best connection type (highest success rate)
|
|
42
|
+
*/
|
|
43
|
+
getBestConnection(availableTypes?: ConnectionType[]): ConnectionType | undefined;
|
|
44
|
+
/**
|
|
45
|
+
* Get the most recent successful connection type
|
|
46
|
+
*/
|
|
47
|
+
getMostRecentSuccessful(availableTypes?: ConnectionType[]): ConnectionType | undefined;
|
|
48
|
+
/**
|
|
49
|
+
* Check if a connection type is considered reliable
|
|
50
|
+
* (e.g., success rate > 75% with at least 5 attempts)
|
|
51
|
+
*/
|
|
52
|
+
isReliable(connectionType: ConnectionType, minAttempts?: number, minRate?: number): boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Get connection recommendation with reasoning
|
|
55
|
+
*/
|
|
56
|
+
getRecommendation(availableTypes?: ConnectionType[]): {
|
|
57
|
+
recommended: ConnectionType | undefined;
|
|
58
|
+
reason: string;
|
|
59
|
+
stats: ConnectionStats[];
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* Reset all statistics
|
|
63
|
+
*/
|
|
64
|
+
reset(): void;
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=connection-tracker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection-tracker.d.ts","sourceRoot":"","sources":["../../src/utils/connection-tracker.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAIvD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,cAAc,EAAE,cAAc,CAAA;IAC9B,YAAY,EAAE,MAAM,CAAA;IACpB,YAAY,EAAE,MAAM,CAAA;IACpB,aAAa,EAAE,MAAM,CAAA;IACrB,WAAW,EAAE,MAAM,CAAA;IACnB,gBAAgB,EAAE,MAAM,CAAA;IACxB,eAAe,CAAC,EAAE,IAAI,CAAA;IACtB,eAAe,CAAC,EAAE,IAAI,CAAA;IACtB,eAAe,CAAC,EAAE,IAAI,CAAA;CACvB;AAED;;GAEG;AACH,qBAAa,iBAAiB;IAK1B,OAAO,CAAC,QAAQ;IAJlB,OAAO,CAAC,KAAK,CAAkD;IAC/D,OAAO,CAAC,MAAM,CAAQ;gBAGZ,QAAQ,EAAE,MAAM,EACxB,QAAQ,CAAC,EAAE,MAAM;IAqBnB;;OAEG;IACH,aAAa,CAAC,cAAc,EAAE,cAAc,EAAE,SAAS,GAAE,MAAU,GAAG,IAAI;IAwB1E;;OAEG;IACH,aAAa,CAAC,cAAc,EAAE,cAAc,GAAG,IAAI;IAmBnD;;OAEG;IACH,QAAQ,CAAC,cAAc,EAAE,cAAc,GAAG,eAAe,GAAG,SAAS;IAIrE;;OAEG;IACH,WAAW,IAAI,eAAe,EAAE;IAIhC;;OAEG;IACH,iBAAiB,CAAC,cAAc,GAAE,cAAc,EAAmB,GAAG,cAAc,GAAG,SAAS;IAsBhG;;OAEG;IACH,uBAAuB,CAAC,cAAc,GAAE,cAAc,EAAmB,GAAG,cAAc,GAAG,SAAS;IAiBtG;;;OAGG;IACH,UAAU,CAAC,cAAc,EAAE,cAAc,EAAE,WAAW,GAAE,MAAU,EAAE,OAAO,GAAE,MAAa,GAAG,OAAO;IASpG;;OAEG;IACH,iBAAiB,CAAC,cAAc,GAAE,cAAc,EAAmB,GAAG;QACpE,WAAW,EAAE,cAAc,GAAG,SAAS,CAAA;QACvC,MAAM,EAAE,MAAM,CAAA;QACd,KAAK,EAAE,eAAe,EAAE,CAAA;KACzB;IAsCD;;OAEG;IACH,KAAK,IAAI,IAAI;CAad"}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/* Copyright(C) 2024-2026, donavanbecker (https://github.com/donavanbecker). All rights reserved.
|
|
2
|
+
*
|
|
3
|
+
* utils/connection-tracker.ts: SwitchBot v4.0.0 - Connection Success Tracking
|
|
4
|
+
*/
|
|
5
|
+
import { Logger } from './index.js';
|
|
6
|
+
/**
|
|
7
|
+
* Tracks connection success/failure statistics per device per connection type
|
|
8
|
+
*/
|
|
9
|
+
export class ConnectionTracker {
|
|
10
|
+
deviceId;
|
|
11
|
+
stats = new Map();
|
|
12
|
+
logger;
|
|
13
|
+
constructor(deviceId, logLevel) {
|
|
14
|
+
this.deviceId = deviceId;
|
|
15
|
+
this.logger = new Logger(`ConnectionTracker:${deviceId}`, logLevel);
|
|
16
|
+
// Initialize stats for all connection types
|
|
17
|
+
const connectionTypes = ['ble', 'api'];
|
|
18
|
+
for (const type of connectionTypes) {
|
|
19
|
+
this.stats.set(type, {
|
|
20
|
+
connectionType: type,
|
|
21
|
+
successCount: 0,
|
|
22
|
+
failureCount: 0,
|
|
23
|
+
totalAttempts: 0,
|
|
24
|
+
successRate: 1, // Start optimistic
|
|
25
|
+
averageLatencyMs: 0,
|
|
26
|
+
lastAttemptTime: undefined,
|
|
27
|
+
lastSuccessTime: undefined,
|
|
28
|
+
lastFailureTime: undefined,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Record a successful attempt
|
|
34
|
+
*/
|
|
35
|
+
recordSuccess(connectionType, latencyMs = 0) {
|
|
36
|
+
const stat = this.stats.get(connectionType);
|
|
37
|
+
if (!stat) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
stat.successCount++;
|
|
41
|
+
stat.totalAttempts++;
|
|
42
|
+
stat.lastAttemptTime = new Date();
|
|
43
|
+
stat.lastSuccessTime = new Date();
|
|
44
|
+
// Update average latency (exponential moving average)
|
|
45
|
+
const alpha = 0.3;
|
|
46
|
+
stat.averageLatencyMs = stat.averageLatencyMs * (1 - alpha) + latencyMs * alpha;
|
|
47
|
+
// Update success rate
|
|
48
|
+
stat.successRate = stat.totalAttempts === 0 ? 1 : stat.successCount / stat.totalAttempts;
|
|
49
|
+
this.logger.debug(`${connectionType}: success recorded`, {
|
|
50
|
+
successRate: stat.successRate.toFixed(2),
|
|
51
|
+
latency: latencyMs,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Record a failed attempt
|
|
56
|
+
*/
|
|
57
|
+
recordFailure(connectionType) {
|
|
58
|
+
const stat = this.stats.get(connectionType);
|
|
59
|
+
if (!stat) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
stat.failureCount++;
|
|
63
|
+
stat.totalAttempts++;
|
|
64
|
+
stat.lastAttemptTime = new Date();
|
|
65
|
+
stat.lastFailureTime = new Date();
|
|
66
|
+
// Update success rate
|
|
67
|
+
stat.successRate = stat.totalAttempts === 0 ? 1 : stat.successCount / stat.totalAttempts;
|
|
68
|
+
this.logger.debug(`${connectionType}: failure recorded`, {
|
|
69
|
+
successRate: stat.successRate.toFixed(2),
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Get statistics for a connection type
|
|
74
|
+
*/
|
|
75
|
+
getStats(connectionType) {
|
|
76
|
+
return this.stats.get(connectionType);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Get all statistics
|
|
80
|
+
*/
|
|
81
|
+
getAllStats() {
|
|
82
|
+
return [...this.stats.values()];
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Get the best connection type (highest success rate)
|
|
86
|
+
*/
|
|
87
|
+
getBestConnection(availableTypes = ['ble', 'api']) {
|
|
88
|
+
let bestType;
|
|
89
|
+
let bestRate = -1;
|
|
90
|
+
for (const type of availableTypes) {
|
|
91
|
+
const stat = this.stats.get(type);
|
|
92
|
+
if (stat && stat.successRate > bestRate) {
|
|
93
|
+
bestRate = stat.successRate;
|
|
94
|
+
bestType = type;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (bestType) {
|
|
98
|
+
const stat = this.stats.get(bestType);
|
|
99
|
+
if (stat.totalAttempts > 0) {
|
|
100
|
+
this.logger.debug(`Best connection: ${bestType} (success rate: ${stat.successRate.toFixed(2)})`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return bestType;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Get the most recent successful connection type
|
|
107
|
+
*/
|
|
108
|
+
getMostRecentSuccessful(availableTypes = ['ble', 'api']) {
|
|
109
|
+
let mostRecentType;
|
|
110
|
+
let mostRecentTime;
|
|
111
|
+
for (const type of availableTypes) {
|
|
112
|
+
const stat = this.stats.get(type);
|
|
113
|
+
if (stat?.lastSuccessTime) {
|
|
114
|
+
if (!mostRecentTime || stat.lastSuccessTime > mostRecentTime) {
|
|
115
|
+
mostRecentTime = stat.lastSuccessTime;
|
|
116
|
+
mostRecentType = type;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return mostRecentType;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Check if a connection type is considered reliable
|
|
124
|
+
* (e.g., success rate > 75% with at least 5 attempts)
|
|
125
|
+
*/
|
|
126
|
+
isReliable(connectionType, minAttempts = 5, minRate = 0.75) {
|
|
127
|
+
const stat = this.stats.get(connectionType);
|
|
128
|
+
if (!stat) {
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
return stat.totalAttempts >= minAttempts && stat.successRate >= minRate;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Get connection recommendation with reasoning
|
|
135
|
+
*/
|
|
136
|
+
getRecommendation(availableTypes = ['ble', 'api']) {
|
|
137
|
+
const stats = availableTypes.map(type => this.stats.get(type)).filter(Boolean);
|
|
138
|
+
// If no attempt history, recommend first available
|
|
139
|
+
if (stats.every(s => s.totalAttempts === 0)) {
|
|
140
|
+
return {
|
|
141
|
+
recommended: availableTypes[0],
|
|
142
|
+
reason: 'No history, using first available connection',
|
|
143
|
+
stats,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
// Find most reliable based on success rate
|
|
147
|
+
const bestType = this.getBestConnection(availableTypes);
|
|
148
|
+
if (!bestType) {
|
|
149
|
+
return {
|
|
150
|
+
recommended: undefined,
|
|
151
|
+
reason: 'No available connections',
|
|
152
|
+
stats,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
const bestStat = this.stats.get(bestType);
|
|
156
|
+
let reason = `${bestType} has best success rate (${bestStat.successRate.toFixed(2)})`;
|
|
157
|
+
// Add context about latency if applicable
|
|
158
|
+
if (bestStat.averageLatencyMs > 0) {
|
|
159
|
+
reason += ` with avg latency ${bestStat.averageLatencyMs.toFixed(0)}ms`;
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
recommended: bestType,
|
|
163
|
+
reason,
|
|
164
|
+
stats,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Reset all statistics
|
|
169
|
+
*/
|
|
170
|
+
reset() {
|
|
171
|
+
this.logger.debug('Resetting all statistics');
|
|
172
|
+
for (const stat of this.stats.values()) {
|
|
173
|
+
stat.successCount = 0;
|
|
174
|
+
stat.failureCount = 0;
|
|
175
|
+
stat.totalAttempts = 0;
|
|
176
|
+
stat.successRate = 1;
|
|
177
|
+
stat.averageLatencyMs = 0;
|
|
178
|
+
stat.lastAttemptTime = undefined;
|
|
179
|
+
stat.lastSuccessTime = undefined;
|
|
180
|
+
stat.lastFailureTime = undefined;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=connection-tracker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection-tracker.js","sourceRoot":"","sources":["../../src/utils/connection-tracker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { ConnectionType } from '../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Information about a fallback event
|
|
4
|
+
*/
|
|
5
|
+
export interface FallbackEvent {
|
|
6
|
+
deviceId: string;
|
|
7
|
+
primaryConnection: ConnectionType;
|
|
8
|
+
fallbackConnection: ConnectionType | undefined;
|
|
9
|
+
reason: string;
|
|
10
|
+
timestamp: Date;
|
|
11
|
+
attemptsCount?: number;
|
|
12
|
+
totalTimeMs?: number;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Type for custom fallback handler callbacks
|
|
16
|
+
*/
|
|
17
|
+
export type FallbackHandler = (event: FallbackEvent) => void | Promise<void>;
|
|
18
|
+
/**
|
|
19
|
+
* Options for registering a fallback handler
|
|
20
|
+
*/
|
|
21
|
+
export interface FallbackHandlerOptions {
|
|
22
|
+
/** Handler identifier for later removal */
|
|
23
|
+
id?: string;
|
|
24
|
+
/** Handler priority (higher = executes first) */
|
|
25
|
+
priority?: number;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Manages custom fallback handlers and events
|
|
29
|
+
*/
|
|
30
|
+
export declare class FallbackHandlerManager {
|
|
31
|
+
private handlers;
|
|
32
|
+
private logger;
|
|
33
|
+
private handlerCounter;
|
|
34
|
+
constructor(logLevel?: number);
|
|
35
|
+
/**
|
|
36
|
+
* Register a custom fallback handler
|
|
37
|
+
*/
|
|
38
|
+
register(handler: FallbackHandler, options?: FallbackHandlerOptions): string;
|
|
39
|
+
/**
|
|
40
|
+
* Unregister a fallback handler
|
|
41
|
+
*/
|
|
42
|
+
unregister(id: string): boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Emit a fallback event to all registered handlers
|
|
45
|
+
*/
|
|
46
|
+
emit(event: FallbackEvent): Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* Clear all handlers
|
|
49
|
+
*/
|
|
50
|
+
clear(): void;
|
|
51
|
+
/**
|
|
52
|
+
* Get handler count
|
|
53
|
+
*/
|
|
54
|
+
getHandlerCount(): number;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Built-in fallback handler: Log fallback events
|
|
58
|
+
*/
|
|
59
|
+
export declare function createLoggingFallbackHandler(logLevel?: number): FallbackHandler;
|
|
60
|
+
/**
|
|
61
|
+
* Built-in fallback handler: Metrics/statistics collection
|
|
62
|
+
*/
|
|
63
|
+
export declare function createMetricsCollectionHandler(): FallbackHandler;
|
|
64
|
+
/**
|
|
65
|
+
* Built-in fallback handler: Alert on repeated fallbacks
|
|
66
|
+
*/
|
|
67
|
+
export declare function createAlertHandler(alertThreshold?: number): FallbackHandler;
|
|
68
|
+
//# sourceMappingURL=fallback-handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fallback-handler.d.ts","sourceRoot":"","sources":["../../src/utils/fallback-handler.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAIvD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAA;IAChB,iBAAiB,EAAE,cAAc,CAAA;IACjC,kBAAkB,EAAE,cAAc,GAAG,SAAS,CAAA;IAC9C,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,IAAI,CAAA;IACf,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;AAE5E;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,2CAA2C;IAC3C,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,iDAAiD;IACjD,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED;;GAEG;AACH,qBAAa,sBAAsB;IACjC,OAAO,CAAC,QAAQ,CAGH;IAEb,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,cAAc,CAAI;gBAEd,QAAQ,CAAC,EAAE,MAAM;IAI7B;;OAEG;IACH,QAAQ,CACN,OAAO,EAAE,eAAe,EACxB,OAAO,GAAE,sBAA2B,GACnC,MAAM;IAUT;;OAEG;IACH,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAQ/B;;OAEG;IACG,IAAI,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAqB/C;;OAEG;IACH,KAAK,IAAI,IAAI;IAKb;;OAEG;IACH,eAAe,IAAI,MAAM;CAG1B;AAED;;GAEG;AACH,wBAAgB,4BAA4B,CAAC,QAAQ,GAAE,MAAU,GAAG,eAAe,CAmBlF;AAED;;GAEG;AACH,wBAAgB,8BAA8B,IAAI,eAAe,CA+BhE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,cAAc,GAAE,MAAU,GAAG,eAAe,CAkB9E"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/* Copyright(C) 2024-2026, donavanbecker (https://github.com/donavanbecker). All rights reserved.
|
|
2
|
+
*
|
|
3
|
+
* utils/fallback-handler.ts: SwitchBot v4.0.0 - Custom Fallback Handlers
|
|
4
|
+
*/
|
|
5
|
+
import { Logger } from './index.js';
|
|
6
|
+
/**
|
|
7
|
+
* Manages custom fallback handlers and events
|
|
8
|
+
*/
|
|
9
|
+
export class FallbackHandlerManager {
|
|
10
|
+
handlers = new Map();
|
|
11
|
+
logger;
|
|
12
|
+
handlerCounter = 0;
|
|
13
|
+
constructor(logLevel) {
|
|
14
|
+
this.logger = new Logger('FallbackHandlerManager', logLevel);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Register a custom fallback handler
|
|
18
|
+
*/
|
|
19
|
+
register(handler, options = {}) {
|
|
20
|
+
const id = options.id || `handler_${++this.handlerCounter}`;
|
|
21
|
+
const priority = options.priority ?? 0;
|
|
22
|
+
this.handlers.set(id, { handler, priority });
|
|
23
|
+
this.logger.debug(`Registered fallback handler: ${id} (priority: ${priority})`);
|
|
24
|
+
return id;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Unregister a fallback handler
|
|
28
|
+
*/
|
|
29
|
+
unregister(id) {
|
|
30
|
+
const removed = this.handlers.delete(id);
|
|
31
|
+
if (removed) {
|
|
32
|
+
this.logger.debug(`Unregistered fallback handler: ${id}`);
|
|
33
|
+
}
|
|
34
|
+
return removed;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Emit a fallback event to all registered handlers
|
|
38
|
+
*/
|
|
39
|
+
async emit(event) {
|
|
40
|
+
// Sort handlers by priority (descending)
|
|
41
|
+
// eslint-disable-next-line e18e/prefer-array-to-sorted
|
|
42
|
+
const sortedHandlers = [...this.handlers.entries()].sort((a, b) => b[1].priority - a[1].priority);
|
|
43
|
+
this.logger.debug(`Emitting fallback event to ${sortedHandlers.length} handlers`, {
|
|
44
|
+
device: event.deviceId,
|
|
45
|
+
primary: event.primaryConnection,
|
|
46
|
+
fallback: event.fallbackConnection,
|
|
47
|
+
});
|
|
48
|
+
for (const [id, { handler }] of sortedHandlers) {
|
|
49
|
+
try {
|
|
50
|
+
await Promise.resolve(handler(event));
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
this.logger.error(`Fallback handler ${id} threw error`, error);
|
|
54
|
+
// Continue with other handlers even if one fails
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Clear all handlers
|
|
60
|
+
*/
|
|
61
|
+
clear() {
|
|
62
|
+
this.logger.debug(`Clearing ${this.handlers.size} fallback handlers`);
|
|
63
|
+
this.handlers.clear();
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Get handler count
|
|
67
|
+
*/
|
|
68
|
+
getHandlerCount() {
|
|
69
|
+
return this.handlers.size;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Built-in fallback handler: Log fallback events
|
|
74
|
+
*/
|
|
75
|
+
export function createLoggingFallbackHandler(logLevel = 3) {
|
|
76
|
+
const logger = new Logger('FallbackLogger', logLevel);
|
|
77
|
+
return (event) => {
|
|
78
|
+
if (!event.fallbackConnection) {
|
|
79
|
+
logger.error(`Device ${event.deviceId}: ${event.primaryConnection} failed and no fallback available`);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
logger.warn(`Device ${event.deviceId}: ${event.primaryConnection} failed, falling back to ${event.fallbackConnection}`, {
|
|
83
|
+
reason: event.reason,
|
|
84
|
+
attempts: event.attemptsCount,
|
|
85
|
+
timeMs: event.totalTimeMs,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Built-in fallback handler: Metrics/statistics collection
|
|
92
|
+
*/
|
|
93
|
+
export function createMetricsCollectionHandler() {
|
|
94
|
+
const metrics = {
|
|
95
|
+
totalFallbacks: 0,
|
|
96
|
+
fallbacksByDevice: new Map(),
|
|
97
|
+
fallbacksByConnection: new Map(),
|
|
98
|
+
lastFallbackTime: undefined,
|
|
99
|
+
};
|
|
100
|
+
const handler = (event) => {
|
|
101
|
+
metrics.totalFallbacks++;
|
|
102
|
+
metrics.lastFallbackTime = event.timestamp;
|
|
103
|
+
const deviceCount = metrics.fallbacksByDevice.get(event.deviceId) || 0;
|
|
104
|
+
metrics.fallbacksByDevice.set(event.deviceId, deviceCount + 1);
|
|
105
|
+
if (event.fallbackConnection) {
|
|
106
|
+
const connectionKey = `${event.primaryConnection}->${event.fallbackConnection}`;
|
|
107
|
+
const count = metrics.fallbacksByConnection.get(connectionKey) || 0;
|
|
108
|
+
metrics.fallbacksByConnection.set(connectionKey, count + 1);
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
handler.getMetrics = () => ({ ...metrics });
|
|
112
|
+
return handler;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Built-in fallback handler: Alert on repeated fallbacks
|
|
116
|
+
*/
|
|
117
|
+
export function createAlertHandler(alertThreshold = 3) {
|
|
118
|
+
const fallbackCounts = new Map();
|
|
119
|
+
const logger = new Logger('FallbackAlertHandler');
|
|
120
|
+
return (event) => {
|
|
121
|
+
const count = (fallbackCounts.get(event.deviceId) || 0) + 1;
|
|
122
|
+
fallbackCounts.set(event.deviceId, count);
|
|
123
|
+
if (count === alertThreshold) {
|
|
124
|
+
logger.error(`ALERT: Device ${event.deviceId} has fallen back ${count} times - check connection`);
|
|
125
|
+
}
|
|
126
|
+
if (count > alertThreshold && count % alertThreshold === 0) {
|
|
127
|
+
logger.error(`ALERT: Device ${event.deviceId} has fallen back ${count} times`);
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=fallback-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fallback-handler.js","sourceRoot":"","sources":["../../src/utils/fallback-handler.ts"],"names":[],"mappings":"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"}
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -25,6 +25,11 @@ export declare function normalizeMAC(mac: string): string;
|
|
|
25
25
|
* Convert MAC address to device ID format
|
|
26
26
|
*/
|
|
27
27
|
export declare function macToDeviceId(mac: string): string;
|
|
28
|
+
/**
|
|
29
|
+
* Extract MAC address from manufacturer data (SwitchBot: company ID 0x0969)
|
|
30
|
+
* Bytes: [2 bytes company ID (69 09)] + [6 bytes MAC] + ...
|
|
31
|
+
*/
|
|
32
|
+
export declare function extractMacFromManufacturerData(manufacturerDataHex?: unknown): string | undefined;
|
|
28
33
|
/**
|
|
29
34
|
* Delay utility
|
|
30
35
|
*/
|
|
@@ -94,4 +99,9 @@ export declare function debounce<T extends (...args: any[]) => any>(fn: T, delay
|
|
|
94
99
|
* Throttle function
|
|
95
100
|
*/
|
|
96
101
|
export declare function throttle<T extends (...args: any[]) => any>(fn: T, limitMs: number): (...args: Parameters<T>) => void;
|
|
102
|
+
export { BOT_BLE_ACTIONS, type BotBleAction, buildBotBleCommand, parseBotBleResponse, validateBotPassword, } from './bot-ble.js';
|
|
103
|
+
export { CircuitBreaker, type CircuitBreakerConfig, CircuitBreakerState, type CircuitBreakerStats } from './circuit-breaker.js';
|
|
104
|
+
export { type ConnectionStats, ConnectionTracker } from './connection-tracker.js';
|
|
105
|
+
export { createAlertHandler, createLoggingFallbackHandler, createMetricsCollectionHandler, type FallbackEvent, type FallbackHandler, FallbackHandlerManager, type FallbackHandlerOptions, } from './fallback-handler.js';
|
|
106
|
+
export { type RetryConfig, RetryExecutor, type RetryResult } from './retry.js';
|
|
97
107
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAEjD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEpC;;GAEG;AACH,qBAAa,MAAM;IAEf,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,KAAK;gBADI,IAAI,EAAE,MAAM,EACrB,KAAK,GAAE,QAAY;IAG7B,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI;IAI/B,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI;IAM5C,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI;IAM3C,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI;IAM3C,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI;CAK7C;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"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"}
|
package/dist/utils/index.js
CHANGED
|
@@ -37,24 +37,54 @@ export class Logger {
|
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
|
+
// Regex patterns at module scope to avoid recompilation
|
|
41
|
+
const MAC_REGEX = /^(?:[0-9A-F]{2}[:-]){5}[0-9A-F]{2}$/i;
|
|
42
|
+
const DASH_REGEX = /-/g;
|
|
43
|
+
const COLON_REGEX = /:/g;
|
|
40
44
|
/**
|
|
41
45
|
* Validate MAC address format
|
|
42
46
|
*/
|
|
43
47
|
export function isValidMAC(mac) {
|
|
44
|
-
|
|
45
|
-
return macRegex.test(mac);
|
|
48
|
+
return MAC_REGEX.test(mac);
|
|
46
49
|
}
|
|
47
50
|
/**
|
|
48
51
|
* Normalize MAC address to lowercase with colons
|
|
49
52
|
*/
|
|
50
53
|
export function normalizeMAC(mac) {
|
|
51
|
-
return mac.toLowerCase().replace(
|
|
54
|
+
return mac.toLowerCase().replace(DASH_REGEX, ':');
|
|
52
55
|
}
|
|
53
56
|
/**
|
|
54
57
|
* Convert MAC address to device ID format
|
|
55
58
|
*/
|
|
56
59
|
export function macToDeviceId(mac) {
|
|
57
|
-
return mac.replace(
|
|
60
|
+
return mac.replace(COLON_REGEX, '').toUpperCase();
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Extract MAC address from manufacturer data (SwitchBot: company ID 0x0969)
|
|
64
|
+
* Bytes: [2 bytes company ID (69 09)] + [6 bytes MAC] + ...
|
|
65
|
+
*/
|
|
66
|
+
export function extractMacFromManufacturerData(manufacturerDataHex) {
|
|
67
|
+
if (!manufacturerDataHex || typeof manufacturerDataHex !== 'string') {
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
// Check if hex string starts with 6909 (SwitchBot company ID in little-endian)
|
|
71
|
+
if (!manufacturerDataHex.startsWith('6909')) {
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
// Extract 6 bytes (12 hex chars) starting at position 4 (after company ID)
|
|
75
|
+
const macHex = manufacturerDataHex.substring(4, 16);
|
|
76
|
+
if (macHex.length !== 12) {
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
// Convert to MAC address format: XX:XX:XX:XX:XX:XX
|
|
80
|
+
return [
|
|
81
|
+
macHex.substring(0, 2),
|
|
82
|
+
macHex.substring(2, 4),
|
|
83
|
+
macHex.substring(4, 6),
|
|
84
|
+
macHex.substring(6, 8),
|
|
85
|
+
macHex.substring(8, 10),
|
|
86
|
+
macHex.substring(10, 12),
|
|
87
|
+
].join(':').toUpperCase();
|
|
58
88
|
}
|
|
59
89
|
/**
|
|
60
90
|
* Delay utility
|
|
@@ -203,4 +233,11 @@ export function throttle(fn, limitMs) {
|
|
|
203
233
|
}
|
|
204
234
|
};
|
|
205
235
|
}
|
|
236
|
+
// Export Bot BLE password utilities
|
|
237
|
+
export { BOT_BLE_ACTIONS, buildBotBleCommand, parseBotBleResponse, validateBotPassword, } from './bot-ble.js';
|
|
238
|
+
export { CircuitBreaker, CircuitBreakerState } from './circuit-breaker.js';
|
|
239
|
+
export { ConnectionTracker } from './connection-tracker.js';
|
|
240
|
+
export { createAlertHandler, createLoggingFallbackHandler, createMetricsCollectionHandler, FallbackHandlerManager, } from './fallback-handler.js';
|
|
241
|
+
// Export advanced utilities
|
|
242
|
+
export { RetryExecutor } from './retry.js';
|
|
206
243
|
//# sourceMappingURL=index.js.map
|
package/dist/utils/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEpC;;GAEG;AACH,MAAM,OAAO,MAAM;IAEE;IACT;IAFV,YACmB,IAAY,EACrB,QAAkB,CAAC;QADV,SAAI,GAAJ,IAAI,CAAQ;QACrB,UAAK,GAAL,KAAK,CAAc;IAC1B,CAAC;IAEJ,QAAQ,CAAC,KAAe;QACtB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAA;IACpB,CAAC;IAED,KAAK,CAAC,OAAe,EAAE,GAAG,IAAW;QACnC,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC;YACpB,OAAO,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,IAAI,UAAU,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,CAAA;QAC1D,CAAC;IACH,CAAC;IAED,IAAI,CAAC,OAAe,EAAE,GAAG,IAAW;QAClC,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC;YACpB,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,SAAS,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,CAAA;QACxD,CAAC;IACH,CAAC;IAED,IAAI,CAAC,OAAe,EAAE,GAAG,IAAW;QAClC,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC;YACpB,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,SAAS,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,CAAA;QACxD,CAAC;IACH,CAAC;IAED,KAAK,CAAC,OAAe,EAAE,GAAG,IAAW;QACnC,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC;YACpB,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,UAAU,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,CAAA;QACzD,CAAC;IACH,CAAC;CACF;AAED
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"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"}
|