@switchbot/homebridge-switchbot 5.0.0-beta.42 → 5.0.0-beta.43
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/CHANGELOG.md +2 -0
- package/README.md +22 -0
- package/config.schema.json +10 -0
- package/dist/platform-hap.d.ts +5 -0
- package/dist/platform-hap.d.ts.map +1 -1
- package/dist/platform-hap.js +68 -14
- package/dist/platform-hap.js.map +1 -1
- package/dist/platform-matter.d.ts +5 -0
- package/dist/platform-matter.d.ts.map +1 -1
- package/dist/platform-matter.js +60 -6
- package/dist/platform-matter.js.map +1 -1
- package/dist/settings.d.ts +5 -0
- package/dist/settings.d.ts.map +1 -1
- package/dist/settings.js.map +1 -1
- package/dist/utils.d.ts +8 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +64 -16
- package/dist/utils.js.map +1 -1
- package/docs/assets/highlight.css +14 -0
- package/docs/index.html +12 -1
- package/docs/variables/default.html +1 -1
- package/package.json +1 -1
- package/src/platform-hap.ts +72 -14
- package/src/platform-matter.ts +67 -6
- package/src/settings.ts +5 -0
- package/src/utils.ts +74 -25
package/CHANGELOG.md
CHANGED
|
@@ -14,6 +14,8 @@ All notable changes to this project will be documented in this file. This projec
|
|
|
14
14
|
- Centralize OpenAPI/BLE -> Matter mapping and expand BLE/OpenAPI parsing to include PM2.5/PM10/VOC/CO2, temperature/humidity, improved color parsing, and additional sensor/robot-vacuum fields.
|
|
15
15
|
- Prefer accessory-specific update helpers where available; fall back to generic Matter updates otherwise.
|
|
16
16
|
- Add unit tests covering BLE parsing, stale-accessory behavior, mapping helpers, and lifecycle cleanup.
|
|
17
|
+
- Add `options.dailyApiResetLocalMidnight` (boolean) to control whether the daily API budget resets at local midnight (true) or UTC midnight (false, default).
|
|
18
|
+
- Fix configuration schema placement for the "Reset Daily Counter at Local Midnight" option: remove erroneous insertion inside IR remote type list and expose it correctly under platform `options`.
|
|
17
19
|
|
|
18
20
|
## [4.3.1](https://github.com/OpenWonderLabs/homebridge-switchbot/releases/tag/v4.3.1) (2025-03-04)
|
|
19
21
|
|
package/README.md
CHANGED
|
@@ -238,6 +238,28 @@ Reliability and rate-limiting:
|
|
|
238
238
|
|
|
239
239
|
These controls keep API usage smooth and predictable while preserving per-device control when needed.
|
|
240
240
|
|
|
241
|
+
## OpenAPI rate limiting and daily budget
|
|
242
|
+
|
|
243
|
+
To prevent hitting SwitchBot’s daily OpenAPI limit, the plugin provides several platform-level options under `options`:
|
|
244
|
+
|
|
245
|
+
- `dailyApiLimit` (number, default 10000): maximum OpenAPI requests per day that the plugin will allow.
|
|
246
|
+
- `dailyApiReserveForCommands` (number, default 1000): requests reserved for user actions so background polling pauses before the hard limit.
|
|
247
|
+
- `webhookOnlyOnReserve` (boolean, default false): when remaining budget reaches the reserve, pause background polling/discovery; webhooks and commands continue until the hard limit.
|
|
248
|
+
- `dailyApiResetLocalMidnight` (boolean, default false): if true, resets the daily counter at local midnight; when false, resets at UTC midnight.
|
|
249
|
+
|
|
250
|
+
Example (excerpt):
|
|
251
|
+
|
|
252
|
+
```json
|
|
253
|
+
{
|
|
254
|
+
"options": {
|
|
255
|
+
"dailyApiLimit": 10000,
|
|
256
|
+
"dailyApiReserveForCommands": 1000,
|
|
257
|
+
"webhookOnlyOnReserve": false,
|
|
258
|
+
"dailyApiResetLocalMidnight": true
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
241
263
|
## SwitchBot APIs
|
|
242
264
|
|
|
243
265
|
- [OpenWonderLabs/node-switchbot](https://github.com/OpenWonderLabs/node-switchbot)
|
package/config.schema.json
CHANGED
|
@@ -1593,6 +1593,12 @@
|
|
|
1593
1593
|
"default": false,
|
|
1594
1594
|
"description": "If true, completely stop background polling/discovery once the remaining budget hits the reserve. Webhooks and commands still work until the hard limit."
|
|
1595
1595
|
},
|
|
1596
|
+
"dailyApiResetLocalMidnight": {
|
|
1597
|
+
"title": "Reset Daily Counter at Local Midnight",
|
|
1598
|
+
"type": "boolean",
|
|
1599
|
+
"default": false,
|
|
1600
|
+
"description": "If enabled, the daily API counter resets at local (system timezone) midnight. When disabled, it resets at UTC midnight."
|
|
1601
|
+
},
|
|
1596
1602
|
"logging": {
|
|
1597
1603
|
"title": "Logging Setting",
|
|
1598
1604
|
"type": "string",
|
|
@@ -1858,6 +1864,10 @@
|
|
|
1858
1864
|
"key": "options.keepStaleAccessories",
|
|
1859
1865
|
"description": "<em class='primary-text'>If true, previously-registered accessories for devices that are no longer discovered or configured will be kept on the bridge. Default: false (stale accessories are removed automatically).</em>"
|
|
1860
1866
|
},
|
|
1867
|
+
{
|
|
1868
|
+
"key": "options.dailyApiResetLocalMidnight",
|
|
1869
|
+
"description": "<em class='primary-text'>If true, the daily API request counter will reset at local midnight (system timezone). If false (default), it will reset at UTC midnight.</em>"
|
|
1870
|
+
},
|
|
1861
1871
|
{
|
|
1862
1872
|
"key": "options.allowInvalidCharacters",
|
|
1863
1873
|
"description": "<em class='primary-text'>Allows device names with characters that are normally invalid in HomeKit. Use with caution, as this may lead to unexpected behavior.</em>"
|
package/dist/platform-hap.d.ts
CHANGED
|
@@ -143,6 +143,11 @@ export declare class SwitchBotHAPPlatform implements DynamicPlatformPlugin {
|
|
|
143
143
|
* @returns {Promise<void>} A promise that resolves when the version has been retrieved and logged.
|
|
144
144
|
*/
|
|
145
145
|
getVersion(): Promise<void>;
|
|
146
|
+
/**
|
|
147
|
+
* Validate that the user's configuration won't exceed API limits
|
|
148
|
+
* Warn if device count × polling frequency will hit daily limits
|
|
149
|
+
*/
|
|
150
|
+
private validateApiUsageConfig;
|
|
146
151
|
/**
|
|
147
152
|
* Validate and clean a string value for a Name Characteristic.
|
|
148
153
|
* @param displayName - The display name of the accessory.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"platform-hap.d.ts","sourceRoot":"","sources":["../src/platform-hap.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"platform-hap.d.ts","sourceRoot":"","sources":["../src/platform-hap.ts"],"names":[],"mappings":"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"}
|
package/dist/platform-hap.js
CHANGED
|
@@ -203,6 +203,7 @@ export class SwitchBotHAPPlatform {
|
|
|
203
203
|
dailyLimit: dailyApiLimit,
|
|
204
204
|
reserveForCommands: dailyApiReserveForCommands,
|
|
205
205
|
pausePollingAtReserve: webhookOnlyOnReserve,
|
|
206
|
+
resetAtLocalMidnight: this.config.options?.dailyApiResetAtLocalMidnight ?? false,
|
|
206
207
|
});
|
|
207
208
|
this.apiTracker.startHourlyLogging();
|
|
208
209
|
}
|
|
@@ -465,8 +466,12 @@ export class SwitchBotHAPPlatform {
|
|
|
465
466
|
const { response, statusCode } = await this.switchBotAPI.getDevices();
|
|
466
467
|
this.debugLog(`response: ${JSON.stringify(response)}`);
|
|
467
468
|
if (this.isSuccessfulResponse(statusCode)) {
|
|
468
|
-
|
|
469
|
-
|
|
469
|
+
const deviceList = Array.isArray(response.body.deviceList) ? response.body.deviceList : [];
|
|
470
|
+
const irDeviceList = Array.isArray(response.body.infraredRemoteList) ? response.body.infraredRemoteList : [];
|
|
471
|
+
await this.handleDevices(deviceList);
|
|
472
|
+
await this.handleIRDevices(irDeviceList);
|
|
473
|
+
// Diagnostic: warn users if their device count + refresh rate may exceed daily limits
|
|
474
|
+
this.validateApiUsageConfig(deviceList.length, irDeviceList.length);
|
|
470
475
|
break;
|
|
471
476
|
}
|
|
472
477
|
else {
|
|
@@ -2777,23 +2782,25 @@ export class SwitchBotHAPPlatform {
|
|
|
2777
2782
|
});
|
|
2778
2783
|
}
|
|
2779
2784
|
async retryRequest(device, deviceMaxRetries, deviceDelayBetweenRetries) {
|
|
2785
|
+
// Check API budget BEFORE attempting any retries - don't waste cycles on blocked requests
|
|
2786
|
+
if (!this.apiTracker?.trySpend('poll')) {
|
|
2787
|
+
// Don't log on every blocked request - the ApiRequestTracker handles periodic warnings
|
|
2788
|
+
return {
|
|
2789
|
+
response: {
|
|
2790
|
+
deviceId: '',
|
|
2791
|
+
deviceType: '',
|
|
2792
|
+
hubDeviceId: '',
|
|
2793
|
+
version: 0,
|
|
2794
|
+
deviceName: '',
|
|
2795
|
+
},
|
|
2796
|
+
statusCode: 429,
|
|
2797
|
+
};
|
|
2798
|
+
}
|
|
2780
2799
|
let retryCount = 0;
|
|
2781
2800
|
const maxRetries = deviceMaxRetries;
|
|
2782
2801
|
const delayBetweenRetries = deviceDelayBetweenRetries;
|
|
2783
2802
|
while (retryCount < maxRetries) {
|
|
2784
2803
|
try {
|
|
2785
|
-
if (!this.apiTracker?.trySpend('poll')) {
|
|
2786
|
-
return {
|
|
2787
|
-
response: {
|
|
2788
|
-
deviceId: '',
|
|
2789
|
-
deviceType: '',
|
|
2790
|
-
hubDeviceId: '',
|
|
2791
|
-
version: 0,
|
|
2792
|
-
deviceName: '',
|
|
2793
|
-
},
|
|
2794
|
-
statusCode: 429,
|
|
2795
|
-
};
|
|
2796
|
-
}
|
|
2797
2804
|
const { response, statusCode } = await this.switchBotAPI.getDeviceStatus(device.deviceId, this.config.credentials?.token, this.config.credentials?.secret);
|
|
2798
2805
|
this.debugLog(`response: ${JSON.stringify(response)}`);
|
|
2799
2806
|
return { response, statusCode };
|
|
@@ -2909,6 +2916,53 @@ export class SwitchBotHAPPlatform {
|
|
|
2909
2916
|
this.debugLog(`Plugin Version: ${version}`);
|
|
2910
2917
|
this.version = version;
|
|
2911
2918
|
}
|
|
2919
|
+
/**
|
|
2920
|
+
* Validate that the user's configuration won't exceed API limits
|
|
2921
|
+
* Warn if device count × polling frequency will hit daily limits
|
|
2922
|
+
*/
|
|
2923
|
+
validateApiUsageConfig(deviceCount, irDeviceCount) {
|
|
2924
|
+
try {
|
|
2925
|
+
const totalDevices = deviceCount + irDeviceCount;
|
|
2926
|
+
if (totalDevices === 0) {
|
|
2927
|
+
return;
|
|
2928
|
+
}
|
|
2929
|
+
const refreshRate = this.platformRefreshRate ?? 300; // seconds
|
|
2930
|
+
const dailyLimit = this.config.options?.dailyApiLimit ?? 10000;
|
|
2931
|
+
const reserveForCommands = this.config.options?.dailyApiReserveForCommands ?? 1000;
|
|
2932
|
+
// Calculate polls per day (86400 seconds in a day)
|
|
2933
|
+
const pollsPerDevicePerDay = Math.floor(86400 / refreshRate);
|
|
2934
|
+
const totalPollsPerDay = pollsPerDevicePerDay * totalDevices;
|
|
2935
|
+
// Add discovery calls (typically 1-2 per day)
|
|
2936
|
+
const estimatedDiscoveryCalls = 2;
|
|
2937
|
+
const totalEstimatedCalls = totalPollsPerDay + estimatedDiscoveryCalls;
|
|
2938
|
+
const usableLimit = dailyLimit - reserveForCommands;
|
|
2939
|
+
const percentOfLimit = Math.round((totalEstimatedCalls / usableLimit) * 100);
|
|
2940
|
+
this.debugLog(`[API Usage Diagnostic] ${totalDevices} devices × ${pollsPerDevicePerDay} polls/day = ${totalPollsPerDay} estimated daily polls`);
|
|
2941
|
+
this.debugLog(`[API Usage Diagnostic] With ${reserveForCommands} reserved for commands, usable limit is ${usableLimit}`);
|
|
2942
|
+
if (totalEstimatedCalls > dailyLimit) {
|
|
2943
|
+
this.errorLog(`⚠️ API LIMIT WARNING: Your configuration will exceed the daily API limit!`);
|
|
2944
|
+
this.errorLog(` Devices: ${totalDevices} | Refresh rate: ${refreshRate}s | Estimated daily polls: ${totalEstimatedCalls}`);
|
|
2945
|
+
this.errorLog(` Daily limit: ${dailyLimit} | You will use ${percentOfLimit}% of available budget`);
|
|
2946
|
+
this.errorLog(` SOLUTION: Increase refreshRate to ${Math.ceil((totalDevices * 86400) / usableLimit)} seconds or higher`);
|
|
2947
|
+
this.errorLog(` OR: Enable webhooks and set 'webhookOnlyOnReserve: true' to reduce polling`);
|
|
2948
|
+
}
|
|
2949
|
+
else if (totalEstimatedCalls > usableLimit) {
|
|
2950
|
+
this.warnLog(`⚠️ API USAGE WARNING: Configuration may exceed usable daily API budget`);
|
|
2951
|
+
this.warnLog(` Devices: ${totalDevices} | Refresh rate: ${refreshRate}s | Estimated daily polls: ${totalEstimatedCalls}`);
|
|
2952
|
+
this.warnLog(` Usable limit (after reserve): ${usableLimit} | You will use ${percentOfLimit}% of budget`);
|
|
2953
|
+
this.warnLog(` Polling may pause when approaching limit. Consider increasing refreshRate to ${Math.ceil((totalDevices * 86400) / usableLimit)}s`);
|
|
2954
|
+
}
|
|
2955
|
+
else if (percentOfLimit > 75) {
|
|
2956
|
+
this.infoLog(`[API Usage] Using ${percentOfLimit}% of daily budget (${totalEstimatedCalls}/${usableLimit} calls). Monitor usage if adding more devices.`);
|
|
2957
|
+
}
|
|
2958
|
+
else {
|
|
2959
|
+
this.debugLog(`[API Usage] Configuration looks good: ${percentOfLimit}% of daily budget (${totalEstimatedCalls}/${usableLimit} calls)`);
|
|
2960
|
+
}
|
|
2961
|
+
}
|
|
2962
|
+
catch (e) {
|
|
2963
|
+
this.debugErrorLog(`Failed to validate API usage config: ${e.message ?? e}`);
|
|
2964
|
+
}
|
|
2965
|
+
}
|
|
2912
2966
|
/**
|
|
2913
2967
|
* Validate and clean a string value for a Name Characteristic.
|
|
2914
2968
|
* @param displayName - The display name of the accessory.
|