From caca2a5480916942a6e0bc06e43d11a487137784 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 20 Aug 2025 13:25:49 +0000 Subject: [PATCH 1/3] Initial plan From 00d88202c66bf0228cf3a238cdd55a9d68f84c38 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 20 Aug 2025 13:30:04 +0000 Subject: [PATCH 2/3] Initial analysis and plan for Switchbot Curtain BLE issues on Raspberry Pi Co-authored-by: donavanbecker <9875439+donavanbecker@users.noreply.github.com> --- package-lock.json | 74 ----------------------------------------------- 1 file changed, 74 deletions(-) diff --git a/package-lock.json b/package-lock.json index 95e6897f..c6f72ec1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3318,72 +3318,6 @@ "url": "https://opencollective.com/vitest" } }, - "node_modules/@vue/compiler-core": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.13.tgz", - "integrity": "sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/parser": "^7.25.3", - "@vue/shared": "3.5.13", - "entities": "^4.5.0", - "estree-walker": "^2.0.2", - "source-map-js": "^1.2.0" - } - }, - "node_modules/@vue/compiler-dom": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.13.tgz", - "integrity": "sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@vue/compiler-core": "3.5.13", - "@vue/shared": "3.5.13" - } - }, - "node_modules/@vue/compiler-sfc": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.13.tgz", - "integrity": "sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/parser": "^7.25.3", - "@vue/compiler-core": "3.5.13", - "@vue/compiler-dom": "3.5.13", - "@vue/compiler-ssr": "3.5.13", - "@vue/shared": "3.5.13", - "estree-walker": "^2.0.2", - "magic-string": "^0.30.11", - "postcss": "^8.4.48", - "source-map-js": "^1.2.0" - } - }, - "node_modules/@vue/compiler-ssr": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.13.tgz", - "integrity": "sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@vue/compiler-dom": "3.5.13", - "@vue/shared": "3.5.13" - } - }, - "node_modules/@vue/shared": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.13.tgz", - "integrity": "sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/@yarnpkg/lockfile": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", @@ -5885,14 +5819,6 @@ "node": ">=4.0" } }, - "node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", From 9872dd6dfeea312ba0710804b822adf3742808c0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 20 Aug 2025 13:35:03 +0000 Subject: [PATCH 3/3] Fix Switchbot Curtain BLE connection issues and NaN position values Co-authored-by: donavanbecker <9875439+donavanbecker@users.noreply.github.com> --- src/device/blindtilt.ts | 6 +++++- src/device/curtain.ts | 38 ++++++++++++++++++++++++++++++-------- 2 files changed, 35 insertions(+), 9 deletions(-) diff --git a/src/device/blindtilt.ts b/src/device/blindtilt.ts index be5ba244..3662ee2a 100644 --- a/src/device/blindtilt.ts +++ b/src/device/blindtilt.ts @@ -594,7 +594,11 @@ export class BlindTilt extends deviceBase { return await this.retryBLE({ max: this.maxRetryBLE(), fn: async () => { - return await deviceList[0].runToPos(100 - Number(this.WindowCovering.TargetPosition), setPositionMode) + if (deviceList && Array.isArray(deviceList) && deviceList.length > 0) { + return await deviceList[0].runToPos(100 - Number(this.WindowCovering.TargetPosition), setPositionMode) + } else { + throw new Error('No device found') + } }, }) }) diff --git a/src/device/curtain.ts b/src/device/curtain.ts index 9fb2a4bd..11a18257 100644 --- a/src/device/curtain.ts +++ b/src/device/curtain.ts @@ -378,9 +378,11 @@ export class Curtain extends deviceBase { this.debugLog('BLEparseStatus') this.debugLog(`(position, battery) = BLE:(${this.serviceData.position}, ${this.serviceData.battery}), current:(${this.WindowCovering.CurrentPosition}, ${this.Battery.BatteryLevel})`) // CurrentPosition - if ('position' in this.serviceData) { - this.WindowCovering.CurrentPosition = 100 - this.serviceData.position + if ('position' in this.serviceData && this.serviceData.position !== undefined && this.serviceData.position !== null && !isNaN(Number(this.serviceData.position))) { + this.WindowCovering.CurrentPosition = 100 - Number(this.serviceData.position) await this.getCurrentPostion() + } else { + this.warnLog(`Invalid position data from BLE: ${this.serviceData.position}`) } // CurrentAmbientLightLevel if (!(this.device as curtainConfig).hide_lightsensor && this.LightSensor?.Service && 'lightLevel' in this.serviceData) { @@ -491,10 +493,10 @@ export class Curtain extends deviceBase { // Start to monitor advertisement packets const serviceData = await this.monitorAdvertisementPackets(switchBotBLE) as curtainServiceData | curtain3ServiceData // Update HomeKit - if ((serviceData.model === SwitchBotBLEModel.Curtain || SwitchBotBLEModel.Curtain3) - && (serviceData.modelName === SwitchBotBLEModelName.Curtain || SwitchBotBLEModelName.Curtain3)) { + if ((serviceData.model === SwitchBotBLEModel.Curtain || serviceData.model === SwitchBotBLEModel.Curtain3) + && (serviceData.modelName === SwitchBotBLEModelName.Curtain || serviceData.modelName === SwitchBotBLEModelName.Curtain3)) { this.serviceData = serviceData - if (serviceData !== undefined || serviceData !== null) { + if (serviceData !== undefined && serviceData !== null) { await this.BLEparseStatus() await this.updateHomeKitCharacteristics() } else { @@ -562,7 +564,7 @@ export class Curtain extends deviceBase { this.platform.bleEventHandler[this.device.bleMac] = async (context: curtainServiceData | curtain3ServiceData) => { try { this.serviceData = context - if (context !== undefined || context !== null) { + if (context !== undefined && context !== null) { this.debugLog(`received BLE: ${JSON.stringify(context)}`) await this.BLEparseStatus() await this.updateHomeKitCharacteristics() @@ -624,7 +626,11 @@ export class Curtain extends deviceBase { return await this.retryBLE({ max: this.maxRetryBLE(), fn: async () => { - return await deviceList[0].runToPos(100 - Number(this.WindowCovering.TargetPosition), adjustedMode) + if (deviceList && Array.isArray(deviceList) && deviceList.length > 0) { + return await deviceList[0].runToPos(100 - Number(this.WindowCovering.TargetPosition), adjustedMode) + } else { + throw new Error('No device found') + } }, }) }) @@ -783,6 +789,17 @@ export class Curtain extends deviceBase { async updateHomeKitCharacteristics(): Promise { await this.setMinMax() + + // Validate position values to prevent NaN + if (isNaN(Number(this.WindowCovering.CurrentPosition))) { + this.warnLog(`CurrentPosition is NaN, keeping previous value`) + this.WindowCovering.CurrentPosition = this.accessory.context.CurrentPosition ?? 100 + } + if (isNaN(Number(this.WindowCovering.TargetPosition))) { + this.warnLog(`TargetPosition is NaN, keeping previous value`) + this.WindowCovering.TargetPosition = this.accessory.context.TargetPosition ?? 100 + } + // CurrentPosition await this.updateCharacteristic(this.WindowCovering.Service, this.hap.Characteristic.CurrentPosition, this.WindowCovering.CurrentPosition, 'CurrentPosition') // PositionState @@ -805,17 +822,22 @@ export class Curtain extends deviceBase { } async BLEPushConnection() { + this.warnLog('BLE connection failed for push operation') if (this.platform.config.credentials?.token && this.device.connectionType === 'BLE/OpenAPI') { this.warnLog('Using OpenAPI Connection to Push Changes') await this.openAPIpushChanges() + } else { + this.errorLog('No fallback available for BLE push failure. Consider using BLE/OpenAPI connection type.') } } async BLERefreshConnection(switchbot: SwitchBotBLE): Promise { - this.errorLog(`wasn't able to establish BLE Connection, node-switchbot: ${switchbot}`) + this.warnLog(`BLE connection failed for refresh operation, node-switchbot: ${switchbot}`) if (this.platform.config.credentials?.token && this.device.connectionType === 'BLE/OpenAPI') { this.warnLog('Using OpenAPI Connection to Refresh Status') await this.openAPIRefreshStatus() + } else { + this.errorLog('No fallback available for BLE refresh failure. Consider using BLE/OpenAPI connection type.') } }