From 612b82122afb8a6bc431d3595667131d8cc2830b Mon Sep 17 00:00:00 2001 From: Donavan Becker Date: Sat, 19 Aug 2023 14:18:26 -0500 Subject: [PATCH] v2.8.0 (#798) ## [Version 2.8.0](https://github.com/OpenWonderLabs/homebridge-switchbot/releases/tag/v2.8.0) (2023-08-19) ## What's Changed - Add Hub 2 Light-Level Support. [#776](https://github.com/OpenWonderLabs/homebridge-switchbot/issues/776) - Enable Meter Battery Level for OpenAPI, Thanks [@mrlt8](https://github.com/mrlt8) [#782](https://github.com/OpenWonderLabs/homebridge-switchbot/pull/782) - Enable Meter Plus Battery Level for OpenAPI, Thanks [@mrlt8](https://github.com/mrlt8) [#787](https://github.com/OpenWonderLabs/homebridge-switchbot/pull/787) - Enable Battery Level and Version for OpenAPI for BlindTilt, Bot, Ceiling Lights, Color Bulb, Contact, Curtain, Hub, Humidifier, Indoor/Outdoor Sensor, Light Strip, Lock, Meter, Meter Plus, Motion , Plug, Plug Mini, & Robot Vacuum Cleaner - Housekeeping and updated dependencies. **Full Changelog**: https://github.com/OpenWonderLabs/homebridge-switchbot/compare/v2.7.1....v2.8.0 --- .prettierrc | 2 +- .vscode/settings.json | 2 +- CHANGELOG.md | 12 + README.md | 2 +- config.schema.json | 8 + package-lock.json | 504 ++++++++++++++++--------------- package.json | 22 +- src/device/blindtilt.ts | 196 +++++++----- src/device/bot.ts | 266 +++++++++------- src/device/ceilinglight.ts | 196 +++++++----- src/device/colorbulb.ts | 241 +++++++++------ src/device/contact.ts | 163 ++++++---- src/device/curtain.ts | 300 +++++++++--------- src/device/hub.ts | 269 ++++++++++++++--- src/device/humidifier.ts | 229 ++++++++------ src/device/iosensor.ts | 88 +++--- src/device/lightstrip.ts | 198 +++++++----- src/device/lock.ts | 139 +++++---- src/device/meter.ts | 186 +++++++----- src/device/meterplus.ts | 187 +++++++----- src/device/motion.ts | 156 ++++++---- src/device/plug.ts | 118 +++++--- src/device/robotvacuumcleaner.ts | 171 +++++++---- src/irdevice/airconditioner.ts | 328 ++++++++++---------- src/irdevice/airpurifier.ts | 101 ++++--- src/irdevice/camera.ts | 70 +++-- src/irdevice/fan.ts | 92 +++--- src/irdevice/light.ts | 84 +++--- src/irdevice/other.ts | 74 +++-- src/irdevice/tv.ts | 128 ++++---- src/irdevice/vacuumcleaner.ts | 70 +++-- src/irdevice/waterheater.ts | 82 +++-- src/platform.ts | 289 ++++++++++-------- src/settings.ts | 81 ++--- src/utils.ts | 2 +- 35 files changed, 3010 insertions(+), 2046 deletions(-) diff --git a/.prettierrc b/.prettierrc index d06c8e13..39f15e5a 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,6 +1,6 @@ { "semi": true, - "singleQuote": false, + "singleQuote": true, "bracketSameLine": true, "printWidth": 150, "tabWidth": 2, diff --git a/.vscode/settings.json b/.vscode/settings.json index 8dd1b6ee..cfce933b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,7 +9,7 @@ "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[typescript]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" + "editor.defaultFormatter": "vscode.typescript-language-features" }, "typescript.format.enable": true, "editor.rulers": [ diff --git a/CHANGELOG.md b/CHANGELOG.md index fc21e8f9..b603188f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,18 @@ All notable changes to this project will be documented in this file. This project uses [Semantic Versioning](https://semver.org/) +## [Version 2.8.0](https://github.com/OpenWonderLabs/homebridge-switchbot/releases/tag/v2.8.0) (2023-08-19) + +## What's Changed + +- Add Hub 2 Light-Level Support. [#776](https://github.com/OpenWonderLabs/homebridge-switchbot/issues/776) +- Enable Meter Battery Level for OpenAPI, Thanks [@mrlt8](https://github.com/mrlt8) [#782](https://github.com/OpenWonderLabs/homebridge-switchbot/pull/782) +- Enable Meter Plus Battery Level for OpenAPI, Thanks [@mrlt8](https://github.com/mrlt8) [#787](https://github.com/OpenWonderLabs/homebridge-switchbot/pull/787) +- Enable Battery Level and Version for OpenAPI for BlindTilt, Bot, Ceiling Lights, Color Bulb, Contact, Curtain, Hub, Humidifier, Indoor/Outdoor Sensor, Light Strip, Lock, Meter, Meter Plus, Motion , Plug, Plug Mini, & Robot Vacuum Cleaner +- Housekeeping and updated dependencies. + +**Full Changelog**: https://github.com/OpenWonderLabs/homebridge-switchbot/compare/v2.7.1....v2.8.0 + ## [Version 2.7.1](https://github.com/OpenWonderLabs/homebridge-switchbot/releases/tag/v2.7.1) (2023-07-29) ## What's Changed diff --git a/README.md b/README.md index 424adbd7..8fbc9fae 100644 --- a/README.md +++ b/README.md @@ -97,7 +97,7 @@ - Must supply `deviceId` & `deviceName` to Device Config - Check `Enable Bluetooth Low Energy (BLE) Connection` on Device Config - [SwitchBot Blind Tilt](https://us.switch-bot.com/pages/switchbot-blind-tilt) -- Supports OpenAPI Connection Only + - Supports OpenAPI Connection Only - If using OpenAPI: - [SwitchBot Hub Mini](https://www.switch-bot.com/products/switchbot-hub-mini) or [SwitchBot Hub 2](https://us.switch-bot.com/pages/switchbot-hub-2) Required - Enable Cloud Services for Device on SwitchBot App diff --git a/config.schema.json b/config.schema.json index 6f90808e..83c884a8 100644 --- a/config.schema.json +++ b/config.schema.json @@ -224,6 +224,13 @@ "condition": { "functionBody": "return (model.options && model.options.devices && !model.options.devices[arrayIndices].hide_device && (model.options.devices[arrayIndices].configDeviceType === 'Hub 2') && model.options.devices[arrayIndices].deviceId);" } + }, + "hide_lightsensor": { + "title": "Hide Hub 2's Light Sensor", + "type": "boolean", + "condition": { + "functionBody": "return (model.options && model.options.devices && !model.options.devices[arrayIndices].hide_device && (model.options.devices[arrayIndices].configDeviceType === 'Hub 2') && model.options.devices[arrayIndices].deviceId);" + } } } }, @@ -1224,6 +1231,7 @@ "options.devices[].connectionType", "options.devices[].hidHub.hide_temperature", "options.devices[].hidHub.hide_humidity", + "options.devices[].hidHub.hide_lightsensor", "options.devices[].scanDuration", "options.devices[].disableCaching", "options.devices[].maxRetry", diff --git a/package-lock.json b/package-lock.json index 3a206623..1ec92e06 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@switchbot/homebridge-switchbot", - "version": "2.7.1", + "version": "2.8.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@switchbot/homebridge-switchbot", - "version": "2.7.1", + "version": "2.8.0", "funding": [ { "type": "Paypal", @@ -19,26 +19,26 @@ ], "license": "ISC", "dependencies": { - "@homebridge/plugin-ui-utils": "^0.0.19", + "@homebridge/plugin-ui-utils": "^0.1.0", "async-mqtt": "^2.6.3", "crypto-js": "^4.1.1", "fakegato-history": "^0.6.4", - "homebridge-lib": "^6.4.0", + "homebridge-lib": "^6.4.1", "rxjs": "^7.8.1", - "undici": "^5.22.1" + "undici": "^5.23.0" }, "devDependencies": { "@types/crypto-js": "^4.1.1", - "@types/node": "^20.4.5", - "@typescript-eslint/eslint-plugin": "^6.2.0", - "@typescript-eslint/parser": "^6.2.0", - "eslint": "^8.46.0", - "eslint-config-prettier": "8.9.0", + "@types/node": "^20.5.1", + "@typescript-eslint/eslint-plugin": "^6.4.0", + "@typescript-eslint/parser": "^6.4.0", + "eslint": "^8.47.0", + "eslint-config-prettier": "9.0.0", "eslint-plugin-prettier": "5.0.0", "homebridge": "^1.6.1", "nodemon": "^3.0.1", - "npm-check-updates": "^16.10.17", - "prettier": "3.0.0", + "npm-check-updates": "^16.12.2", + "prettier": "3.0.2", "rimraf": "^5.0.1", "ts-node": "^10.9.1", "typescript": "^5.1.6" @@ -155,9 +155,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.1.tgz", - "integrity": "sha512-9t7ZA7NGGK8ckelF0PQCfcxIUzs1Md5rrO6U/c+FIQNanea5UZC0wqKXH4vHBccmu4ZJgZ2idtPeW7+Q2npOEA==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", + "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", "dev": true, "dependencies": { "ajv": "^6.12.4", @@ -178,9 +178,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.46.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.46.0.tgz", - "integrity": "sha512-a8TLtmPi8xzPkCbp/OGFUo5yhRkHM2Ko9kOWP4znJr0WAhWyThaw3PnwX4vOTWOAMsV2uRt32PPDcEz63esSaA==", + "version": "8.47.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.47.0.tgz", + "integrity": "sha512-P6omY1zv5MItm93kLM8s2vr1HICJH8v0dvddDhysbIuZ+vcjOHg5Zbkf1mTkcmi2JA9oBG2anOkRnW8WJTS8Og==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -229,9 +229,9 @@ "dev": true }, "node_modules/@homebridge/plugin-ui-utils": { - "version": "0.0.19", - "resolved": "https://registry.npmjs.org/@homebridge/plugin-ui-utils/-/plugin-ui-utils-0.0.19.tgz", - "integrity": "sha512-axFX7lN2Yd7bz/6SlD7dzq5sY/N9+XYuLHPukuiyHQRDtNMRL1uDqJhOx6RVaN2tYDHB75h7YxRQWP7U44Mgzg==" + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@homebridge/plugin-ui-utils/-/plugin-ui-utils-0.1.0.tgz", + "integrity": "sha512-dFpXhSy/+moDzOf8yRZxeuqZOAHTA0bZDElMXnO98cequ+7kPmX+wgREYVrYcHZYtJK744nD1n7qT2gy/E/yFg==" }, "node_modules/@homebridge/put": { "version": "0.0.8", @@ -652,9 +652,9 @@ } }, "node_modules/@sigstore/bundle": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-1.0.0.tgz", - "integrity": "sha512-yLvrWDOh6uMOUlFCTJIZEnwOT9Xte7NPXUqVexEKGSF5XtBAuSg5du0kn3dRR0p47a4ah10Y0mNt8+uyeQXrBQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-1.1.0.tgz", + "integrity": "sha512-PFutXEy0SmQxYI4texPw3dd2KewuNqv7OuK1ZFtY2fM754yhvG2KdgwIhRnoEE2uHdtdGNQ8s0lb94dW9sELog==", "dev": true, "dependencies": { "@sigstore/protobuf-specs": "^0.2.0" @@ -664,14 +664,28 @@ } }, "node_modules/@sigstore/protobuf-specs": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.2.0.tgz", - "integrity": "sha512-8ZhZKAVfXjIspDWwm3D3Kvj0ddbJ0HqDZ/pOs5cx88HpT8mVsotFrg7H1UMnXOuDHz6Zykwxn4mxG3QLuN+RUg==", + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.2.1.tgz", + "integrity": "sha512-XTWVxnWJu+c1oCshMLwnKvz8ZQJJDVOlciMfgpJBQbThVjKTCG8dwyhgLngBD2KN0ap9F/gOV8rFDEx8uh7R2A==", "dev": true, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/@sigstore/sign": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-1.0.0.tgz", + "integrity": "sha512-INxFVNQteLtcfGmcoldzV6Je0sbbfh9I16DM4yJPw3j5+TFP8X6uIiA18mvpEa9yyeycAKgPmOA3X9hVdVTPUA==", + "dev": true, + "dependencies": { + "@sigstore/bundle": "^1.1.0", + "@sigstore/protobuf-specs": "^0.2.0", + "make-fetch-happen": "^11.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/@sigstore/tuf": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-1.0.3.tgz", @@ -807,9 +821,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.4.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.5.tgz", - "integrity": "sha512-rt40Nk13II9JwQBdeYqmbn2Q6IVTA5uPhvSO+JVqdXw/6/4glI6oR9ezty/A9Hg5u7JH4OmYmuQ+XvjKm0Datg==", + "version": "20.5.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.1.tgz", + "integrity": "sha512-4tT2UrL5LBqDwoed9wZ6N3umC4Yhz3W3FloMmiiG4JwmUJWpie0c7lcnUNd4gtMKuDEO4wRVS8B6Xa0uMRsMKg==", "dev": true }, "node_modules/@types/semver": { @@ -819,21 +833,20 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.2.0.tgz", - "integrity": "sha512-rClGrMuyS/3j0ETa1Ui7s6GkLhfZGKZL3ZrChLeAiACBE/tRc1wq8SNZESUuluxhLj9FkUefRs2l6bCIArWBiQ==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.4.0.tgz", + "integrity": "sha512-62o2Hmc7Gs3p8SLfbXcipjWAa6qk2wZGChXG2JbBtYpwSRmti/9KHLqfbLs9uDigOexG+3PaQ9G2g3201FWLKg==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.2.0", - "@typescript-eslint/type-utils": "6.2.0", - "@typescript-eslint/utils": "6.2.0", - "@typescript-eslint/visitor-keys": "6.2.0", + "@typescript-eslint/scope-manager": "6.4.0", + "@typescript-eslint/type-utils": "6.4.0", + "@typescript-eslint/utils": "6.4.0", + "@typescript-eslint/visitor-keys": "6.4.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", "natural-compare": "^1.4.0", - "natural-compare-lite": "^1.4.0", "semver": "^7.5.4", "ts-api-utils": "^1.0.1" }, @@ -855,15 +868,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.2.0.tgz", - "integrity": "sha512-igVYOqtiK/UsvKAmmloQAruAdUHihsOCvplJpplPZ+3h4aDkC/UKZZNKgB6h93ayuYLuEymU3h8nF1xMRbh37g==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.4.0.tgz", + "integrity": "sha512-I1Ah1irl033uxjxO9Xql7+biL3YD7w9IU8zF+xlzD/YxY6a4b7DYA08PXUUCbm2sEljwJF6ERFy2kTGAGcNilg==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.2.0", - "@typescript-eslint/types": "6.2.0", - "@typescript-eslint/typescript-estree": "6.2.0", - "@typescript-eslint/visitor-keys": "6.2.0", + "@typescript-eslint/scope-manager": "6.4.0", + "@typescript-eslint/types": "6.4.0", + "@typescript-eslint/typescript-estree": "6.4.0", + "@typescript-eslint/visitor-keys": "6.4.0", "debug": "^4.3.4" }, "engines": { @@ -883,13 +896,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.2.0.tgz", - "integrity": "sha512-1ZMNVgm5nnHURU8ZSJ3snsHzpFeNK84rdZjluEVBGNu7jDymfqceB3kdIZ6A4xCfEFFhRIB6rF8q/JIqJd2R0Q==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.4.0.tgz", + "integrity": "sha512-TUS7vaKkPWDVvl7GDNHFQMsMruD+zhkd3SdVW0d7b+7Zo+bd/hXJQ8nsiUZMi1jloWo6c9qt3B7Sqo+flC1nig==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.2.0", - "@typescript-eslint/visitor-keys": "6.2.0" + "@typescript-eslint/types": "6.4.0", + "@typescript-eslint/visitor-keys": "6.4.0" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -900,13 +913,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.2.0.tgz", - "integrity": "sha512-DnGZuNU2JN3AYwddYIqrVkYW0uUQdv0AY+kz2M25euVNlujcN2u+rJgfJsBFlUEzBB6OQkUqSZPyuTLf2bP5mw==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.4.0.tgz", + "integrity": "sha512-TvqrUFFyGY0cX3WgDHcdl2/mMCWCDv/0thTtx/ODMY1QhEiyFtv/OlLaNIiYLwRpAxAtOLOY9SUf1H3Q3dlwAg==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.2.0", - "@typescript-eslint/utils": "6.2.0", + "@typescript-eslint/typescript-estree": "6.4.0", + "@typescript-eslint/utils": "6.4.0", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -927,9 +940,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.2.0.tgz", - "integrity": "sha512-1nRRaDlp/XYJQLvkQJG5F3uBTno5SHPT7XVcJ5n1/k2WfNI28nJsvLakxwZRNY5spuatEKO7d5nZWsQpkqXwBA==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.4.0.tgz", + "integrity": "sha512-+FV9kVFrS7w78YtzkIsNSoYsnOtrYVnKWSTVXoL1761CsCRv5wpDOINgsXpxD67YCLZtVQekDDyaxfjVWUJmmg==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -940,13 +953,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.2.0.tgz", - "integrity": "sha512-Mts6+3HQMSM+LZCglsc2yMIny37IhUgp1Qe8yJUYVyO6rHP7/vN0vajKu3JvHCBIy8TSiKddJ/Zwu80jhnGj1w==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.4.0.tgz", + "integrity": "sha512-iDPJArf/K2sxvjOR6skeUCNgHR/tCQXBsa+ee1/clRKr3olZjZ/dSkXPZjG6YkPtnW6p5D1egeEPMCW6Gn4yLA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.2.0", - "@typescript-eslint/visitor-keys": "6.2.0", + "@typescript-eslint/types": "6.4.0", + "@typescript-eslint/visitor-keys": "6.4.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -967,17 +980,17 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.2.0.tgz", - "integrity": "sha512-RCFrC1lXiX1qEZN8LmLrxYRhOkElEsPKTVSNout8DMzf8PeWoQG7Rxz2SadpJa3VSh5oYKGwt7j7X/VRg+Y3OQ==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.4.0.tgz", + "integrity": "sha512-BvvwryBQpECPGo8PwF/y/q+yacg8Hn/2XS+DqL/oRsOPK+RPt29h5Ui5dqOKHDlbXrAeHUTnyG3wZA0KTDxRZw==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.2.0", - "@typescript-eslint/types": "6.2.0", - "@typescript-eslint/typescript-estree": "6.2.0", + "@typescript-eslint/scope-manager": "6.4.0", + "@typescript-eslint/types": "6.4.0", + "@typescript-eslint/typescript-estree": "6.4.0", "semver": "^7.5.4" }, "engines": { @@ -992,12 +1005,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.2.0.tgz", - "integrity": "sha512-QbaYUQVKKo9bgCzpjz45llCfwakyoxHetIy8CAvYCtd16Zu1KrpzNHofwF8kGkpPOxZB2o6kz+0nqH8ZkIzuoQ==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.4.0.tgz", + "integrity": "sha512-yJSfyT+uJm+JRDWYRYdCm2i+pmvXJSMtPR9Cq5/XQs4QIgNoLcoRtDdzsLbLsFM/c6um6ohQkg/MLxWvoIndJA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.2.0", + "@typescript-eslint/types": "6.4.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -1048,6 +1061,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "devOptional": true, "dependencies": { "debug": "4" }, @@ -1056,13 +1070,11 @@ } }, "node_modules/agentkeepalive": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.3.0.tgz", - "integrity": "sha512-7Epl1Blf4Sy37j4v9f9FjICCh4+KAQOyXgHEwlyBiAQLbhKdq/i2QQU3amQalS/wPhdPzDXPL5DMR5bkn+YeWg==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", + "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", "dev": true, "dependencies": { - "debug": "^4.1.0", - "depd": "^2.0.0", "humanize-ms": "^1.2.1" }, "engines": { @@ -1200,14 +1212,6 @@ "node": ">=8" } }, - "node_modules/arrify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", - "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", - "engines": { - "node": ">=8" - } - }, "node_modules/async-mqtt": { "version": "2.6.3", "resolved": "https://registry.npmjs.org/async-mqtt/-/async-mqtt-2.6.3.tgz", @@ -1497,16 +1501,16 @@ } }, "node_modules/cacache": { - "version": "17.1.3", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-17.1.3.tgz", - "integrity": "sha512-jAdjGxmPxZh0IipMdR7fK/4sDSrHMLUV0+GvVUsjwyGNKHsh79kW/otg+GkbXwl6Uzvy9wsvHOX4nUoWldeZMg==", + "version": "17.1.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-17.1.4.tgz", + "integrity": "sha512-/aJwG2l3ZMJ1xNAnqbMpA40of9dj/pIH3QfiuQSqjfPJF747VR0J/bHn+/KdNnHKc6XQcWt/AfRSBft82W1d2A==", "dev": true, "dependencies": { "@npmcli/fs": "^3.1.0", "fs-minipass": "^3.0.0", "glob": "^10.2.2", "lru-cache": "^7.7.1", - "minipass": "^5.0.0", + "minipass": "^7.0.3", "minipass-collect": "^1.0.2", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", @@ -1574,6 +1578,15 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/cacache/node_modules/minipass": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.3.tgz", + "integrity": "sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/cacheable-lookup": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", @@ -2065,15 +2078,6 @@ "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", "devOptional": true }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/detect-libc": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", @@ -2255,15 +2259,15 @@ } }, "node_modules/eslint": { - "version": "8.46.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.46.0.tgz", - "integrity": "sha512-cIO74PvbW0qU8e0mIvk5IV3ToWdCq5FYG6gWPHHkx6gNdjlbAYvtfHmlCMXxjcoVaIdwy/IAt3+mDkZkfvb2Dg==", + "version": "8.47.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.47.0.tgz", + "integrity": "sha512-spUQWrdPt+pRVP1TTJLmfRNJJHHZryFmptzcafwSvHsceV81djHOdnEeDmkdotZyLNjDhrOasNK8nikkoG1O8Q==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.1", - "@eslint/js": "^8.46.0", + "@eslint/eslintrc": "^2.1.2", + "@eslint/js": "^8.47.0", "@humanwhocodes/config-array": "^0.11.10", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -2274,7 +2278,7 @@ "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.2", + "eslint-visitor-keys": "^3.4.3", "espree": "^9.6.1", "esquery": "^1.4.2", "esutils": "^2.0.2", @@ -2309,9 +2313,9 @@ } }, "node_modules/eslint-config-prettier": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.9.0.tgz", - "integrity": "sha512-+sbni7NfVXnOpnRadUA8S28AUlsZt9GjgFvABIRL9Hkn8KqNzOp+7Lw4QWtrwn20KzU3wqu1QoOj2m+7rKRqkA==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.0.0.tgz", + "integrity": "sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw==", "dev": true, "bin": { "eslint-config-prettier": "bin/cli.js" @@ -2366,9 +2370,9 @@ } }, "node_modules/eslint-visitor-keys": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.2.tgz", - "integrity": "sha512-8drBzUEyZ2llkpCA67iYrgEssKDUu68V8ChqqOfFupIaG/LCVPUT+CoGJpT77zJprs4T/W7p07LP7zAIMuweVw==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -2590,11 +2594,6 @@ "node": ">=10.17.0" } }, - "node_modules/fast-text-encoding": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.6.tgz", - "integrity": "sha512-VhXlQgj9ioXCqGstD37E/HBeqEGV/qOD/kmbVG8h5xKBYvM1L3lR1Zn4555cQ8GkYbJa8aJSipLPndE1k6zK2w==" - }, "node_modules/fastq": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", @@ -2753,17 +2752,26 @@ } }, "node_modules/fs-minipass": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.2.tgz", - "integrity": "sha512-2GAfyfoaCDRrM6jaOS3UsBts8yJ55VioXdWcOL7dK9zdAuKT71+WBA4ifnNYqVjYv+4SsPxjK0JT4yIIn4cA/g==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", + "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", "dev": true, "dependencies": { - "minipass": "^5.0.0" + "minipass": "^7.0.3" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/fs-minipass/node_modules/minipass": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.3.tgz", + "integrity": "sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -2826,29 +2834,52 @@ } }, "node_modules/gaxios": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-5.1.3.tgz", - "integrity": "sha512-95hVgBRgEIRQQQHIbnxBXeHbW4TqFk4ZDJW7wmVtvYar72FdhRIo1UGOLS2eRAKCPEdPBWu+M7+A33D9CdX9rA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.1.0.tgz", + "integrity": "sha512-EIHuesZxNyIkUGcTQKQPMICyOpDD/bi+LJIJx+NLsSGmnS7N+xCLRX5bi4e9yAu9AlSZdVq+qlyWWVuTh/483w==", "dependencies": { "extend": "^3.0.2", - "https-proxy-agent": "^5.0.0", + "https-proxy-agent": "^7.0.1", "is-stream": "^2.0.0", "node-fetch": "^2.6.9" }, "engines": { - "node": ">=12" + "node": ">=14" + } + }, + "node_modules/gaxios/node_modules/agent-base": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/gaxios/node_modules/https-proxy-agent": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.1.tgz", + "integrity": "sha512-Eun8zV0kcYS1g19r78osiQLEFIRspRUDd9tIfBCTBPBeMieF/EsJNL8VI3xOIdYRDEkjQnqOYPsZ2DsWsVsFwQ==", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" } }, "node_modules/gcp-metadata": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-5.3.0.tgz", - "integrity": "sha512-FNTkdNEnBdlqF2oatizolQqNANMrcqJt6AAYt99B3y1aLLC8Hc5IOBb+ZnnzllodEEf6xMBp6wRcBbc16fa65w==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.0.0.tgz", + "integrity": "sha512-Ozxyi23/1Ar51wjUT2RDklK+3HxqDr8TLBNK8rBBFQ7T85iIGnXnVusauj06QyqCXRFZig8LZC+TUddWbndlpQ==", "dependencies": { - "gaxios": "^5.0.0", + "gaxios": "^6.0.0", "json-bigint": "^1.0.0" }, "engines": { - "node": ">=12" + "node": ">=14" } }, "node_modules/get-intrinsic": { @@ -2945,9 +2976,9 @@ } }, "node_modules/globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "version": "13.21.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.21.0.tgz", + "integrity": "sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -2980,64 +3011,48 @@ } }, "node_modules/google-auth-library": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-8.9.0.tgz", - "integrity": "sha512-f7aQCJODJFmYWN6PeNKzgvy9LI2tYmXnzpNDHEjG5sDNPgGb2FXQyTBnXeSH+PAtpKESFD+LmHw3Ox3mN7e1Fg==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.0.0.tgz", + "integrity": "sha512-IQGjgQoVUAfOk6khqTVMLvWx26R+yPw9uLyb1MNyMQpdKiKt0Fd9sp4NWoINjyGHR8S3iw12hMTYK7O8J07c6Q==", "dependencies": { - "arrify": "^2.0.0", "base64-js": "^1.3.0", "ecdsa-sig-formatter": "^1.0.11", - "fast-text-encoding": "^1.0.0", - "gaxios": "^5.0.0", - "gcp-metadata": "^5.3.0", - "gtoken": "^6.1.0", + "gaxios": "^6.0.0", + "gcp-metadata": "^6.0.0", + "gtoken": "^7.0.0", "jws": "^4.0.0", "lru-cache": "^6.0.0" }, "engines": { - "node": ">=12" - } - }, - "node_modules/google-p12-pem": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-4.0.1.tgz", - "integrity": "sha512-WPkN4yGtz05WZ5EhtlxNDWPhC4JIic6G8ePitwUWy4l+XPVYec+a0j0Ts47PDtW59y3RwAhUd9/h9ZZ63px6RQ==", - "dependencies": { - "node-forge": "^1.3.1" - }, - "bin": { - "gp12-pem": "build/src/bin/gp12-pem.js" - }, - "engines": { - "node": ">=12.0.0" + "node": ">=14" } }, "node_modules/googleapis": { - "version": "123.0.0", - "resolved": "https://registry.npmjs.org/googleapis/-/googleapis-123.0.0.tgz", - "integrity": "sha512-btZanWj70+xlPWB2/r1GbfBu6qrD650ihFW9fXga+LKdkRUqXo0w2ohNPTKZiDgerJS0sh8c7bsQq9mmWFU8MA==", + "version": "126.0.0", + "resolved": "https://registry.npmjs.org/googleapis/-/googleapis-126.0.0.tgz", + "integrity": "sha512-BeCwYJfthEWUgY0ka7msSxyMuRwrwJTqL9yMlnuCxyy1JlRZwaI5ZVVp4ofwiGiNP9UuuR3Yk9CJKWQLg4Tq1A==", "dependencies": { - "google-auth-library": "^8.0.2", - "googleapis-common": "^6.0.0" + "google-auth-library": "^9.0.0", + "googleapis-common": "^7.0.0" }, "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" } }, "node_modules/googleapis-common": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/googleapis-common/-/googleapis-common-6.0.4.tgz", - "integrity": "sha512-m4ErxGE8unR1z0VajT6AYk3s6a9gIMM6EkDZfkPnES8joeOlEtFEJeF8IyZkb0tjPXkktUfYrE4b3Li1DNyOwA==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/googleapis-common/-/googleapis-common-7.0.0.tgz", + "integrity": "sha512-58iSybJPQZ8XZNMpjrklICefuOuyJ0lMxfKmBqmaC0/xGT4SiOs4BE60LAOOGtBURy1n8fHa2X2YUNFEWWbXyQ==", "dependencies": { "extend": "^3.0.2", - "gaxios": "^5.0.1", - "google-auth-library": "^8.0.2", + "gaxios": "^6.0.3", + "google-auth-library": "^9.0.0", "qs": "^6.7.0", "url-template": "^2.0.8", "uuid": "^9.0.0" }, "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" } }, "node_modules/gopd": { @@ -3089,16 +3104,15 @@ "dev": true }, "node_modules/gtoken": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-6.1.2.tgz", - "integrity": "sha512-4ccGpzz7YAr7lxrT2neugmXQ3hP9ho2gcaityLVkiUecAiwiy60Ii8gRbZeOsXV19fYaRjgBSshs8kXw+NKCPQ==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.0.1.tgz", + "integrity": "sha512-KcFVtoP1CVFtQu0aSk3AyAt2og66PFhZAlkUOuWKwzMLoulHXG5W5wE5xAnHb+yl3/wEFoqGW7/cDGMU8igDZQ==", "dependencies": { - "gaxios": "^5.0.1", - "google-p12-pem": "^4.0.0", + "gaxios": "^6.0.0", "jws": "^4.0.0" }, "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" } }, "node_modules/hap-nodejs": { @@ -3215,9 +3229,9 @@ } }, "node_modules/hb-lib-tools": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/hb-lib-tools/-/hb-lib-tools-1.0.11.tgz", - "integrity": "sha512-V9CjaDeD4ffb90OVc+kj8Hivic43IhHvShg6Go8G/lDnV+iZksKu4hpUiyjPbx6ZWQjX55ezGegjWe8hsJIHQA==", + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/hb-lib-tools/-/hb-lib-tools-1.0.12.tgz", + "integrity": "sha512-8JyHs8+sgDJWxo9YUnl9K6BMKmL6wU9jtcdjkFepIPYL0CRL1yRuBonmBiLZpY7hOgwM17W+wLsuPdZ+ZRcnrA==", "dependencies": { "bonjour-hap": "^3.6.4", "chalk": "^4.1.2", @@ -3230,7 +3244,7 @@ "upnp": "cli/upnp.js" }, "engines": { - "node": "18.17.0||^18||^16" + "node": "18.17.1||^18||^16" } }, "node_modules/help-me": { @@ -3273,12 +3287,12 @@ } }, "node_modules/homebridge-lib": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/homebridge-lib/-/homebridge-lib-6.4.0.tgz", - "integrity": "sha512-ZwfsxgtXLNlPLX/KuIVMW2T3pjkA/Yr/pCVZSdZDG9ApH5LmCBBK4sUniE5ZFAo9Rq8uAUbvjn7DTSqdGlQ/3g==", + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/homebridge-lib/-/homebridge-lib-6.4.1.tgz", + "integrity": "sha512-SDBzPTpYCUaMA4AcE6PPVbMCYJ6NUcB1v4iCrxwXrbLGbiobN1O5qraP4W9dQ8ETBg6gXHADW0pcT9tILxSfnQ==", "dependencies": { "@homebridge/plugin-ui-utils": "~0.0.19", - "hb-lib-tools": "~1.0.11" + "hb-lib-tools": "~1.0.12" }, "bin": { "hap": "cli/hap.js", @@ -3288,9 +3302,14 @@ }, "engines": { "homebridge": "^1.6.1", - "node": "18.17.0||^18||^16" + "node": "18.17.1||^18||^16" } }, + "node_modules/homebridge-lib/node_modules/@homebridge/plugin-ui-utils": { + "version": "0.0.19", + "resolved": "https://registry.npmjs.org/@homebridge/plugin-ui-utils/-/plugin-ui-utils-0.0.19.tgz", + "integrity": "sha512-axFX7lN2Yd7bz/6SlD7dzq5sY/N9+XYuLHPukuiyHQRDtNMRL1uDqJhOx6RVaN2tYDHB75h7YxRQWP7U44Mgzg==" + }, "node_modules/hosted-git-info": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-5.2.1.tgz", @@ -3349,6 +3368,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "devOptional": true, "dependencies": { "agent-base": "6", "debug": "4" @@ -3631,9 +3651,9 @@ } }, "node_modules/is-core-module": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz", - "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==", + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", + "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", "dev": true, "dependencies": { "has": "^1.0.3" @@ -3963,9 +3983,9 @@ "dev": true }, "node_modules/jackspeak": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.2.2.tgz", - "integrity": "sha512-mgNtVv4vUuaKA97yxUHoA3+FkuhtxkjdXEWOyB/N76fjy0FjezEt34oy3epBtvCvS+7DyKwqCFWx/oJLV5+kCg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.0.tgz", + "integrity": "sha512-uKmsITSsF4rUWQHzqaRUuyAir3fZfW3f202Ee34lz/gZCi970CPZwyQXLGNgWJvvZbvFyzeyGq0+4fcG/mBKZg==", "dev": true, "dependencies": { "@isaacs/cliui": "^8.0.2" @@ -4389,12 +4409,12 @@ } }, "node_modules/minipass-fetch": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.3.tgz", - "integrity": "sha512-n5ITsTkDqYkYJZjcRWzZt9qnZKCT7nKCosJhHoj7S7zD+BP4jVbWs+odsniw5TA3E0sLomhTKOKjF86wf11PuQ==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", + "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", "dev": true, "dependencies": { - "minipass": "^5.0.0", + "minipass": "^7.0.3", "minipass-sized": "^1.0.3", "minizlib": "^2.1.2" }, @@ -4405,6 +4425,15 @@ "encoding": "^0.1.13" } }, + "node_modules/minipass-fetch/node_modules/minipass": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.3.tgz", + "integrity": "sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/minipass-flush": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", @@ -4618,12 +4647,6 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, - "node_modules/natural-compare-lite": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", - "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", - "dev": true - }, "node_modules/negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -4640,9 +4663,9 @@ "optional": true }, "node_modules/node-fetch": { - "version": "2.6.12", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz", - "integrity": "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==", + "version": "2.6.13", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.13.tgz", + "integrity": "sha512-StxNAxh15zr77QvvkmveSQ8uCQ4+v5FkvNTj0OESmiHu+VRi/gXArXtkWMElOsOUNLtUEvI4yS+rdtOHZTwlQA==", "dependencies": { "whatwg-url": "^5.0.0" }, @@ -4658,14 +4681,6 @@ } } }, - "node_modules/node-forge": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", - "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", - "engines": { - "node": ">= 6.13.0" - } - }, "node_modules/node-gyp": { "version": "9.4.0", "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.4.0.tgz", @@ -4969,9 +4984,9 @@ } }, "node_modules/npm-check-updates": { - "version": "16.10.17", - "resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-16.10.17.tgz", - "integrity": "sha512-ZoIbWYJhlgMDoByq1WC6Ys3E76IvNCxgS54tPUFbK5J/nqf/BCJt6xiMPAEa7G1HuyAruG+orUF9uTsTGUZl8g==", + "version": "16.12.2", + "resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-16.12.2.tgz", + "integrity": "sha512-N0jeEcak3/+PS1O5JzwJ2+fvmQVv+084O4iRnDtcMBLcr9S7vPOBxwWgsEuNfj3shKFZRYOuh4NHB9nMenCHXA==", "dev": true, "dependencies": { "chalk": "^5.3.0", @@ -4988,6 +5003,7 @@ "json-parse-helpfulerror": "^1.0.3", "jsonlines": "^0.1.1", "lodash": "^4.17.21", + "make-fetch-happen": "^11.1.1", "minimatch": "^9.0.3", "p-map": "^4.0.0", "pacote": "15.2.0", @@ -5071,9 +5087,9 @@ } }, "node_modules/npm-install-checks": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.1.1.tgz", - "integrity": "sha512-dH3GmQL4vsPtld59cOn8uY0iOqRmqKvV+DLGwNXV/Q7MDgD2QfOADWd/mFXcIE5LVhYYGjA3baz6W9JneqnuCw==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.2.0.tgz", + "integrity": "sha512-744wat5wAAHsxa4590mWO0tJ8PKxR8ORZsH9wGpQc3nWTzozMAgBN/XyqYw7mg3yqLM8dLwEnwSfKMmXAjF69g==", "dev": true, "dependencies": { "semver": "^7.1.1" @@ -5506,9 +5522,9 @@ } }, "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.0.tgz", - "integrity": "sha512-svTf/fzsKHffP42sujkO/Rjs37BCIsQVRCeNYIm9WN8rgT7ffoUnRtZCqU+6BqcSBdv8gwJeTz8knJpgACeQMw==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.1.tgz", + "integrity": "sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==", "dev": true, "engines": { "node": "14 || >=16.14" @@ -5560,9 +5576,9 @@ } }, "node_modules/prettier": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.0.tgz", - "integrity": "sha512-zBf5eHpwHOGPC47h0zrPyNn+eAEIdEzfywMoYn2XPi0P44Zp0tSq64rq0xAREh4auw2cJZHo9QUob+NqCQky4g==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.2.tgz", + "integrity": "sha512-o2YR9qtniXvwEZlOKbveKfDQVyqxbEIWn48Z8m3ZJjBjcCmUy3xZGIv+7AkaeuaTr6yPXJjwv07ZWlsWbEy1rQ==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" @@ -6312,13 +6328,14 @@ "devOptional": true }, "node_modules/sigstore": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-1.8.0.tgz", - "integrity": "sha512-ogU8qtQ3VFBawRJ8wjsBEX/vIFeHuGs1fm4jZtjWQwjo8pfAt7T/rh+udlAN4+QUe0IzA8qRSc/YZ7dHP6kh+w==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-1.9.0.tgz", + "integrity": "sha512-0Zjz0oe37d08VeOtBIuB6cRriqXse2e8w+7yIy2XSXjshRKxbc2KkhXjL229jXSxEm7UbcjS76wcJDGQddVI9A==", "dev": true, "dependencies": { - "@sigstore/bundle": "^1.0.0", + "@sigstore/bundle": "^1.1.0", "@sigstore/protobuf-specs": "^0.2.0", + "@sigstore/sign": "^1.0.0", "@sigstore/tuf": "^1.0.3", "make-fetch-happen": "^11.0.1" }, @@ -6484,17 +6501,26 @@ } }, "node_modules/ssri": { - "version": "10.0.4", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.4.tgz", - "integrity": "sha512-12+IR2CB2C28MMAw0Ncqwj5QbTcs0nGIhgJzYWzDkb21vWmfNI83KS4f3Ci6GI98WreIfG7o9UXp3C0qbpA8nQ==", + "version": "10.0.5", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.5.tgz", + "integrity": "sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A==", "dev": true, "dependencies": { - "minipass": "^5.0.0" + "minipass": "^7.0.3" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/ssri/node_modules/minipass": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.3.tgz", + "integrity": "sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/stop-iteration-iterator": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", @@ -6769,9 +6795,9 @@ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, "node_modules/ts-api-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.1.tgz", - "integrity": "sha512-lC/RGlPmwdrIBFTX59wwNzqh7aR2otPNPR/5brHZm/XKFYKsfqxihXUe9pU3JI+3vGkl+vyCoNNnPhJn3aLK1A==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.2.tgz", + "integrity": "sha512-Cbu4nIqnEdd+THNEsBdkolnOXhg0I8XteoHaEKgvsxpsbWda4IsUut2c187HxywQCvveojow0Dgw/amxtSKVkQ==", "dev": true, "engines": { "node": ">=16.13.0" @@ -6824,9 +6850,9 @@ } }, "node_modules/tslib": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz", - "integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==" + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, "node_modules/tuf-js": { "version": "1.1.7", @@ -6906,9 +6932,9 @@ "dev": true }, "node_modules/undici": { - "version": "5.22.1", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.22.1.tgz", - "integrity": "sha512-Ji2IJhFXZY0x/0tVBXeQwgPlLWw13GVzpsWPQ3rV50IFMMof2I55PZZxtm4P6iNq+L5znYN9nSTAq0ZyE6lSJw==", + "version": "5.23.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.23.0.tgz", + "integrity": "sha512-1D7w+fvRsqlQ9GscLBwcAJinqcZGHUKjbOmXdlE/v8BvEGXjeWAax+341q44EuTcHXXnfyKNbKRq4Lg7OzhMmg==", "dependencies": { "busboy": "^1.6.0" }, diff --git a/package.json b/package.json index 493641bb..3fea4ff7 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "displayName": "Homebridge SwitchBot", "name": "@switchbot/homebridge-switchbot", - "version": "2.7.1", + "version": "2.8.0", "description": "The [Homebridge](https://homebridge.io) SwitchBot plugin allows you to access your [SwitchBot](https://www.switch-bot.com) device(s) from HomeKit.", "author": "SwitchBot (https://github.com/SwitchBot)", "license": "ISC", @@ -55,13 +55,13 @@ "ir" ], "dependencies": { - "@homebridge/plugin-ui-utils": "^0.0.19", + "@homebridge/plugin-ui-utils": "^0.1.0", "async-mqtt": "^2.6.3", "crypto-js": "^4.1.1", "fakegato-history": "^0.6.4", - "homebridge-lib": "^6.4.0", + "homebridge-lib": "^6.4.1", "rxjs": "^7.8.1", - "undici": "^5.22.1" + "undici": "^5.23.0" }, "optionalDependencies": { "@abandonware/bluetooth-hci-socket": "^0.5.3-10", @@ -70,16 +70,16 @@ }, "devDependencies": { "@types/crypto-js": "^4.1.1", - "@types/node": "^20.4.5", - "@typescript-eslint/eslint-plugin": "^6.2.0", - "@typescript-eslint/parser": "^6.2.0", - "eslint": "^8.46.0", - "eslint-config-prettier": "8.9.0", + "@types/node": "^20.5.1", + "@typescript-eslint/eslint-plugin": "^6.4.0", + "@typescript-eslint/parser": "^6.4.0", + "eslint": "^8.47.0", + "eslint-config-prettier": "9.0.0", "eslint-plugin-prettier": "5.0.0", "homebridge": "^1.6.1", "nodemon": "^3.0.1", - "npm-check-updates": "^16.10.17", - "prettier": "3.0.0", + "npm-check-updates": "^16.12.2", + "prettier": "3.0.2", "rimraf": "^5.0.1", "ts-node": "^10.9.1", "typescript": "^5.1.6" diff --git a/src/device/blindtilt.ts b/src/device/blindtilt.ts index fdc54e11..ac99821c 100644 --- a/src/device/blindtilt.ts +++ b/src/device/blindtilt.ts @@ -30,11 +30,11 @@ export class BlindTilt { CurrentAmbientLightLevel?: CharacteristicValue; BatteryLevel?: CharacteristicValue; StatusLowBattery?: CharacteristicValue; - CurrentHorizontalTiltAngle!: CharacteristicValue; TargetHorizontalTiltAngle!: CharacteristicValue; // OpenAPI Others + Version: deviceStatus['version']; deviceStatus!: any; //deviceStatusResponse; slidePosition: deviceStatus['slidePosition']; direction: deviceStatus['direction']; @@ -80,17 +80,21 @@ export class BlindTilt { doBlindTiltUpdate!: Subject; // Connection - private readonly BLE = (this.device.connectionType === 'BLE' || this.device.connectionType === 'BLE/OpenAPI'); - private readonly OpenAPI = (this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'BLE/OpenAPI'); - - constructor(private readonly platform: SwitchBotPlatform, private accessory: PlatformAccessory, public device: device & devicesConfig) { + private readonly BLE = this.device.connectionType === 'BLE' || this.device.connectionType === 'BLE/OpenAPI'; + private readonly OpenAPI = this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'BLE/OpenAPI'; + + constructor( + private readonly platform: SwitchBotPlatform, + private accessory: PlatformAccessory, + public device: device & devicesConfig, + ) { // default placeholders this.logs(device); this.refreshRate(device); this.scan(device); - this.config(device); this.setupMqtt(device); this.context(); + this.config(device); this.mappingMode = (device.blindTilt?.mode as BlindTiltMappingMode) ?? BlindTiltMappingMode.OnlyUp; this.debugLog(`Mapping mode: ${this.mappingMode}`); @@ -236,8 +240,10 @@ export class BlindTilt { await this.pushChanges(); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType} Connection,` - + ` Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType} Connection,` + + ` Error Message: ${JSON.stringify(e.message)}`, + ); } this.blindTiltUpdateInProgress = false; }); @@ -255,8 +261,9 @@ export class BlindTilt { await this.openAPIparseStatus(); } else { await this.offlineOff(); - this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` - + ` ${this.device.connectionType}, parseStatus will not happen.`); + this.debugWarnLog( + `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + ` ${this.device.connectionType}, parseStatus will not happen.`, + ); } } @@ -351,8 +358,8 @@ export class BlindTilt { this.debugLog(); } this.debugLog( - `${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.lightLevel},` - + ` CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`, + `${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.lightLevel},` + + ` CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`, ); } // Battery @@ -362,8 +369,9 @@ export class BlindTilt { } else { this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL; } - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel},` - + ` StatusLowBattery: ${this.StatusLowBattery}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel},` + ` StatusLowBattery: ${this.StatusLowBattery}`, + ); } async openAPIparseStatus(): Promise { @@ -388,7 +396,7 @@ export class BlindTilt { if (this.setNewTarget && this.moving) { await this.setMinMax(); - if (this.TargetPosition > this.CurrentPosition || (homekitTiltAngle && (this.TargetHorizontalTiltAngle !== this.CurrentHorizontalTiltAngle))) { + if (this.TargetPosition > this.CurrentPosition || (homekitTiltAngle && this.TargetHorizontalTiltAngle !== this.CurrentHorizontalTiltAngle)) { this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Closing, CurrentPosition: ${this.CurrentPosition} `); this.PositionState = this.platform.Characteristic.PositionState.INCREASING; this.windowCoveringService.getCharacteristic(this.platform.Characteristic.PositionState).updateValue(this.PositionState); @@ -399,15 +407,17 @@ export class BlindTilt { this.windowCoveringService.getCharacteristic(this.platform.Characteristic.PositionState).updateValue(this.PositionState); this.debugLog(`${this.device.deviceType}: ${this.CurrentPosition} DECREASING PositionState: ${this.PositionState}`); } else { - this.debugLog(`${this.device.deviceType}: ${this.CurrentPosition} Standby because reached position,` + - ` CurrentPosition: ${this.CurrentPosition}`); + this.debugLog( + `${this.device.deviceType}: ${this.CurrentPosition} Standby because reached position,` + ` CurrentPosition: ${this.CurrentPosition}`, + ); this.PositionState = this.platform.Characteristic.PositionState.STOPPED; this.windowCoveringService.getCharacteristic(this.platform.Characteristic.PositionState).updateValue(this.PositionState); this.debugLog(`${this.device.deviceType}: ${this.CurrentPosition} STOPPED PositionState: ${this.PositionState}`); } } else { - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Standby because device not moving,` + - ` CurrentPosition: ${this.CurrentPosition}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} Standby because device not moving,` + ` CurrentPosition: ${this.CurrentPosition}`, + ); this.TargetPosition = this.CurrentPosition; if (homekitTiltAngle) { this.TargetHorizontalTiltAngle = this.CurrentHorizontalTiltAngle; @@ -445,8 +455,10 @@ export class BlindTilt { await this.openAPIRefreshStatus(); } else { await this.offlineOff(); - this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` - + ` ${this.device.connectionType}, refreshStatus will not happen.`); + this.debugWarnLog( + `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + + ` ${this.device.connectionType}, refreshStatus will not happen.`, + ); } } @@ -471,8 +483,10 @@ export class BlindTilt { // Set an event hander switchbot.onadvertisement = async (ad: any) => { this.address = ad.address; - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Config BLE Address: ${this.device.bleMac},` - + ` BLE Address Found: ${this.address}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} Config BLE Address: ${this.device.bleMac},` + + ` BLE Address Found: ${this.address}`, + ); this.serviceData = ad.serviceData; this.calibration = ad.serviceData.calibration; this.battery = ad.serviceData.battery; @@ -483,7 +497,8 @@ export class BlindTilt { this.debugLog( `${this.device.deviceType}: ${this.accessory.displayName} calibration: ${ad.serviceData.calibration}, ` + `position: ${ad.serviceData.position}, lightLevel: ${ad.serviceData.lightLevel}, battery: ${ad.serviceData.battery}, ` + - `inMotion: ${ad.serviceData.inMotion}`); + `inMotion: ${ad.serviceData.inMotion}`, + ); if (this.serviceData) { this.connected = true; @@ -503,8 +518,10 @@ export class BlindTilt { }) .catch(async (e: any) => { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLERefreshStatus with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed BLERefreshStatus with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + ); await this.BLERefreshConnection(switchbot); }); } else { @@ -518,14 +535,11 @@ export class BlindTilt { const { body, statusCode, headers } = await request(`${Devices}/${this.device.deviceId}/status`, { headers: this.platform.generateHeaders(), }); - const deviceStatus = await body.json(); + const deviceStatus: any = await body.json(); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`); this.statusCode(statusCode); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`); - this.debugLog( - `${this.device.deviceType}: ${this.accessory.displayName - } refreshStatus: ${JSON.stringify(deviceStatus)}`, - ); + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} refreshStatus: ${JSON.stringify(deviceStatus)}`); this.slidePosition = deviceStatus.body.slidePosition; this.direction = deviceStatus.body.direction; this.moving = deviceStatus.body.moving; @@ -534,8 +548,10 @@ export class BlindTilt { this.updateHomeKitCharacteristics(); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + ); } } @@ -548,8 +564,9 @@ export class BlindTilt { await this.openAPIpushChanges(); } else { await this.offlineOff(); - this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` - + ` ${this.device.connectionType}, pushChanges will not happen.`); + this.debugWarnLog( + `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + ` ${this.device.connectionType}, pushChanges will not happen.`, + ); } // Refresh the status from the API interval(15000) @@ -593,8 +610,10 @@ export class BlindTilt { }) .catch(async (e: any) => { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushChanges with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushChanges with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + ); await this.BLEPushConnection(); }); } else { @@ -602,7 +621,8 @@ export class BlindTilt { await this.BLEPushConnection(); } } else { - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No BLEpushChanges, CurrentPosition & TargetPosition Are the Same.` + + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} No BLEpushChanges, CurrentPosition & TargetPosition Are the Same.` + ` CurrentPosition: ${this.CurrentPosition}, TargetPosition ${this.TargetPosition}`, ); } @@ -630,29 +650,28 @@ export class BlindTilt { async openAPIpushChanges(): Promise { this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIpushChanges`); - const hasDifferentAndRelevantHorizontalTiltAngle = ( - this.mappingMode === BlindTiltMappingMode.UseTiltForDirection - && this.TargetHorizontalTiltAngle !== this.CurrentHorizontalTiltAngle); - if ((this.TargetPosition !== this.CurrentPosition) || hasDifferentAndRelevantHorizontalTiltAngle || this.device.disableCaching) { + const hasDifferentAndRelevantHorizontalTiltAngle = + this.mappingMode === BlindTiltMappingMode.UseTiltForDirection && this.TargetHorizontalTiltAngle !== this.CurrentHorizontalTiltAngle; + if (this.TargetPosition !== this.CurrentPosition || hasDifferentAndRelevantHorizontalTiltAngle || this.device.disableCaching) { const [direction, position] = this.mapHomekitValuesToDeviceValues(Number(this.TargetPosition), Number(this.TargetHorizontalTiltAngle)); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Pushing ${this.TargetPosition} (device = ${direction};${position})`); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Mode: ${this.Mode}`); let bodyChange = ''; if (position === 100) { bodyChange = JSON.stringify({ - 'command': 'fullyOpen', - 'commandType': 'command', + command: 'fullyOpen', + commandType: 'command', }); } else if (position === 0) { bodyChange = JSON.stringify({ - 'command': direction === 'up' ? 'closeUp' : 'closeDown', - 'commandType': 'command', + command: direction === 'up' ? 'closeUp' : 'closeDown', + commandType: 'command', }); } else { bodyChange = JSON.stringify({ - 'command': 'setPosition', - 'parameter': `${direction};${position}`, - 'commandType': 'command', + command: 'setPosition', + parameter: `${direction};${position}`, + commandType: 'command', }); } this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${bodyChange},`); @@ -662,20 +681,22 @@ export class BlindTilt { method: 'POST', headers: this.platform.generateHeaders(), }); - const deviceStatus = await body.json(); + const deviceStatus: any = await body.json(); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`); this.statusCode(statusCode); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIpushChanges with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed openAPIpushChanges with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, ); } } else { - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No OpenAPI Changes, CurrentPosition & TargetPosition Are the Same.` - + ` CurrentPosition: ${this.CurrentPosition}, TargetPosition ${this.TargetPosition}` - + ` CurrentHorizontalTiltAngle: ${this.CurrentHorizontalTiltAngle}, TargetPosition ${this.TargetHorizontalTiltAngle}`, + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} No OpenAPI Changes, CurrentPosition & TargetPosition Are the Same.` + + ` CurrentPosition: ${this.CurrentPosition}, TargetPosition ${this.TargetPosition}` + + ` CurrentHorizontalTiltAngle: ${this.CurrentHorizontalTiltAngle}, TargetPosition ${this.TargetHorizontalTiltAngle}`, ); } } @@ -699,7 +720,6 @@ export class BlindTilt { this.startUpdatingBlindTiltIfNeeded(); } - /** * Handle requests to set the value of the "Target Position" characteristic */ @@ -720,21 +740,24 @@ export class BlindTilt { async startUpdatingBlindTiltIfNeeded(): Promise { await this.setMinMax(); this.debugLog('setMinMax'); - if (this.TargetPosition > this.CurrentPosition || (this.TargetHorizontalTiltAngle !== this.CurrentHorizontalTiltAngle)) { + if (this.TargetPosition > this.CurrentPosition || this.TargetHorizontalTiltAngle !== this.CurrentHorizontalTiltAngle) { this.PositionState = this.platform.Characteristic.PositionState.INCREASING; this.setNewTarget = true; - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} value: ${this.CurrentPosition},` + - ` CurrentPosition: ${this.CurrentPosition}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} value: ${this.CurrentPosition},` + ` CurrentPosition: ${this.CurrentPosition}`, + ); } else if (this.TargetPosition < this.CurrentPosition) { this.PositionState = this.platform.Characteristic.PositionState.DECREASING; this.setNewTarget = true; - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} value: ${this.CurrentPosition},` + - ` CurrentPosition: ${this.CurrentPosition}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} value: ${this.CurrentPosition},` + ` CurrentPosition: ${this.CurrentPosition}`, + ); } else { this.PositionState = this.platform.Characteristic.PositionState.STOPPED; this.setNewTarget = false; - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} value: ${this.CurrentPosition},` + - ` CurrentPosition: ${this.CurrentPosition}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} value: ${this.CurrentPosition},` + ` CurrentPosition: ${this.CurrentPosition}`, + ); } this.windowCoveringService.setCharacteristic(this.platform.Characteristic.PositionState, this.PositionState); this.windowCoveringService.getCharacteristic(this.platform.Characteristic.PositionState).updateValue(this.PositionState); @@ -765,8 +788,10 @@ export class BlindTilt { this.mqttPublish('CurrentHorizontalTiltAngle', this.CurrentHorizontalTiltAngle); } this.accessory.context.CurrentHorizontalTiltAngle = this.CurrentHorizontalTiltAngle; - this.windowCoveringService.updateCharacteristic(this.platform.Characteristic.CurrentHorizontalTiltAngle, - Number(this.CurrentHorizontalTiltAngle)); + this.windowCoveringService.updateCharacteristic( + this.platform.Characteristic.CurrentHorizontalTiltAngle, + Number(this.CurrentHorizontalTiltAngle), + ); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic CurrentHorizontalTiltAngle: ${this.CurrentHorizontalTiltAngle}`); } @@ -811,8 +836,10 @@ export class BlindTilt { } this.accessory.context.CurrentAmbientLightLevel = this.CurrentAmbientLightLevel; this.lightSensorService?.updateCharacteristic(this.platform.Characteristic.CurrentAmbientLightLevel, this.CurrentAmbientLightLevel); - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}` - + ` updateCharacteristic CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName}` + + ` updateCharacteristic CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`, + ); } } if (this.BLE) { @@ -983,8 +1010,10 @@ export class BlindTilt { if (this.updateRate > device.scanDuration) { this.scanDuration = this.updateRate; if (this.BLE) { - this.warnLog(`${this.device.deviceType}: ` - + `${this.accessory.displayName} scanDuration is less than updateRate, overriding scanDuration with updateRate`); + this.warnLog( + `${this.device.deviceType}: ` + + `${this.accessory.displayName} scanDuration is less than updateRate, overriding scanDuration with updateRate`, + ); } } else { this.scanDuration = this.accessory.context.scanDuration = device.scanDuration; @@ -1020,8 +1049,10 @@ export class BlindTilt { this.offlineOff(); break; case 171: - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` - + `Hub: ${this.device.hubDeviceId}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` + + `Hub: ${this.device.hubDeviceId}`, + ); this.offlineOff(); break; case 190: @@ -1037,8 +1068,10 @@ export class BlindTilt { this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Request successful, statusCode: ${statusCode}`); break; default: - this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode: ` - + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`); + this.infoLog( + `${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode: ` + + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`, + ); } } @@ -1065,14 +1098,17 @@ export class BlindTilt { FirmwareRevision(accessory: PlatformAccessory, device: device & devicesConfig): CharacteristicValue { let FirmwareRevision: string; - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}` - + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName}` + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`, + ); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} device.firmware: ${device.firmware}`); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`); - if (accessory.context.FirmwareRevision) { - FirmwareRevision = accessory.context.FirmwareRevision; - } else if (device.firmware) { + if (device.firmware) { FirmwareRevision = device.firmware; + } else if (device.version) { + FirmwareRevision = JSON.stringify(device.version); + } else if (accessory.context.FirmwareRevision) { + FirmwareRevision = accessory.context.FirmwareRevision; } else { FirmwareRevision = this.platform.version; } @@ -1272,7 +1308,7 @@ export class BlindTilt { } if (Object.entries(config).length !== 0) { - this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); + this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); } } @@ -1342,4 +1378,4 @@ export class BlindTilt { enablingDeviceLogging(): boolean { return this.deviceLogging.includes('debug') || this.deviceLogging === 'standard'; } -} \ No newline at end of file +} diff --git a/src/device/bot.ts b/src/device/bot.ts index 76ae37b0..56fc7015 100644 --- a/src/device/bot.ts +++ b/src/device/bot.ts @@ -32,6 +32,8 @@ export class Bot { StatusLowBattery!: CharacteristicValue; // OpenAPI Others + Version: deviceStatus['version']; + Battery: deviceStatus['battery']; power: deviceStatus['power']; deviceStatus!: any; //deviceStatusResponse; @@ -60,19 +62,23 @@ export class Bot { doBotUpdate!: Subject; // Connection - private readonly BLE = (this.device.connectionType === 'BLE' || this.device.connectionType === 'BLE/OpenAPI'); - private readonly OpenAPI = (this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'BLE/OpenAPI'); - - constructor(private readonly platform: SwitchBotPlatform, private accessory: PlatformAccessory, public device: device & devicesConfig) { + private readonly BLE = this.device.connectionType === 'BLE' || this.device.connectionType === 'BLE/OpenAPI'; + private readonly OpenAPI = this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'BLE/OpenAPI'; + + constructor( + private readonly platform: SwitchBotPlatform, + private accessory: PlatformAccessory, + public device: device & devicesConfig, + ) { // default placeholders this.logs(device); this.scan(device); this.refreshRate(device); this.PressOrSwitch(device); this.allowPushChanges(device); - this.config(device); this.context(); this.DoublePress(device); + this.config(device); this.multiPressCount = 0; @@ -109,8 +115,7 @@ export class Bot { // Add switchService (this.switchService = accessory.getService(this.platform.Service.Switch) || accessory.addService(this.platform.Service.Switch)), `${accessory.displayName} Switch`; - this.infoLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Switch`); - + this.debugWarnLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Switch`); this.switchService.setCharacteristic(this.platform.Characteristic.Name, accessory.displayName); if (!this.switchService.testCharacteristic(this.platform.Characteristic.ConfiguredName)) { @@ -132,7 +137,7 @@ export class Bot { (this.garageDoorService = accessory.getService(this.platform.Service.GarageDoorOpener) || accessory.addService(this.platform.Service.GarageDoorOpener)), `${accessory.displayName} Garage Door Opener`; - this.infoLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Garage Door Opener`); + this.debugWarnLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Garage Door Opener`); this.garageDoorService.setCharacteristic(this.platform.Characteristic.Name, accessory.displayName); if (!this.garageDoorService.testCharacteristic(this.platform.Characteristic.ConfiguredName)) { @@ -154,7 +159,7 @@ export class Bot { // Add switchService (this.doorService = accessory.getService(this.platform.Service.Door) || accessory.addService(this.platform.Service.Door)), `${accessory.displayName} Door`; - this.infoLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Door`); + this.debugWarnLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Door`); this.doorService.setCharacteristic(this.platform.Characteristic.Name, accessory.displayName); if (!this.doorService.testCharacteristic(this.platform.Characteristic.ConfiguredName)) { @@ -184,7 +189,7 @@ export class Bot { // Add switchService (this.windowService = accessory.getService(this.platform.Service.Window) || accessory.addService(this.platform.Service.Window)), `${accessory.displayName} Window`; - this.infoLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Window`); + this.debugWarnLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Window`); this.windowService.setCharacteristic(this.platform.Characteristic.Name, accessory.displayName); if (!this.windowService.testCharacteristic(this.platform.Characteristic.ConfiguredName)) { @@ -215,7 +220,7 @@ export class Bot { (this.windowCoveringService = accessory.getService(this.platform.Service.WindowCovering) || accessory.addService(this.platform.Service.WindowCovering)), `${accessory.displayName} Window Covering`; - this.infoLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Window Covering`); + this.debugWarnLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Window Covering`); this.windowCoveringService.setCharacteristic(this.platform.Characteristic.Name, accessory.displayName); if (!this.windowCoveringService.testCharacteristic(this.platform.Characteristic.ConfiguredName)) { @@ -245,7 +250,7 @@ export class Bot { // Add switchService (this.lockService = accessory.getService(this.platform.Service.LockMechanism) || accessory.addService(this.platform.Service.LockMechanism)), `${accessory.displayName} Lock`; - this.infoLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Lock`); + this.debugWarnLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Lock`); this.lockService.setCharacteristic(this.platform.Characteristic.Name, accessory.displayName); if (!this.lockService.testCharacteristic(this.platform.Characteristic.ConfiguredName)) { @@ -266,7 +271,7 @@ export class Bot { // Add switchService (this.faucetService = accessory.getService(this.platform.Service.Faucet) || accessory.addService(this.platform.Service.Faucet)), `${accessory.displayName} Faucet`; - this.infoLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Faucet`); + this.debugWarnLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Faucet`); this.faucetService.setCharacteristic(this.platform.Characteristic.Name, accessory.displayName); if (!this.faucetService.testCharacteristic(this.platform.Characteristic.ConfiguredName)) { @@ -287,7 +292,7 @@ export class Bot { // Add switchService (this.fanService = accessory.getService(this.platform.Service.Fan) || accessory.addService(this.platform.Service.Fan)), `${accessory.displayName} Fan`; - this.infoLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Fan`); + this.debugWarnLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Fan`); this.fanService.setCharacteristic(this.platform.Characteristic.Name, accessory.displayName); if (!this.fanService.testCharacteristic(this.platform.Characteristic.ConfiguredName)) { @@ -310,7 +315,7 @@ export class Bot { accessory.getService(this.platform.Service.StatefulProgrammableSwitch) || accessory.addService(this.platform.Service.StatefulProgrammableSwitch)), `${accessory.displayName} Stateful Programmable Switch`; - this.infoLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Stateful Programmable Switch`); + this.debugWarnLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Stateful Programmable Switch`); this.statefulProgrammableSwitchService.setCharacteristic(this.platform.Characteristic.Name, accessory.displayName); if (!this.statefulProgrammableSwitchService.testCharacteristic(this.platform.Characteristic.ConfiguredName)) { @@ -333,7 +338,7 @@ export class Bot { // Add outletService (this.outletService = accessory.getService(this.platform.Service.Outlet) || accessory.addService(this.platform.Service.Outlet)), `${accessory.displayName} Outlet`; - this.infoLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Outlet`); + this.debugWarnLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Outlet`); this.outletService.setCharacteristic(this.platform.Characteristic.Name, accessory.displayName); if (!this.outletService.testCharacteristic(this.platform.Characteristic.ConfiguredName)) { @@ -343,19 +348,16 @@ export class Bot { } // Battery Service - if (!this.BLE) { - this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Removing Battery Service`); - this.batteryService = this.accessory.getService(this.platform.Service.Battery); - accessory.removeService(this.batteryService!); - } else if (this.BLE && !this.batteryService) { + if (!this.batteryService) { this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Add Battery Service`); (this.batteryService = this.accessory.getService(this.platform.Service.Battery) || this.accessory.addService(this.platform.Service.Battery)), `${accessory.displayName} Battery`; this.batteryService.setCharacteristic(this.platform.Characteristic.Name, `${accessory.displayName} Battery`); if (!this.batteryService.testCharacteristic(this.platform.Characteristic.ConfiguredName)) { - this.batteryService.addCharacteristic(this.platform.Characteristic.ConfiguredName, accessory.displayName); + this.batteryService.addCharacteristic(this.platform.Characteristic.ConfiguredName, `${accessory.displayName} Battery`); } + this.batteryService.setCharacteristic(this.platform.Characteristic.ChargingState, this.platform.Characteristic.ChargingState.NOT_CHARGEABLE); } else { this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Battery Service Not Added`); } @@ -392,8 +394,10 @@ export class Bot { } } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType} Connection,` - + ` Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType} Connection,` + + ` Error Message: ${JSON.stringify(e.message)}`, + ); } this.botUpdateInProgress = false; }); @@ -411,8 +415,9 @@ export class Bot { await this.openAPIparseStatus(); } else { await this.offlineOff(); - this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` - + ` ${this.device.connectionType}, parseStatus will not happen.`); + this.debugWarnLog( + `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + ` ${this.device.connectionType}, parseStatus will not happen.`, + ); } } @@ -455,6 +460,18 @@ export class Bot { } } this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`); + + // Battery + this.BatteryLevel = Number(this.Battery); + if (this.BatteryLevel < 10) { + this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW; + } else { + this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL; + } + if (Number.isNaN(this.BatteryLevel)) { + this.BatteryLevel = 100; + } + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}`); } /** @@ -469,8 +486,10 @@ export class Bot { await this.openAPIRefreshStatus(); } else { await this.offlineOff(); - this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` - + ` ${this.device.connectionType}, refreshStatus will not happen.`); + this.debugWarnLog( + `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + + ` ${this.device.connectionType}, refreshStatus will not happen.`, + ); } } @@ -495,15 +514,19 @@ export class Bot { // Set an event hander switchbot.onadvertisement = async (ad: ad) => { this.address = ad.address; - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Config BLE Address: ${this.device.bleMac},` - + ` BLE Address Found: ${this.address}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} Config BLE Address: ${this.device.bleMac},` + + ` BLE Address Found: ${this.address}`, + ); this.serviceData = ad.serviceData; this.mode = ad.serviceData.mode; this.state = ad.serviceData.state; this.battery = ad.serviceData.battery; this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} serviceData: ${JSON.stringify(ad.serviceData)}`); - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}, model: ${ad.serviceData.model}, modelName: ` - + `${ad.serviceData.modelName}, mode: ${ad.serviceData.mode}, state: ${ad.serviceData.state}, battery: ${ad.serviceData.battery}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName}, model: ${ad.serviceData.model}, modelName: ` + + `${ad.serviceData.modelName}, mode: ${ad.serviceData.mode}, state: ${ad.serviceData.state}, battery: ${ad.serviceData.battery}`, + ); if (this.serviceData) { this.connected = true; @@ -523,8 +546,10 @@ export class Bot { }) .catch(async (e: any) => { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLERefreshStatus with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed BLERefreshStatus with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + ); await this.BLERefreshConnection(switchbot); }); } else { @@ -538,21 +563,26 @@ export class Bot { const { body, statusCode, headers } = await request(`${Devices}/${this.device.deviceId}/status`, { headers: this.platform.generateHeaders(), }); - const deviceStatus = await body.json(); - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`); - this.statusCode(statusCode); - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`); - this.debugLog( - `${this.device.deviceType}: ${this.accessory.displayName - } refreshStatus: ${JSON.stringify(deviceStatus)}`, - ); - this.power = deviceStatus.body.power; - this.openAPIparseStatus(); - this.updateHomeKitCharacteristics(); + if (statusCode === 200) { + const deviceStatus: any = await body.json(); + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`); + this.statusCode(statusCode); + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`); + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} refreshStatus: ${JSON.stringify(deviceStatus)}`); + this.power = deviceStatus.body.power; + this.Battery = deviceStatus.body.battery; + this.Version = deviceStatus.body.version; + this.openAPIparseStatus(); + this.updateHomeKitCharacteristics(); + } else { + this.statusCode(statusCode); + } } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + ); } } @@ -572,8 +602,9 @@ export class Bot { await this.openAPIpushChanges(); } else { await this.offlineOff(); - this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` - + ` ${this.device.connectionType}, pushChanges will not happen.`); + this.debugWarnLog( + `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + ` ${this.device.connectionType}, pushChanges will not happen.`, + ); } // Refresh the status from the API interval(15000) @@ -618,8 +649,10 @@ export class Bot { }) .catch(async (e: any) => { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushChanges with ${this.device.connectionType}` - + ` Connection & botMode: ${this.botMode}, Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushChanges with ${this.device.connectionType}` + + ` Connection & botMode: ${this.botMode}, Error Message: ${JSON.stringify(e.message)}`, + ); await this.BLEPushConnection(); }); } else if (this.botMode === 'switch') { @@ -645,16 +678,19 @@ export class Bot { }) .catch(async (e: any) => { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushChanges with ${this.device.connectionType}` - + ` Connection & botMode: ${this.botMode}, Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushChanges with ${this.device.connectionType}` + + ` Connection & botMode: ${this.botMode}, Error Message: ${JSON.stringify(e.message)}`, + ); await this.BLEPushConnection(); }); } else { this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Bot Mode: ${this.botMode}`); } } else { - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No BLEpushChanges.` + `On: ${this.On}, ` - + `OnCached: ${this.accessory.context.On}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} No BLEpushChanges.` + `On: ${this.On}, ` + `OnCached: ${this.accessory.context.On}`, + ); } } @@ -664,7 +700,7 @@ export class Bot { this.debugLog(`${this.device.deviceType}: ${this.multiPressCount} request(s) queued.`); this.On = true; } - if ((this.On !== this.accessory.context.On || this.allowPush) || this.multiPressCount > 0) { + if (this.On !== this.accessory.context.On || this.allowPush || this.multiPressCount > 0) { let command = ''; if (this.botMode === 'switch' && this.On) { command = 'turnOn'; @@ -682,9 +718,9 @@ export class Bot { throw new Error(`${this.device.deviceType}: ${this.accessory.displayName} Device Paramters not set for this Bot.`); } const bodyChange = JSON.stringify({ - 'command': `${command}`, - 'parameter': 'default', - 'commandType': 'command', + command: `${command}`, + parameter: 'default', + commandType: 'command', }); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${bodyChange},`); try { @@ -693,7 +729,7 @@ export class Bot { method: 'POST', headers: this.platform.generateHeaders(), }); - const deviceStatus = await body.json(); + const deviceStatus: any = await body.json(); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`); this.statusCode(statusCode); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`); @@ -707,13 +743,17 @@ export class Bot { } } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIpushChanges with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed openAPIpushChanges with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, ); } } else { - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No openAPIpushChanges.` + `On: ${this.On}, ` - + `OnCached: ${this.accessory.context.On}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} No openAPIpushChanges.` + + `On: ${this.On}, ` + + `OnCached: ${this.accessory.context.On}`, + ); } } @@ -767,7 +807,6 @@ export class Bot { this.multiPressCount++; this.debugLog(`${this.device.deviceType} set to Multi-Press. Multi-Press count: ${this.multiPressCount}`); } - } this.On = value; } @@ -791,8 +830,9 @@ export class Bot { this.platform.Characteristic.CurrentDoorState, this.platform.Characteristic.CurrentDoorState.OPEN, ); - this.debugLog(`${this.device.deviceType}: ` - + `${this.accessory.displayName} updateCharacteristic TargetDoorState: Open, CurrentDoorState: Open`); + this.debugLog( + `${this.device.deviceType}: ` + `${this.accessory.displayName} updateCharacteristic TargetDoorState: Open, CurrentDoorState: Open`, + ); } else { this.garageDoorService?.updateCharacteristic( this.platform.Characteristic.TargetDoorState, @@ -802,8 +842,9 @@ export class Bot { this.platform.Characteristic.CurrentDoorState, this.platform.Characteristic.CurrentDoorState.CLOSED, ); - this.debugLog(`${this.device.deviceType}: ` - + `${this.accessory.displayName} updateCharacteristic TargetDoorState: Open, CurrentDoorState: Open`); + this.debugLog( + `${this.device.deviceType}: ` + `${this.accessory.displayName} updateCharacteristic TargetDoorState: Open, CurrentDoorState: Open`, + ); } } this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Garage Door On: ${this.On}`); @@ -877,16 +918,19 @@ export class Bot { this.platform.Characteristic.LockCurrentState, this.platform.Characteristic.LockCurrentState.UNSECURED, ); - this.debugLog(`${this.device.deviceType}: ` - + `${this.accessory.displayName} updateCharacteristic LockTargetState: UNSECURED, LockCurrentState: UNSECURED`); + this.debugLog( + `${this.device.deviceType}: ` + + `${this.accessory.displayName} updateCharacteristic LockTargetState: UNSECURED, LockCurrentState: UNSECURED`, + ); } else { this.lockService?.updateCharacteristic(this.platform.Characteristic.LockTargetState, this.platform.Characteristic.LockTargetState.SECURED); this.lockService?.updateCharacteristic( this.platform.Characteristic.LockCurrentState, this.platform.Characteristic.LockCurrentState.SECURED, ); - this.debugLog(`${this.device.deviceType}: ` - + `${this.accessory.displayName} updateCharacteristic LockTargetState: SECURED, LockCurrentState: SECURED`); + this.debugLog( + `${this.device.deviceType}: ` + `${this.accessory.displayName} updateCharacteristic LockTargetState: SECURED, LockCurrentState: SECURED`, + ); } } this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Lock On: ${this.On}`); @@ -926,16 +970,20 @@ export class Bot { this.platform.Characteristic.ProgrammableSwitchEvent.SINGLE_PRESS, ); this.statefulProgrammableSwitchService?.updateCharacteristic(this.platform.Characteristic.ProgrammableSwitchOutputState, 1); - this.debugLog(`${this.device.deviceType}: ` - + `${this.accessory.displayName} updateCharacteristic ProgrammableSwitchEvent: SINGLE, ProgrammableSwitchOutputState: 1`); + this.debugLog( + `${this.device.deviceType}: ` + + `${this.accessory.displayName} updateCharacteristic ProgrammableSwitchEvent: SINGLE, ProgrammableSwitchOutputState: 1`, + ); } else { this.statefulProgrammableSwitchService?.updateCharacteristic( this.platform.Characteristic.ProgrammableSwitchEvent, this.platform.Characteristic.ProgrammableSwitchEvent.SINGLE_PRESS, ); this.statefulProgrammableSwitchService?.updateCharacteristic(this.platform.Characteristic.ProgrammableSwitchOutputState, 0); - this.debugLog(`${this.device.deviceType}: ` - + `${this.accessory.displayName} updateCharacteristic ProgrammableSwitchEvent: SINGLE, ProgrammableSwitchOutputState: 0`); + this.debugLog( + `${this.device.deviceType}: ` + + `${this.accessory.displayName} updateCharacteristic ProgrammableSwitchEvent: SINGLE, ProgrammableSwitchOutputState: 0`, + ); } } this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} StatefulProgrammableSwitch On: ${this.On}`); @@ -954,23 +1002,22 @@ export class Bot { this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic On: ${this.On}`); } } - this.accessory.context.On = this.On; - if (this.BLE) { - if (this.BatteryLevel === undefined) { - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}`); - } else { - this.accessory.context.BatteryLevel = this.BatteryLevel; - this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, this.BatteryLevel); - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic BatteryLevel: ${this.BatteryLevel}`); - } - if (this.StatusLowBattery === undefined) { - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} StatusLowBattery: ${this.StatusLowBattery}`); - } else { - this.accessory.context.StatusLowBattery = this.StatusLowBattery; - this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, this.StatusLowBattery); - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic StatusLowBattery: ${this.StatusLowBattery}`); - } + if (this.BatteryLevel === undefined) { + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}`); + } else { + this.accessory.context.BatteryLevel = this.BatteryLevel; + this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, this.BatteryLevel); + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic BatteryLevel: ${this.BatteryLevel}`); } + if (this.StatusLowBattery === undefined) { + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} StatusLowBattery: ${this.StatusLowBattery}`); + } else { + this.accessory.context.StatusLowBattery = this.StatusLowBattery; + this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, this.StatusLowBattery); + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic StatusLowBattery: ${this.StatusLowBattery}`); + } + + this.accessory.context.On = this.On; } async removeOutletService(accessory: PlatformAccessory): Promise { @@ -1193,8 +1240,10 @@ export class Bot { this.offlineOff(); break; case 171: - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` - + `Hub: ${this.device.hubDeviceId}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` + + `Hub: ${this.device.hubDeviceId}`, + ); this.offlineOff(); break; case 190: @@ -1210,8 +1259,10 @@ export class Bot { this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Request successful, statusCode: ${statusCode}`); break; default: - this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode: ` - + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`); + this.infoLog( + `${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode: ` + + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`, + ); } } @@ -1254,22 +1305,23 @@ export class Bot { } else { this.outletService?.updateCharacteristic(this.platform.Characteristic.On, e); } - if (this.BLE) { - this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, e); - this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, e); - } + this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, e); + this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, e); } FirmwareRevision(accessory: PlatformAccessory, device: device & devicesConfig): CharacteristicValue { let FirmwareRevision: string; - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}` - + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName}` + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`, + ); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} device.firmware: ${device.firmware}`); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`); - if (accessory.context.FirmwareRevision) { - FirmwareRevision = accessory.context.FirmwareRevision; - } else if (device.firmware) { + if (device.firmware) { FirmwareRevision = device.firmware; + } else if (device.version) { + FirmwareRevision = JSON.stringify(device.version); + } if (accessory.context.FirmwareRevision) { + FirmwareRevision = accessory.context.FirmwareRevision; } else { FirmwareRevision = this.platform.version; } @@ -1341,7 +1393,7 @@ export class Bot { config['maxRetry'] = device.maxRetry; } if (Object.entries(config).length !== 0) { - this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); + this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); } } diff --git a/src/device/ceilinglight.ts b/src/device/ceilinglight.ts index 25000ffb..a3838466 100644 --- a/src/device/ceilinglight.ts +++ b/src/device/ceilinglight.ts @@ -1,3 +1,4 @@ +/* eslint-disable brace-style */ import { Context } from 'vm'; import { request } from 'undici'; import { sleep } from '../utils'; @@ -24,6 +25,7 @@ export class CeilingLight { ColorTemperature?: CharacteristicValue; // OpenAPI Others + Version: deviceStatus['version']; power: deviceStatus['power']; color: deviceStatus['color']; brightness: deviceStatus['brightness']; @@ -59,17 +61,22 @@ export class CeilingLight { doCeilingLightUpdate!: Subject; // Connection - private readonly BLE = (this.device.connectionType === 'BLE' || this.device.connectionType === 'BLE/OpenAPI'); - private readonly OpenAPI = (this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'BLE/OpenAPI'); - - constructor(private readonly platform: SwitchBotPlatform, private accessory: PlatformAccessory, public device: device & devicesConfig) { + private readonly BLE = this.device.connectionType === 'BLE' || this.device.connectionType === 'BLE/OpenAPI'; + private readonly OpenAPI = this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'BLE/OpenAPI'; + + constructor( + private readonly platform: SwitchBotPlatform, + private accessory: PlatformAccessory, + public device: device & devicesConfig, + ) { // default placeholders this.logs(device); this.scan(device); this.refreshRate(device); this.adaptiveLighting(device); - this.config(device); this.context(); + this.config(device); + // this is subject we use to track when we need to POST changes to the SwitchBot API this.doCeilingLightUpdate = new Subject(); this.ceilingLightUpdateInProgress = false; @@ -202,8 +209,10 @@ export class CeilingLight { await this.pushChanges(); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType} Connection,` - + ` Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType} Connection,` + + ` Error Message: ${JSON.stringify(e.message)}`, + ); } this.ceilingLightUpdateInProgress = false; }); @@ -227,14 +236,16 @@ export class CeilingLight { async parseStatus(): Promise { if (!this.device.enableCloudService && this.OpenAPI) { this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} parseStatus enableCloudService: ${this.device.enableCloudService}`); - } else /*if (this.BLE) { + } + /*if (this.BLE) { await this.BLEparseStatus(); - } else*/ if (this.OpenAPI && this.platform.config.credentials?.token) { + } else*/ else if (this.OpenAPI && this.platform.config.credentials?.token) { await this.openAPIparseStatus(); } else { await this.offlineOff(); - this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` - + ` ${this.device.connectionType}, parseStatus will not happen.`); + this.debugWarnLog( + `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + ` ${this.device.connectionType}, parseStatus will not happen.`, + ); } } @@ -275,8 +286,9 @@ export class CeilingLight { this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} blue: ${JSON.stringify(blue)}`); const [hue, saturation] = rgb2hs(Number(red), Number(green), Number(blue)); - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}` - + ` hs: ${JSON.stringify(rgb2hs(Number(red), Number(green), Number(blue)))}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName}` + ` hs: ${JSON.stringify(rgb2hs(Number(red), Number(green), Number(blue)))}`, + ); // Hue this.Hue = hue; @@ -305,14 +317,16 @@ export class CeilingLight { async refreshStatus(): Promise { if (!this.device.enableCloudService && this.OpenAPI) { this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} refreshStatus enableCloudService: ${this.device.enableCloudService}`); - } else/*if (this.BLE) { + } /*if (this.BLE) { await this.BLERefreshStatus(); - } else*/ if (this.OpenAPI && this.platform.config.credentials?.token) { + } else*/ else if (this.OpenAPI && this.platform.config.credentials?.token) { await this.openAPIRefreshStatus(); } else { await this.offlineOff(); - this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` - + ` ${this.device.connectionType}, refreshStatus will not happen.`); + this.debugWarnLog( + `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + + ` ${this.device.connectionType}, refreshStatus will not happen.`, + ); } } @@ -337,8 +351,10 @@ export class CeilingLight { // Set an event hander switchbot.onadvertisement = async (ad: any) => { this.address = ad.address; - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Config BLE Address: ${this.device.bleMac},` - + ` BLE Address Found: ${this.address}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} Config BLE Address: ${this.device.bleMac},` + + ` BLE Address Found: ${this.address}`, + ); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} serviceData: ${JSON.stringify(ad.serviceData)}`); this.serviceData = ad.serviceData; //this.state = ad.serviceData.state; @@ -373,8 +389,10 @@ export class CeilingLight { }) .catch(async (e: any) => { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLERefreshStatus with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed BLERefreshStatus with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + ); await this.BLERefreshConnection(switchbot); }); } else { @@ -388,14 +406,11 @@ export class CeilingLight { const { body, statusCode, headers } = await request(`${Devices}/${this.device.deviceId}/status`, { headers: this.platform.generateHeaders(), }); - const deviceStatus = await body.json(); + const deviceStatus: any = await body.json(); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`); this.statusCode(statusCode); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`); - this.debugLog( - `${this.device.deviceType}: ${this.accessory.displayName - } refreshStatus: ${JSON.stringify(deviceStatus)}`, - ); + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} refreshStatus: ${JSON.stringify(deviceStatus)}`); this.power = deviceStatus.body.power; this.color = deviceStatus.body.color; this.brightness = deviceStatus.body.brightness; @@ -404,8 +419,10 @@ export class CeilingLight { this.updateHomeKitCharacteristics(); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + ); } } @@ -423,14 +440,15 @@ export class CeilingLight { async pushChanges(): Promise { if (!this.device.enableCloudService && this.OpenAPI) { this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} pushChanges enableCloudService: ${this.device.enableCloudService}`); - } else /*if (this.BLE) { + } /*if (this.BLE) { await this.BLEpushChanges(); - } else*/ if (this.OpenAPI && this.platform.config.credentials?.token) { + } else*/ else if (this.OpenAPI && this.platform.config.credentials?.token) { await this.openAPIpushChanges(); } else { await this.offlineOff(); - this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` - + ` ${this.device.connectionType}, pushChanges will not happen.`); + this.debugWarnLog( + `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + ` ${this.device.connectionType}, pushChanges will not happen.`, + ); } // Refresh the status from the API interval(15000) @@ -476,14 +494,15 @@ export class CeilingLight { }) .catch(async (e: any) => { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushChanges with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushChanges with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + ); await this.BLEPushConnection(); }); } else { this.debugLog( - `${this.device.deviceType}: ${this.accessory.displayName} No BLEpushChanges.` + `On: ${this.On}, ` - + `OnCached: ${this.accessory.context.On}`, + `${this.device.deviceType}: ${this.accessory.displayName} No BLEpushChanges.` + `On: ${this.On}, ` + `OnCached: ${this.accessory.context.On}`, ); } } @@ -498,9 +517,9 @@ export class CeilingLight { command = 'turnOff'; } const bodyChange = JSON.stringify({ - 'command': `${command}`, - 'parameter': 'default', - 'commandType': 'command', + command: `${command}`, + parameter: 'default', + commandType: 'command', }); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${bodyChange},`); try { @@ -509,19 +528,23 @@ export class CeilingLight { method: 'POST', headers: this.platform.generateHeaders(), }); - const deviceStatus = await body.json(); + const deviceStatus: any = await body.json(); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`); this.statusCode(statusCode); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIpushChanges with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed openAPIpushChanges with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, ); } } else { - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No openAPIpushChanges.` + `On: ${this.On}, ` - + `OnCached: ${this.accessory.context.On}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} No openAPIpushChanges.` + + `On: ${this.On}, ` + + `OnCached: ${this.accessory.context.On}`, + ); } // Push Hue & Saturation Update if (this.On) { @@ -545,9 +568,9 @@ export class CeilingLight { const [red, green, blue] = hs2rgb(Number(this.Hue), Number(this.Saturation)); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} rgb: ${JSON.stringify([red, green, blue])}`); const bodyChange = JSON.stringify({ - 'command': 'setColor', - 'parameter': `${red}:${green}:${blue}`, - 'commandType': 'command', + command: 'setColor', + parameter: `${red}:${green}:${blue}`, + commandType: 'command', }); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${bodyChange},`); try { @@ -556,19 +579,22 @@ export class CeilingLight { method: 'POST', headers: this.platform.generateHeaders(), }); - const deviceStatus = await body.json(); + const deviceStatus: any = await body.json(); this.debugLog(`Devices: ${JSON.stringify(deviceStatus.body)}`); this.statusCode(statusCode); this.debugLog(`Headers: ${JSON.stringify(headers)}`); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushHueSaturationChanges with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed pushHueSaturationChanges with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, ); } } else { - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No pushHueSaturationChanges. Hue: ${this.Hue}, ` - + `HueCached: ${this.accessory.context.Hue}, Saturation: ${this.Saturation}, SaturationCached: ${this.accessory.context.Saturation}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} No pushHueSaturationChanges. Hue: ${this.Hue}, ` + + `HueCached: ${this.accessory.context.Hue}, Saturation: ${this.Saturation}, SaturationCached: ${this.accessory.context.Saturation}`, + ); } } @@ -578,9 +604,9 @@ export class CeilingLight { const kelvin = Math.round(1000000 / Number(this.ColorTemperature)); this.cacheKelvin = kelvin; const bodyChange = JSON.stringify({ - 'command': 'setColorTemperature', - 'parameter': `${kelvin}`, - 'commandType': 'command', + command: 'setColorTemperature', + parameter: `${kelvin}`, + commandType: 'command', }); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${bodyChange},`); try { @@ -589,19 +615,22 @@ export class CeilingLight { method: 'POST', headers: this.platform.generateHeaders(), }); - const deviceStatus = await body.json(); + const deviceStatus: any = await body.json(); this.debugLog(`Devices: ${JSON.stringify(deviceStatus.body)}`); this.statusCode(statusCode); this.debugLog(`Headers: ${JSON.stringify(headers)}`); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushColorTemperatureChanges with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed pushColorTemperatureChanges with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, ); } } else { - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No pushColorTemperatureChanges.` + - `ColorTemperature: ${this.ColorTemperature}, ColorTemperatureCached: ${this.accessory.context.ColorTemperature}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} No pushColorTemperatureChanges.` + + `ColorTemperature: ${this.ColorTemperature}, ColorTemperatureCached: ${this.accessory.context.ColorTemperature}`, + ); } } @@ -609,9 +638,9 @@ export class CeilingLight { this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} pushBrightnessChanges`); if (this.Brightness !== this.accessory.context.Brightness) { const bodyChange = JSON.stringify({ - 'command': 'setBrightness', - 'parameter': `${this.Brightness}`, - 'commandType': 'command', + command: 'setBrightness', + parameter: `${this.Brightness}`, + commandType: 'command', }); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${bodyChange},`); try { @@ -620,19 +649,23 @@ export class CeilingLight { method: 'POST', headers: this.platform.generateHeaders(), }); - const deviceStatus = await body.json(); + const deviceStatus: any = await body.json(); this.debugLog(`Devices: ${JSON.stringify(deviceStatus.body)}`); this.statusCode(statusCode); this.debugLog(`Headers: ${JSON.stringify(headers)}`); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushBrightnessChanges with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed pushBrightnessChanges with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, ); } } else { - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No pushBrightnessChanges.` + `Brightness: ${this.Brightness}, ` - + `BrightnessCached: ${this.accessory.context.Brightness}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} No pushBrightnessChanges.` + + `Brightness: ${this.Brightness}, ` + + `BrightnessCached: ${this.accessory.context.Brightness}`, + ); } } @@ -884,8 +917,10 @@ export class CeilingLight { this.offlineOff(); break; case 171: - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` - + `Hub: ${this.device.hubDeviceId}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` + + `Hub: ${this.device.hubDeviceId}`, + ); this.offlineOff(); break; case 190: @@ -901,8 +936,10 @@ export class CeilingLight { this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Request successful, statusCode: ${statusCode}`); break; default: - this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode: ` - + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`); + this.infoLog( + `${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode: ` + + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`, + ); } } @@ -923,14 +960,17 @@ export class CeilingLight { FirmwareRevision(accessory: PlatformAccessory, device: device & devicesConfig): CharacteristicValue { let FirmwareRevision: string; - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}` - + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName}` + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`, + ); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} device.firmware: ${device.firmware}`); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`); - if (accessory.context.FirmwareRevision) { - FirmwareRevision = accessory.context.FirmwareRevision; - } else if (device.firmware) { + if (device.firmware) { FirmwareRevision = device.firmware; + } else if (device.version) { + FirmwareRevision = JSON.stringify(device.version); + } else if (accessory.context.FirmwareRevision) { + FirmwareRevision = accessory.context.FirmwareRevision; } else { FirmwareRevision = this.platform.version; } @@ -1004,7 +1044,7 @@ export class CeilingLight { config['maxRetry'] = device.maxRetry; } if (Object.entries(config).length !== 0) { - this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); + this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); } } diff --git a/src/device/colorbulb.ts b/src/device/colorbulb.ts index e4ce4a93..a39f9cfc 100644 --- a/src/device/colorbulb.ts +++ b/src/device/colorbulb.ts @@ -1,3 +1,4 @@ +/* eslint-disable brace-style */ import { Context } from 'vm'; import { request } from 'undici'; import { sleep } from '../utils'; @@ -24,6 +25,7 @@ export class ColorBulb { ColorTemperature?: CharacteristicValue; // OpenAPI Others + Version: deviceStatus['version']; power: deviceStatus['power']; color: deviceStatus['color']; brightness: deviceStatus['brightness']; @@ -44,10 +46,10 @@ export class ColorBulb { wifiRssi: serviceData['wifiRssi']; brightnessBLE: serviceData['brightness']; color_temperature: serviceData['color_temperature']; - preset: any;//serviceData['preset']; - color_mode: any;//serviceData['color_mode']; - speed: any;//serviceData['speed']; - loop_index: any;//serviceData['loop_index']; + preset: any; //serviceData['preset']; + color_mode: any; //serviceData['color_mode']; + speed: any; //serviceData['speed']; + loop_index: any; //serviceData['loop_index']; // Config set_minStep?: number; @@ -69,17 +71,22 @@ export class ColorBulb { doColorBulbUpdate!: Subject; // Connection - private readonly BLE = (this.device.connectionType === 'BLE' || this.device.connectionType === 'BLE/OpenAPI'); - private readonly OpenAPI = (this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'BLE/OpenAPI'); - - constructor(private readonly platform: SwitchBotPlatform, private accessory: PlatformAccessory, public device: device & devicesConfig) { + private readonly BLE = this.device.connectionType === 'BLE' || this.device.connectionType === 'BLE/OpenAPI'; + private readonly OpenAPI = this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'BLE/OpenAPI'; + + constructor( + private readonly platform: SwitchBotPlatform, + private accessory: PlatformAccessory, + public device: device & devicesConfig, + ) { // default placeholders this.logs(device); this.scan(device); this.refreshRate(device); this.adaptiveLighting(device); - this.config(device); this.context(); + this.config(device); + // this is subject we use to track when we need to POST changes to the SwitchBot API this.doColorBulbUpdate = new Subject(); this.colorBulbUpdateInProgress = false; @@ -213,8 +220,10 @@ export class ColorBulb { await this.pushChanges(); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType} Connection,` - + ` Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType} Connection,` + + ` Error Message: ${JSON.stringify(e.message)}`, + ); } this.colorBulbUpdateInProgress = false; }); @@ -232,8 +241,9 @@ export class ColorBulb { await this.openAPIparseStatus(); } else { await this.offlineOff(); - this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` - + ` ${this.device.connectionType}, parseStatus will not happen.`); + this.debugWarnLog( + `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + ` ${this.device.connectionType}, parseStatus will not happen.`, + ); } } @@ -249,7 +259,6 @@ export class ColorBulb { } this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`); - // Brightness this.Brightness = Number(this.brightnessBLE); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Brightness: ${this.Brightness}`); @@ -260,8 +269,10 @@ export class ColorBulb { this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} blue: ${this.blue}`); const [hue, saturation] = rgb2hs(Number(this.red), Number(this.green), Number(this.blue)); - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}` - + ` hs: ${JSON.stringify(rgb2hs(Number(this.red), Number(this.green), Number(this.blue)))}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName}` + + ` hs: ${JSON.stringify(rgb2hs(Number(this.red), Number(this.green), Number(this.blue)))}`, + ); // Hue this.Hue = hue; @@ -305,8 +316,9 @@ export class ColorBulb { this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} blue: ${JSON.stringify(blue)}`); const [hue, saturation] = rgb2hs(Number(red), Number(green), Number(blue)); - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}` - + ` hs: ${JSON.stringify(rgb2hs(Number(red), Number(green), Number(blue)))}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName}` + ` hs: ${JSON.stringify(rgb2hs(Number(red), Number(green), Number(blue)))}`, + ); // Hue this.Hue = hue; @@ -341,8 +353,10 @@ export class ColorBulb { await this.openAPIRefreshStatus(); } else { await this.offlineOff(); - this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` - + ` ${this.device.connectionType}, refreshStatus will not happen.`); + this.debugWarnLog( + `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + + ` ${this.device.connectionType}, refreshStatus will not happen.`, + ); } } @@ -367,8 +381,10 @@ export class ColorBulb { // Set an event hander switchbot.onadvertisement = async (ad: any) => { this.address = ad.address; - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Config BLE Address: ${this.device.bleMac},` - + ` BLE Address Found: ${this.address}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} Config BLE Address: ${this.device.bleMac},` + + ` BLE Address Found: ${this.address}`, + ); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} serviceData: ${JSON.stringify(ad.serviceData)}`); this.serviceData = ad.serviceData; this.powerState = ad.serviceData.power; @@ -408,8 +424,10 @@ export class ColorBulb { }) .catch(async (e: any) => { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLERefreshStatus with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed BLERefreshStatus with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + ); await this.BLERefreshConnection(switchbot); }); } else { @@ -423,7 +441,7 @@ export class ColorBulb { const { body, statusCode, headers } = await request(`${Devices}/${this.device.deviceId}/status`, { headers: this.platform.generateHeaders(), }); - const deviceStatus = await body.json(); + const deviceStatus: any = await body.json(); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`); this.statusCode(statusCode); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`); @@ -436,8 +454,10 @@ export class ColorBulb { this.updateHomeKitCharacteristics(); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + ); } } @@ -455,14 +475,15 @@ export class ColorBulb { async pushChanges(): Promise { if (!this.device.enableCloudService && this.OpenAPI) { this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} pushChanges enableCloudService: ${this.device.enableCloudService}`); - } else/* if (this.BLE) { + } /* if (this.BLE) { await this.BLEpushChanges(); - } else*/if (this.OpenAPI && this.platform.config.credentials?.token) { + } else*/ else if (this.OpenAPI && this.platform.config.credentials?.token) { await this.openAPIpushChanges(); } else { await this.offlineOff(); - this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` - + ` ${this.device.connectionType}, pushChanges will not happen.`); + this.debugWarnLog( + `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + ` ${this.device.connectionType}, pushChanges will not happen.`, + ); } // Refresh the status from the API interval(15000) @@ -508,8 +529,10 @@ export class ColorBulb { }) .catch(async (e: any) => { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushChanges with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushChanges with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + ); await this.BLEPushConnection(); }); // Push Brightness Update @@ -525,8 +548,9 @@ export class ColorBulb { await this.BLEpushRGBChanges(); } } else { - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No BLEpushChanges.` + `On: ${this.On}, ` - + `OnCached: ${this.accessory.context.On}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} No BLEpushChanges.` + `On: ${this.On}, ` + `OnCached: ${this.accessory.context.On}`, + ); } } @@ -555,13 +579,18 @@ export class ColorBulb { }) .catch(async (e: any) => { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushBrightnessChanges with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushBrightnessChanges with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + ); await this.BLEPushConnection(); }); } else { - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No BLEpushBrightnessChanges.` + `Brightness: ${this.Brightness}, ` - + `BrightnessCached: ${this.accessory.context.Brightness}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} No BLEpushBrightnessChanges.` + + `Brightness: ${this.Brightness}, ` + + `BrightnessCached: ${this.accessory.context.Brightness}`, + ); } } @@ -590,14 +619,17 @@ export class ColorBulb { }) .catch(async (e: any) => { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushColorTemperatureChanges with ` - + `${this.device.connectionType} Connection, Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushColorTemperatureChanges with ` + + `${this.device.connectionType} Connection, Error Message: ${JSON.stringify(e.message)}`, + ); await this.BLEPushConnection(); }); } else { - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No BLEpushColorTemperatureChanges.` + - `ColorTemperature: ${this.ColorTemperature}, ColorTemperatureCached: ${this.accessory.context.ColorTemperature}`); - + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} No BLEpushColorTemperatureChanges.` + + `ColorTemperature: ${this.ColorTemperature}, ColorTemperatureCached: ${this.accessory.context.ColorTemperature}`, + ); } } @@ -623,7 +655,7 @@ export class ColorBulb { id: this.device.bleMac, }) .then(async (device_list: any) => { - this.infoLog(`${this.accessory.displayName} Target RGB: ${this.Brightness, red, green, blue}`); + this.infoLog(`${this.accessory.displayName} Target RGB: ${(this.Brightness, red, green, blue)}`); return await device_list[0].setRGB(this.Brightness, red, green, blue); }) .then(() => { @@ -632,13 +664,17 @@ export class ColorBulb { }) .catch(async (e: any) => { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushRGBChanges with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushRGBChanges with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + ); await this.BLEPushConnection(); }); } else { - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No BLEpushRGBChanges. Hue: ${this.Hue}, ` - + `HueCached: ${this.accessory.context.Hue}, Saturation: ${this.Saturation}, SaturationCached: ${this.accessory.context.Saturation}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} No BLEpushRGBChanges. Hue: ${this.Hue}, ` + + `HueCached: ${this.accessory.context.Hue}, Saturation: ${this.Saturation}, SaturationCached: ${this.accessory.context.Saturation}`, + ); } } @@ -652,9 +688,9 @@ export class ColorBulb { command = 'turnOff'; } const bodyChange = JSON.stringify({ - 'command': `${command}`, - 'parameter': 'default', - 'commandType': 'command', + command: `${command}`, + parameter: 'default', + commandType: 'command', }); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${bodyChange},`); try { @@ -663,19 +699,23 @@ export class ColorBulb { method: 'POST', headers: this.platform.generateHeaders(), }); - const deviceStatus = await body.json(); + const deviceStatus: any = await body.json(); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`); this.statusCode(statusCode); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIpushChanges with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed openAPIpushChanges with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, ); } } else { - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No openAPIpushChanges.` + `On: ${this.On}, ` - + `OnCached: ${this.accessory.context.On}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} No openAPIpushChanges.` + + `On: ${this.On}, ` + + `OnCached: ${this.accessory.context.On}`, + ); } // Push Hue & Saturation Update if (this.On) { @@ -699,9 +739,9 @@ export class ColorBulb { const [red, green, blue] = hs2rgb(Number(this.Hue), Number(this.Saturation)); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} rgb: ${JSON.stringify([red, green, blue])}`); const bodyChange = JSON.stringify({ - 'command': 'setColor', - 'parameter': `${red}:${green}:${blue}`, - 'commandType': 'command', + command: 'setColor', + parameter: `${red}:${green}:${blue}`, + commandType: 'command', }); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${bodyChange},`); try { @@ -710,19 +750,22 @@ export class ColorBulb { method: 'POST', headers: this.platform.generateHeaders(), }); - const deviceStatus = await body.json(); + const deviceStatus: any = await body.json(); this.debugLog(`Devices: ${JSON.stringify(deviceStatus.body)}`); this.statusCode(statusCode); this.debugLog(`Headers: ${JSON.stringify(headers)}`); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushHueSaturationChanges with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed pushHueSaturationChanges with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, ); } } else { - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No pushHueSaturationChanges. Hue: ${this.Hue}, ` - + `HueCached: ${this.accessory.context.Hue}, Saturation: ${this.Saturation}, SaturationCached: ${this.accessory.context.Saturation}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} No pushHueSaturationChanges. Hue: ${this.Hue}, ` + + `HueCached: ${this.accessory.context.Hue}, Saturation: ${this.Saturation}, SaturationCached: ${this.accessory.context.Saturation}`, + ); } } @@ -732,9 +775,9 @@ export class ColorBulb { const kelvin = Math.round(1000000 / Number(this.ColorTemperature)); this.cacheKelvin = kelvin; const bodyChange = JSON.stringify({ - 'command': 'setColorTemperature', - 'parameter': `${kelvin}`, - 'commandType': 'command', + command: 'setColorTemperature', + parameter: `${kelvin}`, + commandType: 'command', }); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${bodyChange},`); try { @@ -743,19 +786,22 @@ export class ColorBulb { method: 'POST', headers: this.platform.generateHeaders(), }); - const deviceStatus = await body.json(); + const deviceStatus: any = await body.json(); this.debugLog(`Devices: ${JSON.stringify(deviceStatus.body)}`); this.statusCode(statusCode); this.debugLog(`Headers: ${JSON.stringify(headers)}`); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushColorTemperatureChanges with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed pushColorTemperatureChanges with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, ); } } else { - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No pushColorTemperatureChanges.` + - `ColorTemperature: ${this.ColorTemperature}, ColorTemperatureCached: ${this.accessory.context.ColorTemperature}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} No pushColorTemperatureChanges.` + + `ColorTemperature: ${this.ColorTemperature}, ColorTemperatureCached: ${this.accessory.context.ColorTemperature}`, + ); } } @@ -763,9 +809,9 @@ export class ColorBulb { this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} pushBrightnessChanges`); if (this.Brightness !== this.accessory.context.Brightness) { const bodyChange = JSON.stringify({ - 'command': 'setBrightness', - 'parameter': `${this.Brightness}`, - 'commandType': 'command', + command: 'setBrightness', + parameter: `${this.Brightness}`, + commandType: 'command', }); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${bodyChange},`); try { @@ -774,19 +820,23 @@ export class ColorBulb { method: 'POST', headers: this.platform.generateHeaders(), }); - const deviceStatus = await body.json(); + const deviceStatus: any = await body.json(); this.debugLog(`Devices: ${JSON.stringify(deviceStatus.body)}`); this.statusCode(statusCode); this.debugLog(`Headers: ${JSON.stringify(headers)}`); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushBrightnessChanges with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed pushBrightnessChanges with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, ); } } else { - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No pushBrightnessChanges.` + `Brightness: ${this.Brightness}, ` - + `BrightnessCached: ${this.accessory.context.Brightness}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} No pushBrightnessChanges.` + + `Brightness: ${this.Brightness}, ` + + `BrightnessCached: ${this.accessory.context.Brightness}`, + ); } } @@ -1038,14 +1088,16 @@ export class ColorBulb { this.offlineOff(); break; case 171: - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` - + `Hub: ${this.device.hubDeviceId}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` + + `Hub: ${this.device.hubDeviceId}`, + ); this.offlineOff(); break; case 190: this.errorLog( `${this.device.deviceType}: ${this.accessory.displayName} Device internal error due to device states not synchronized with server,` + - ` Or command format is invalid, statusCode: ${statusCode}`, + ` Or command format is invalid, statusCode: ${statusCode}`, ); break; case 100: @@ -1055,8 +1107,10 @@ export class ColorBulb { this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Request successful, statusCode: ${statusCode}`); break; default: - this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode: ` - + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`); + this.infoLog( + `${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode: ` + + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`, + ); } } @@ -1077,14 +1131,17 @@ export class ColorBulb { FirmwareRevision(accessory: PlatformAccessory, device: device & devicesConfig): CharacteristicValue { let FirmwareRevision: string; - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}` - + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName}` + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`, + ); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} device.firmware: ${device.firmware}`); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`); - if (accessory.context.FirmwareRevision) { - FirmwareRevision = accessory.context.FirmwareRevision; - } else if (device.firmware) { + if (device.firmware) { FirmwareRevision = device.firmware; + } else if (device.version) { + FirmwareRevision = JSON.stringify(device.version); + } if (accessory.context.FirmwareRevision) { + FirmwareRevision = accessory.context.FirmwareRevision; } else { FirmwareRevision = this.platform.version; } @@ -1158,7 +1215,7 @@ export class ColorBulb { config['maxRetry'] = device.maxRetry; } if (Object.entries(config).length !== 0) { - this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); + this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); } } diff --git a/src/device/contact.ts b/src/device/contact.ts index 38129d9b..11908c27 100644 --- a/src/device/contact.ts +++ b/src/device/contact.ts @@ -27,6 +27,8 @@ export class Contact { StatusLowBattery!: CharacteristicValue; // OpenAPI others + Version: deviceStatus['version']; + Battery: deviceStatus['battery']; openState: deviceStatus['openState']; moveDetected: deviceStatus['moveDetected']; brightness: deviceStatus['brightness']; @@ -59,16 +61,20 @@ export class Contact { doContactUpdate!: Subject; // Connection - private readonly BLE = (this.device.connectionType === 'BLE' || this.device.connectionType === 'BLE/OpenAPI'); - private readonly OpenAPI = (this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'BLE/OpenAPI'); - - constructor(private readonly platform: SwitchBotPlatform, private accessory: PlatformAccessory, public device: device & devicesConfig) { + private readonly BLE = this.device.connectionType === 'BLE' || this.device.connectionType === 'BLE/OpenAPI'; + private readonly OpenAPI = this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'BLE/OpenAPI'; + + constructor( + private readonly platform: SwitchBotPlatform, + private accessory: PlatformAccessory, + public device: device & devicesConfig, + ) { // default placeholders this.logs(device); this.scan(device); this.refreshRate(device); - this.config(device); this.context(); + this.config(device); // this is subject we use to track when we need to POST changes to the SwitchBot API this.doContactUpdate = new Subject(); @@ -141,17 +147,16 @@ export class Contact { } // Battery Service - if (!this.BLE) { - this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Removing Battery Service`); - this.batteryService = this.accessory.getService(this.platform.Service.Battery); - accessory.removeService(this.batteryService!); - } else if (this.BLE && !this.batteryService) { + if (!this.batteryService) { this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Add Battery Service`); (this.batteryService = this.accessory.getService(this.platform.Service.Battery) || this.accessory.addService(this.platform.Service.Battery)), `${accessory.displayName} Battery`; this.batteryService.setCharacteristic(this.platform.Characteristic.Name, `${accessory.displayName} Battery`); - this.batteryService.setCharacteristic(this.platform.Characteristic.ConfiguredName, `${accessory.displayName} Battery`); + if (!this.batteryService.testCharacteristic(this.platform.Characteristic.ConfiguredName)) { + this.batteryService.addCharacteristic(this.platform.Characteristic.ConfiguredName, `${accessory.displayName} Battery`); + } + this.batteryService.setCharacteristic(this.platform.Characteristic.ChargingState, this.platform.Characteristic.ChargingState.NOT_CHARGEABLE); } else { this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Battery Service Not Added`); } @@ -179,8 +184,9 @@ export class Contact { await this.openAPIparseStatus(); } else { await this.offlineOff(); - this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` - + ` ${this.device.connectionType}, parseStatus will not happen.`); + this.debugWarnLog( + `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + ` ${this.device.connectionType}, parseStatus will not happen.`, + ); } } @@ -200,15 +206,17 @@ export class Contact { this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} timeout no closed, doorstate: ${this.doorState}`); } this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ContactSensorState: ${this.ContactSensorState}`); - if ((this.ContactSensorState !== this.accessory.context.ContactSensorState) - && this.platform.Characteristic.ContactSensorState.CONTACT_NOT_DETECTED) { + if ( + this.ContactSensorState !== this.accessory.context.ContactSensorState && + this.platform.Characteristic.ContactSensorState.CONTACT_NOT_DETECTED + ) { this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Opened`); } // Movement if (!this.device.contact?.hide_motionsensor) { this.MotionDetected = Boolean(this.movement); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} MotionDetected: ${this.MotionDetected}`); - if ((this.MotionDetected !== this.accessory.context.MotionDetected) && this.MotionDetected) { + if (this.MotionDetected !== this.accessory.context.MotionDetected && this.MotionDetected) { this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Detected Motion`); } } @@ -223,8 +231,10 @@ export class Contact { default: this.CurrentAmbientLightLevel = this.set_maxLux; } - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.is_light},` + - ` CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.is_light},` + + ` CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`, + ); if (this.CurrentAmbientLightLevel !== this.accessory.context.CurrentAmbientLightLevel) { this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`); } @@ -239,8 +249,9 @@ export class Contact { } else { this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL; } - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}, ` - + `StatusLowBattery: ${this.StatusLowBattery}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}, ` + `StatusLowBattery: ${this.StatusLowBattery}`, + ); } async openAPIparseStatus(): Promise { @@ -274,6 +285,19 @@ export class Contact { } this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`); } + // Battery + if (this.battery === undefined) { + this.battery === 100; + } + this.BatteryLevel = Number(this.Battery); + if (this.BatteryLevel < 10) { + this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW; + } else { + this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL; + } + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}, ` + `StatusLowBattery: ${this.StatusLowBattery}`, + ); } /** @@ -288,8 +312,10 @@ export class Contact { await this.openAPIRefreshStatus(); } else { await this.offlineOff(); - this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` - + ` ${this.device.connectionType}, refreshStatus will not happen.`); + this.debugWarnLog( + `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + + ` ${this.device.connectionType}, refreshStatus will not happen.`, + ); } } @@ -317,8 +343,10 @@ export class Contact { this.scanning = true; switchbot.onadvertisement = async (ad: any) => { this.address = ad.address; - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Config BLE Address: ${this.device.bleMac},` - + ` BLE Address Found: ${this.address}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} Config BLE Address: ${this.device.bleMac},` + + ` BLE Address Found: ${this.address}`, + ); this.serviceData = ad.serviceData; this.movement = ad.serviceData.movement; this.tested = ad.serviceData.tested; @@ -355,8 +383,10 @@ export class Contact { }) .catch(async (e: any) => { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLERefreshStatus with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed BLERefreshStatus with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + ); await this.BLERefreshConnection(switchbot); }); } else { @@ -370,23 +400,24 @@ export class Contact { const { body, statusCode, headers } = await request(`${Devices}/${this.device.deviceId}/status`, { headers: this.platform.generateHeaders(), }); - const deviceStatus = await body.json(); + const deviceStatus: any = await body.json(); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`); this.statusCode(statusCode); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`); - this.debugLog( - `${this.device.deviceType}: ${this.accessory.displayName - } refreshStatus: ${JSON.stringify(deviceStatus)}`, - ); + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} refreshStatus: ${JSON.stringify(deviceStatus)}`); this.openState = deviceStatus.body.openState; this.moveDetected = deviceStatus.body.moveDetected; this.brightness = deviceStatus.body.brightness; + this.Battery = deviceStatus.body.battery; + this.Version = deviceStatus.body.version; this.openAPIparseStatus(); this.updateHomeKitCharacteristics(); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + ); } } @@ -416,26 +447,25 @@ export class Contact { } else { this.accessory.context.CurrentAmbientLightLevel = this.CurrentAmbientLightLevel; this.lightSensorService?.updateCharacteristic(this.platform.Characteristic.CurrentAmbientLightLevel, this.CurrentAmbientLightLevel); - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}` - + ` updateCharacteristic CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`, + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName}` + + ` updateCharacteristic CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`, ); } } - if (this.BLE) { - if (this.BatteryLevel === undefined) { - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}`); - } else { - this.accessory.context.BatteryLevel = this.BatteryLevel; - this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, this.BatteryLevel); - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic BatteryLevel: ${this.BatteryLevel}`); - } - if (this.StatusLowBattery === undefined) { - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} StatusLowBattery: ${this.StatusLowBattery}`); - } else { - this.accessory.context.StatusLowBattery = this.StatusLowBattery; - this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, this.StatusLowBattery); - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic StatusLowBattery: ${this.StatusLowBattery}`); - } + if (this.BatteryLevel === undefined) { + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}`); + } else { + this.accessory.context.BatteryLevel = this.BatteryLevel; + this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, this.BatteryLevel); + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic BatteryLevel: ${this.BatteryLevel}`); + } + if (this.StatusLowBattery === undefined) { + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} StatusLowBattery: ${this.StatusLowBattery}`); + } else { + this.accessory.context.StatusLowBattery = this.StatusLowBattery; + this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, this.StatusLowBattery); + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic StatusLowBattery: ${this.StatusLowBattery}`); } } @@ -523,8 +553,10 @@ export class Contact { this.offlineOff(); break; case 171: - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` - + `Hub: ${this.device.hubDeviceId}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` + + `Hub: ${this.device.hubDeviceId}`, + ); this.offlineOff(); break; case 190: @@ -540,8 +572,10 @@ export class Contact { this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Request successful, statusCode: ${statusCode}`); break; default: - this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode: ` - + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`); + this.infoLog( + `${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode: ` + + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`, + ); } } @@ -560,22 +594,23 @@ export class Contact { if (!this.device.contact?.hide_lightsensor) { this.lightSensorService?.updateCharacteristic(this.platform.Characteristic.CurrentAmbientLightLevel, e); } - if (this.BLE) { - this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, e); - this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, e); - } + this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, e); + this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, e); } FirmwareRevision(accessory: PlatformAccessory, device: device & devicesConfig): CharacteristicValue { let FirmwareRevision: string; - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}` - + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName}` + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`, + ); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} device.firmware: ${device.firmware}`); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`); - if (accessory.context.FirmwareRevision) { - FirmwareRevision = accessory.context.FirmwareRevision; - } else if (device.firmware) { + if (device.firmware) { FirmwareRevision = device.firmware; + } else if (device.version) { + FirmwareRevision = JSON.stringify(device.version); + } else if (accessory.context.FirmwareRevision) { + FirmwareRevision = accessory.context.FirmwareRevision; } else { FirmwareRevision = this.platform.version; } @@ -626,7 +661,7 @@ export class Contact { config['scanDuration'] = device.scanDuration; } if (Object.entries(config).length !== 0) { - this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); + this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); } } diff --git a/src/device/curtain.ts b/src/device/curtain.ts index dda5742d..ecfe4da4 100644 --- a/src/device/curtain.ts +++ b/src/device/curtain.ts @@ -26,6 +26,8 @@ export class Curtain { lastActivation?: number; // OpenAPI Others + Version: deviceStatus['version']; + Battery: deviceStatus['battery']; deviceStatus!: any; //deviceStatusResponse; slidePosition: deviceStatus['slidePosition']; moving: deviceStatus['moving']; @@ -68,20 +70,24 @@ export class Curtain { doCurtainUpdate!: Subject; // Connection - private readonly BLE = (this.device.connectionType === 'BLE' || this.device.connectionType === 'BLE/OpenAPI'); - private readonly OpenAPI = (this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'BLE/OpenAPI'); + private readonly BLE = this.device.connectionType === 'BLE' || this.device.connectionType === 'BLE/OpenAPI'; + private readonly OpenAPI = this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'BLE/OpenAPI'; // EVE history service handler historyService: any = null; - constructor(private readonly platform: SwitchBotPlatform, private accessory: PlatformAccessory, public device: device & devicesConfig) { + constructor( + private readonly platform: SwitchBotPlatform, + private accessory: PlatformAccessory, + public device: device & devicesConfig, + ) { // default placeholders this.logs(device); this.refreshRate(device); this.scan(device); - this.config(device); this.setupMqtt(device); this.context(); + this.config(device); // this is subject we use to track when we need to POST changes to the SwitchBot API this.doCurtainUpdate = new Subject(); @@ -166,11 +172,7 @@ export class Curtain { } // Battery Service - if (!this.BLE) { - this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Removing Battery Service`); - this.batteryService = this.accessory.getService(this.platform.Service.Battery); - accessory.removeService(this.batteryService!); - } else if (this.BLE && !this.batteryService) { + if (!this.batteryService) { this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Add Battery Service`); (this.batteryService = this.accessory.getService(this.platform.Service.Battery) || this.accessory.addService(this.platform.Service.Battery)), `${accessory.displayName} Battery`; @@ -179,6 +181,7 @@ export class Curtain { if (!this.batteryService.testCharacteristic(this.platform.Characteristic.ConfiguredName)) { this.batteryService.addCharacteristic(this.platform.Characteristic.ConfiguredName, `${accessory.displayName} Battery`); } + this.batteryService.setCharacteristic(this.platform.Characteristic.ChargingState, this.platform.Characteristic.ChargingState.NOT_CHARGEABLE); } else { this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Battery Service Not Added`); } @@ -218,8 +221,10 @@ export class Curtain { await this.pushChanges(); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType} Connection,` - + ` Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType} Connection,` + + ` Error Message: ${JSON.stringify(e.message)}`, + ); } this.curtainUpdateInProgress = false; }); @@ -229,66 +234,65 @@ export class Curtain { } /* - * Setup EVE history features for curtain devices. + * Setup EVE history features for curtain devices. */ async setupHistoryService(device: device & devicesConfig): Promise { if (device.history !== true) { return; } - + const mac = this.device .deviceId!.match(/.{1,2}/g)! .join(':') .toLowerCase(); - this.historyService = - new this.platform.fakegatoAPI('custom', this.accessory, { - log: this.platform.log, - storage: 'fs', - filename: `${hostname().split(".")[0]}_${mac}_persist.json` - }); + this.historyService = new this.platform.fakegatoAPI('custom', this.accessory, { + log: this.platform.log, + storage: 'fs', + filename: `${hostname().split('.')[0]}_${mac}_persist.json`, + }); const motion: Service = - this.accessory.getService(this.platform.Service.MotionSensor) || - this.accessory.addService(this.platform.Service.MotionSensor, - `${this.accessory.displayName} Motion`); + this.accessory.getService(this.platform.Service.MotionSensor) || + this.accessory.addService(this.platform.Service.MotionSensor, `${this.accessory.displayName} Motion`); motion.addOptionalCharacteristic(this.platform.eve.Characteristics.LastActivation); - motion.getCharacteristic(this.platform.eve.Characteristics.LastActivation) - .onGet(() => { - const lastActivation = this.accessory.context.lastActivation ? - Math.max(0, this.accessory.context.lastActivation - - this.historyService.getInitialTime()) : 0; - return lastActivation; - }); + motion.getCharacteristic(this.platform.eve.Characteristics.LastActivation).onGet(() => { + const lastActivation = this.accessory.context.lastActivation + ? Math.max(0, this.accessory.context.lastActivation - this.historyService.getInitialTime()) + : 0; + return lastActivation; + }); await this.setMinMax(); - motion.getCharacteristic(this.platform.Characteristic.MotionDetected) - .on('change', (event: CharacteristicChange) => { - if (event.newValue !== event.oldValue) { - const sensor = this.accessory.getService(this.platform.Service.MotionSensor); - const entry = { - time: Math.round(new Date().valueOf()/1000), - motion: event.newValue - }; - this.accessory.context.lastActivation = entry.time; - sensor?.updateCharacteristic( - this.platform.eve.Characteristics.LastActivation, - Math.max(0, this.accessory.context.lastActivation - - this.historyService.getInitialTime())); - this.historyService.addEntry(entry); - } - }); + motion.getCharacteristic(this.platform.Characteristic.MotionDetected).on('change', (event: CharacteristicChange) => { + if (event.newValue !== event.oldValue) { + const sensor = this.accessory.getService(this.platform.Service.MotionSensor); + const entry = { + time: Math.round(new Date().valueOf() / 1000), + motion: event.newValue, + }; + this.accessory.context.lastActivation = entry.time; + sensor?.updateCharacteristic( + this.platform.eve.Characteristics.LastActivation, + Math.max(0, this.accessory.context.lastActivation - this.historyService.getInitialTime()), + ); + this.historyService.addEntry(entry); + } + }); this.updateHistory(); } - async updateHistory() : Promise{ + async updateHistory(): Promise { const motion = Number(this.CurrentPosition) > 0 ? 1 : 0; - this.historyService.addEntry ({ - time: Math.round(new Date().valueOf()/1000), - motion: motion + this.historyService.addEntry({ + time: Math.round(new Date().valueOf() / 1000), + motion: motion, }); - setTimeout(() => { - this.updateHistory(); - }, 10 * 60 * 1000); + setTimeout( + () => { + this.updateHistory(); + }, + 10 * 60 * 1000, + ); } - + /** * Parse the device status from the SwitchBot api */ @@ -301,8 +305,9 @@ export class Curtain { await this.openAPIparseStatus(); } else { await this.offlineOff(); - this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` - + ` ${this.device.connectionType}, parseStatus will not happen.`); + this.debugWarnLog( + `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + ` ${this.device.connectionType}, parseStatus will not happen.`, + ); } } @@ -394,8 +399,8 @@ export class Curtain { this.debugLog(); } this.debugLog( - `${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.lightLevel},` - + ` CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`, + `${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.lightLevel},` + + ` CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`, ); } // Battery @@ -405,8 +410,9 @@ export class Curtain { } else { this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL; } - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel},` - + ` StatusLowBattery: ${this.StatusLowBattery}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel},` + ` StatusLowBattery: ${this.StatusLowBattery}`, + ); } async openAPIparseStatus(): Promise { @@ -473,8 +479,10 @@ export class Curtain { await this.openAPIRefreshStatus(); } else { await this.offlineOff(); - this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` - + ` ${this.device.connectionType}, refreshStatus will not happen.`); + this.debugWarnLog( + `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + + ` ${this.device.connectionType}, refreshStatus will not happen.`, + ); } } @@ -499,8 +507,10 @@ export class Curtain { // Set an event hander switchbot.onadvertisement = async (ad: any) => { this.address = ad.address; - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Config BLE Address: ${this.device.bleMac},` - + ` BLE Address Found: ${this.address}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} Config BLE Address: ${this.device.bleMac},` + + ` BLE Address Found: ${this.address}`, + ); this.serviceData = ad.serviceData; this.calibration = ad.serviceData.calibration; this.battery = ad.serviceData.battery; @@ -511,7 +521,8 @@ export class Curtain { this.debugLog( `${this.device.deviceType}: ${this.accessory.displayName} calibration: ${ad.serviceData.calibration}, ` + `position: ${ad.serviceData.position}, lightLevel: ${ad.serviceData.lightLevel}, battery: ${ad.serviceData.battery}, ` + - `inMotion: ${ad.serviceData.inMotion}`); + `inMotion: ${ad.serviceData.inMotion}`, + ); if (this.serviceData) { this.connected = true; @@ -531,8 +542,10 @@ export class Curtain { }) .catch(async (e: any) => { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLERefreshStatus with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed BLERefreshStatus with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + ); await this.BLERefreshConnection(switchbot); }); } else { @@ -546,23 +559,24 @@ export class Curtain { const { body, statusCode, headers } = await request(`${Devices}/${this.device.deviceId}/status`, { headers: this.platform.generateHeaders(), }); - const deviceStatus = await body.json(); + const deviceStatus: any = await body.json(); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`); this.statusCode(statusCode); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`); - this.debugLog( - `${this.device.deviceType}: ${this.accessory.displayName - } refreshStatus: ${JSON.stringify(deviceStatus)}`, - ); + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} refreshStatus: ${JSON.stringify(deviceStatus)}`); this.slidePosition = deviceStatus.body.slidePosition; this.moving = deviceStatus.body.moving; this.brightness = deviceStatus.body.brightness; + this.Battery = deviceStatus.body.battery; + this.Version = deviceStatus.body.version; this.openAPIparseStatus(); this.updateHomeKitCharacteristics(); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + ); } } @@ -575,8 +589,9 @@ export class Curtain { await this.openAPIpushChanges(); } else { await this.offlineOff(); - this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` - + ` ${this.device.connectionType}, pushChanges will not happen.`); + this.debugWarnLog( + `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + ` ${this.device.connectionType}, pushChanges will not happen.`, + ); } // Refresh the status from the API interval(15000) @@ -618,8 +633,10 @@ export class Curtain { }) .catch(async (e: any) => { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushChanges with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushChanges with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + ); await this.BLEPushConnection(); throw new Error('Connection error'); }); @@ -630,7 +647,8 @@ export class Curtain { await this.BLEPushConnection(); } } else { - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No BLEpushChanges, CurrentPosition & TargetPosition Are the Same.` + + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} No BLEpushChanges, CurrentPosition & TargetPosition Are the Same.` + ` CurrentPosition: ${this.CurrentPosition}, TargetPosition ${this.TargetPosition}`, ); } @@ -658,7 +676,7 @@ export class Curtain { async openAPIpushChanges(): Promise { this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIpushChanges`); - if ((this.TargetPosition !== this.CurrentPosition) || this.device.disableCaching) { + if (this.TargetPosition !== this.CurrentPosition || this.device.disableCaching) { this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Pushing ${this.TargetPosition}`); const adjustedTargetPosition = 100 - Number(this.TargetPosition); if (Number(this.TargetPosition) > 50) { @@ -676,9 +694,9 @@ export class Curtain { this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Mode: ${this.Mode}`); const adjustedMode = this.setPositionMode || 'ff'; const bodyChange = JSON.stringify({ - 'command': 'setPosition', - 'parameter': `0,${adjustedMode},${adjustedTargetPosition}`, - 'commandType': 'command', + command: 'setPosition', + parameter: `0,${adjustedMode},${adjustedTargetPosition}`, + commandType: 'command', }); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${bodyChange},`); try { @@ -687,19 +705,22 @@ export class Curtain { method: 'POST', headers: this.platform.generateHeaders(), }); - const deviceStatus = await body.json(); + const deviceStatus: any = await body.json(); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`); this.statusCode(statusCode); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIpushChanges with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed openAPIpushChanges with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, ); } } else { - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No OpenAPI Changes, CurrentPosition & TargetPosition Are the Same.` - + ` CurrentPosition: ${this.CurrentPosition}, TargetPosition ${this.TargetPosition}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} No OpenAPI Changes, CurrentPosition & TargetPosition Are the Same.` + + ` CurrentPosition: ${this.CurrentPosition}, TargetPosition ${this.TargetPosition}`, + ); } } @@ -791,37 +812,37 @@ export class Curtain { } this.accessory.context.CurrentAmbientLightLevel = this.CurrentAmbientLightLevel; this.lightSensorService?.updateCharacteristic(this.platform.Characteristic.CurrentAmbientLightLevel, this.CurrentAmbientLightLevel); - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}` - + ` updateCharacteristic CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`); - if (this.device.history) { - this.historyService?.addEntry ({ - time: Math.round(new Date().valueOf()/1000), - lux: this.CurrentAmbientLightLevel - }); - } + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName}` + + ` updateCharacteristic CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`, + ); + if (this.device.history) { + this.historyService?.addEntry({ + time: Math.round(new Date().valueOf() / 1000), + lux: this.CurrentAmbientLightLevel, + }); + } } } - if (this.BLE) { - if (this.BatteryLevel === undefined) { - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}`); - } else { - if (this.device.mqttURL) { - this.mqttPublish('BatteryLevel', this.BatteryLevel); - } - this.accessory.context.BatteryLevel = this.BatteryLevel; - this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, this.BatteryLevel); - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic BatteryLevel: ${this.BatteryLevel}`); + if (this.BatteryLevel === undefined) { + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}`); + } else { + if (this.device.mqttURL) { + this.mqttPublish('BatteryLevel', this.BatteryLevel); } - if (this.StatusLowBattery === undefined) { - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} StatusLowBattery: ${this.StatusLowBattery}`); - } else { - if (this.device.mqttURL) { - this.mqttPublish('StatusLowBattery', this.StatusLowBattery); - } - this.accessory.context.StatusLowBattery = this.StatusLowBattery; - this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, this.StatusLowBattery); - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic StatusLowBattery: ${this.StatusLowBattery}`); + this.accessory.context.BatteryLevel = this.BatteryLevel; + this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, this.BatteryLevel); + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic BatteryLevel: ${this.BatteryLevel}`); + } + if (this.StatusLowBattery === undefined) { + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} StatusLowBattery: ${this.StatusLowBattery}`); + } else { + if (this.device.mqttURL) { + this.mqttPublish('StatusLowBattery', this.StatusLowBattery); } + this.accessory.context.StatusLowBattery = this.StatusLowBattery; + this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, this.StatusLowBattery); + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic StatusLowBattery: ${this.StatusLowBattery}`); } } @@ -970,8 +991,10 @@ export class Curtain { if (this.updateRate > device.scanDuration) { this.scanDuration = this.updateRate; if (this.BLE) { - this.warnLog(`${this.device.deviceType}: ` - + `${this.accessory.displayName} scanDuration is less than updateRate, overriding scanDuration with updateRate`); + this.warnLog( + `${this.device.deviceType}: ` + + `${this.accessory.displayName} scanDuration is less than updateRate, overriding scanDuration with updateRate`, + ); } } else { this.scanDuration = this.accessory.context.scanDuration = device.scanDuration; @@ -1007,8 +1030,10 @@ export class Curtain { this.offlineOff(); break; case 171: - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` - + `Hub: ${this.device.hubDeviceId}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` + + `Hub: ${this.device.hubDeviceId}`, + ); this.offlineOff(); break; case 190: @@ -1024,8 +1049,10 @@ export class Curtain { this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Request successful, statusCode: ${statusCode}`); break; default: - this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode: ` - + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`); + this.infoLog( + `${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode: ` + + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`, + ); } } @@ -1043,23 +1070,24 @@ export class Curtain { if (!this.device.curtain?.hide_lightsensor) { this.lightSensorService?.updateCharacteristic(this.platform.Characteristic.CurrentAmbientLightLevel, e); } - if (this.BLE) { - this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, e); - this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, e); - } + this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, e); + this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, e); //throw new this.platform.api.hap.HapStatusError(HAPStatus.SERVICE_COMMUNICATION_FAILURE); } FirmwareRevision(accessory: PlatformAccessory, device: device & devicesConfig): CharacteristicValue { let FirmwareRevision: string; - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}` - + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName}` + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`, + ); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} device.firmware: ${device.firmware}`); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`); - if (accessory.context.FirmwareRevision) { - FirmwareRevision = accessory.context.FirmwareRevision; - } else if (device.firmware) { + if (device.firmware) { FirmwareRevision = device.firmware; + } else if (device.version) { + FirmwareRevision = JSON.stringify(device.version); + } if (accessory.context.FirmwareRevision) { + FirmwareRevision = accessory.context.FirmwareRevision; } else { FirmwareRevision = this.platform.version; } @@ -1087,23 +1115,23 @@ export class Curtain { if (!this.device.curtain?.hide_lightsensor) { if (this.accessory.context.CurrentAmbientLightLevel !== undefined) { - this.CurrentAmbientLightLevel = this.accessory.context.CurrentAmbientLightLevel; + this.CurrentAmbientLightLevel = this.accessory.context.CurrentAmbientLightLevel; } } if (this.BLE) { if (this.accessory.context.BatteryLevel === undefined) { - this.BatteryLevel = 100; + this.BatteryLevel = 100; } else { - this.BatteryLevel = this.accessory.context.BatteryLevel; + this.BatteryLevel = this.accessory.context.BatteryLevel; } if (this.accessory.context.StatusLowBattery === undefined) { - this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL; + this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL; } else { - this.StatusLowBattery = this.accessory.context.StatusLowBattery; + this.StatusLowBattery = this.accessory.context.StatusLowBattery; } } - + if (this.device.history === true) { // initialize when this accessory is newly created. this.accessory.context.lastActivation = this.accessory.context.lastActivation ?? 0; @@ -1159,7 +1187,7 @@ export class Curtain { config['maxRetry'] = device.maxRetry; } if (Object.entries(config).length !== 0) { - this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); + this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); } } diff --git a/src/device/hub.ts b/src/device/hub.ts index aa5f7ed8..cd23ba3b 100644 --- a/src/device/hub.ts +++ b/src/device/hub.ts @@ -3,20 +3,25 @@ import { interval } from 'rxjs'; import { request } from 'undici'; import { Context } from 'vm'; import { SwitchBotPlatform } from '../platform'; -import { Devices, device, devicesConfig } from '../settings'; +import { Devices, device, deviceStatus, devicesConfig } from '../settings'; import { sleep } from '../utils'; export class Hub { // Services hubTemperatureSensor: Service; hubHumiditySensor: Service; + hubLightSensor: Service; // Characteristic Values CurrentRelativeHumidity!: number; CurrentTemperature!: number; + CurrentAmbientLightLevel!: number; // OpenAPI Others + Version: deviceStatus['version']; deviceStatus!: any; //deviceStatusResponse; + lightLevel!: number; + spaceBetweenLevels!: number; // Config set_minStep!: number; @@ -31,10 +36,15 @@ export class Hub { private readonly BLE = this.device.connectionType === 'BLE' || this.device.connectionType === 'BLE/OpenAPI'; private readonly OpenAPI = this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'BLE/OpenAPI'; - constructor(private readonly platform: SwitchBotPlatform, private accessory: PlatformAccessory, public device: device & devicesConfig) { + constructor( + private readonly platform: SwitchBotPlatform, + private accessory: PlatformAccessory, + public device: device & devicesConfig, + ) { // default placeholders this.logs(device); this.refreshRate(device); + this.config(device); this.CurrentRelativeHumidity = accessory.context.CurrentRelativeHumidity; this.CurrentTemperature = accessory.context.CurrentTemperature; @@ -56,11 +66,14 @@ export class Hub { // you can create multiple services for each accessory (this.hubTemperatureSensor = accessory.getService(this.platform.Service.TemperatureSensor) || accessory.addService(this.platform.Service.TemperatureSensor)), - `${device.deviceName} ${device.deviceType}`; + `${device.deviceName} ${device.deviceType}`; (this.hubHumiditySensor = accessory.getService(this.platform.Service.HumiditySensor) || accessory.addService(this.platform.Service.HumiditySensor)), - `${device.deviceName} ${device.deviceType}`; + `${device.deviceName} ${device.deviceType}`; + + (this.hubLightSensor = accessory.getService(this.platform.Service.LightSensor) || accessory.addService(this.platform.Service.LightSensor)), + `${device.deviceName} ${device.deviceType}`; // To avoid "Cannot add a Service with the same UUID another Service without also defining a unique 'subtype' property." error, // when creating multiple services of the same type, you need to use the following syntax to specify a name and subtype id: @@ -78,10 +91,30 @@ export class Hub { this.hubHumiditySensor.addCharacteristic(this.platform.Characteristic.ConfiguredName, accessory.displayName); } + this.hubLightSensor.setCharacteristic(this.platform.Characteristic.Name, accessory.displayName); + if (!this.hubLightSensor.testCharacteristic(this.platform.Characteristic.ConfiguredName)) { + this.hubLightSensor.addCharacteristic(this.platform.Characteristic.ConfiguredName, accessory.displayName); + } + // each service must implement at-minimum the "required characteristics" for the given service type // see https://developers.homebridge.io/#/service/WindowCovering - // console.log(this.hubHumiditySensor); + // Temperature Sensor Service + if (device.hub?.hide_temperature) { + this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Removing Temperature Sensor Service`); + this.hubTemperatureSensor = this.hubTemperatureSensor.setCharacteristic(this.platform.Characteristic.CurrentTemperature, false); + accessory.removeService(this.hubTemperatureSensor!); + } else if (!this.hubTemperatureSensor) { + this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Add Temperature Sensor Service`); + (this.hubTemperatureSensor = + accessory.getService(this.platform.Service.TemperatureSensor) || accessory.addService(this.platform.Service.TemperatureSensor)), + `${device.deviceName} ${device.deviceType}`; + + this.hubTemperatureSensor.setCharacteristic(this.platform.Characteristic.Name, `${accessory.displayName} Temperature Sensor`); + this.hubTemperatureSensor.setCharacteristic(this.platform.Characteristic.ConfiguredName, `${accessory.displayName} Temperature Sensor`); + } else { + this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Temperature Sensor Service Not Added`); + } // Humidity Sensor Service if (device.hub?.hide_humidity) { @@ -92,7 +125,7 @@ export class Hub { this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Add Humidity Sensor Service`); (this.hubHumiditySensor = accessory.getService(this.platform.Service.HumiditySensor) || accessory.addService(this.platform.Service.HumiditySensor)), - `${device.deviceName} ${device.deviceType}`; + `${device.deviceName} ${device.deviceType}`; this.hubHumiditySensor.setCharacteristic(this.platform.Characteristic.Name, `${accessory.displayName} Humidity Sensor`); this.hubHumiditySensor.setCharacteristic(this.platform.Characteristic.ConfiguredName, `${accessory.displayName} Humidity Sensor`); @@ -100,21 +133,20 @@ export class Hub { this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Humidity Sensor Service Not Added`); } - // Temperature Sensor Service - if (device.hub?.hide_temperature) { - this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Removing Temperature Sensor Service`); - this.hubTemperatureSensor = this.hubTemperatureSensor.setCharacteristic(this.platform.Characteristic.CurrentTemperature, false); - accessory.removeService(this.hubTemperatureSensor!); - } else if (!this.hubTemperatureSensor) { - this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Add Temperature Sensor Service`); - (this.hubTemperatureSensor = - accessory.getService(this.platform.Service.TemperatureSensor) || accessory.addService(this.platform.Service.TemperatureSensor)), - `${device.deviceName} ${device.deviceType}`; + // Humidity Sensor Service + if (device.hub?.hide_lightsensor) { + this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Removing Light Sensor Service`); + this.hubLightSensor = this.hubLightSensor.setCharacteristic(this.platform.Characteristic.CurrentAmbientLightLevel, false); + accessory.removeService(this.hubLightSensor!); + } else if (!this.hubLightSensor) { + this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Add Light Sensor Service`); + (this.hubLightSensor = accessory.getService(this.platform.Service.LightSensor) || accessory.addService(this.platform.Service.LightSensor)), + `${device.deviceName} ${device.deviceType}`; - this.hubTemperatureSensor.setCharacteristic(this.platform.Characteristic.Name, `${accessory.displayName} Temperature Sensor`); - this.hubTemperatureSensor.setCharacteristic(this.platform.Characteristic.ConfiguredName, `${accessory.displayName} Temperature Sensor`); + this.hubLightSensor.setCharacteristic(this.platform.Characteristic.Name, `${accessory.displayName} Light Sensor`); + this.hubLightSensor.setCharacteristic(this.platform.Characteristic.ConfiguredName, `${accessory.displayName} Light Sensor`); } else { - this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Temperature Sensor Service Not Added`); + this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Light Sensor Service Not Added`); } // Update Homekit @@ -146,6 +178,105 @@ export class Hub { // this.infoLog(`temp: ${this.CurrentTemperature}, humidity: ${this.CurrentRelativeHumidity}`); this.hubTemperatureSensor.setCharacteristic(this.platform.Characteristic.CurrentTemperature, this.CurrentTemperature); this.hubHumiditySensor.setCharacteristic(this.platform.Characteristic.CurrentRelativeHumidity, this.CurrentRelativeHumidity); + + if (!this.device.curtain?.hide_lightsensor) { + this.set_minLux = this.minLux(); + this.set_maxLux = this.maxLux(); + this.spaceBetweenLevels = 19; + + // Brightness + switch (this.lightLevel) { + case 1: + this.CurrentAmbientLightLevel = this.set_minLux; + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.lightLevel}`); + break; + case 2: + this.CurrentAmbientLightLevel = (this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels; + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.lightLevel},` + + ` Calculation: ${(this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels}`, + ); + break; + case 3: + this.CurrentAmbientLightLevel = ((this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels) * 2; + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.lightLevel}`); + break; + case 4: + this.CurrentAmbientLightLevel = ((this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels) * 3; + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.lightLevel}`); + break; + case 5: + this.CurrentAmbientLightLevel = ((this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels) * 4; + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.lightLevel}`); + break; + case 6: + this.CurrentAmbientLightLevel = ((this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels) * 5; + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.lightLevel}`); + break; + case 7: + this.CurrentAmbientLightLevel = ((this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels) * 6; + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.lightLevel}`); + break; + case 8: + this.CurrentAmbientLightLevel = ((this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels) * 7; + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.lightLevel}`); + break; + case 9: + this.CurrentAmbientLightLevel = ((this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels) * 8; + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.lightLevel}`); + break; + case 10: + this.CurrentAmbientLightLevel = ((this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels) * 9; + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.lightLevel}`); + break; + case 11: + this.CurrentAmbientLightLevel = ((this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels) * 10; + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.lightLevel}`); + break; + case 12: + this.CurrentAmbientLightLevel = ((this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels) * 11; + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.lightLevel}`); + break; + case 13: + this.CurrentAmbientLightLevel = ((this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels) * 12; + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.lightLevel}`); + break; + case 14: + this.CurrentAmbientLightLevel = ((this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels) * 13; + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.lightLevel}`); + break; + case 15: + this.CurrentAmbientLightLevel = ((this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels) * 14; + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.lightLevel}`); + break; + case 16: + this.CurrentAmbientLightLevel = ((this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels) * 15; + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.lightLevel}`); + break; + case 17: + this.CurrentAmbientLightLevel = ((this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels) * 16; + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.lightLevel}`); + break; + case 18: + this.CurrentAmbientLightLevel = ((this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels) * 17; + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.lightLevel}`); + break; + case 19: + this.CurrentAmbientLightLevel = ((this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels) * 18; + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.lightLevel}`); + break; + case 20: + default: + this.CurrentAmbientLightLevel = this.set_maxLux; + this.debugLog(); + } + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.lightLevel},` + + ` CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`, + ); + } + + this.hubLightSensor.setCharacteristic(this.platform.Characteristic.CurrentAmbientLightLevel, this.CurrentAmbientLightLevel); } async refreshStatus(): Promise { @@ -163,22 +294,22 @@ export class Hub { const { body, statusCode, headers } = await request(`${Devices}/${this.device.deviceId}/status`, { headers: this.platform.generateHeaders(), }); - const deviceStatus = await body.json(); + const deviceStatus: any = await body.json(); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`); this.statusCode(statusCode); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`); - this.debugLog( - `${this.device.deviceType}: ${this.accessory.displayName - } refreshStatus: ${JSON.stringify(deviceStatus)}`, - ); + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} refreshStatus: ${JSON.stringify(deviceStatus)}`); this.CurrentTemperature = deviceStatus.body.temperature; this.CurrentRelativeHumidity = deviceStatus.body.humidity; + this.lightLevel = deviceStatus.body.lightLevel; this.openAPIparseStatus(); this.updateHomeKitCharacteristics(); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + ); } } @@ -207,20 +338,31 @@ export class Hub { */ async updateHomeKitCharacteristics(): Promise { + if (this.CurrentTemperature === undefined) { + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentTemperature: ${this.CurrentTemperature}`); + } else { + this.accessory.context.CurrentTemperature = this.CurrentTemperature; + this.hubTemperatureSensor?.updateCharacteristic(this.platform.Characteristic.CurrentTemperature, this.CurrentTemperature); + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic CurrentTemperature: ${this.CurrentTemperature}`); + } if (this.CurrentRelativeHumidity === undefined) { this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentRelativeHumidity: ${this.CurrentRelativeHumidity}`); } else { this.accessory.context.CurrentRelativeHumidity = this.CurrentRelativeHumidity; this.hubHumiditySensor?.updateCharacteristic(this.platform.Characteristic.CurrentRelativeHumidity, this.CurrentRelativeHumidity); - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic CurrentRelativeHumidity: ${this.CurrentRelativeHumidity}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} ` + `updateCharacteristic CurrentRelativeHumidity: ${this.CurrentRelativeHumidity}`, + ); } - - if (this.CurrentTemperature === undefined) { - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentTemperature: ${this.CurrentTemperature}`); + if (this.CurrentAmbientLightLevel === undefined) { + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`); } else { - this.accessory.context.CurrentTemperature = this.CurrentTemperature; - this.hubTemperatureSensor?.updateCharacteristic(this.platform.Characteristic.CurrentTemperature, this.CurrentTemperature); - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic CurrentTemperature: ${this.CurrentTemperature}`); + this.accessory.context.CurrentAmbientLightLevel = this.CurrentAmbientLightLevel; + this.hubLightSensor?.updateCharacteristic(this.platform.Characteristic.CurrentAmbientLightLevel, this.CurrentAmbientLightLevel); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} ` + + `updateCharacteristic CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`, + ); } } @@ -240,8 +382,10 @@ export class Hub { this.offlineOff(); break; case 171: - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` - + `Hub: ${this.device.hubDeviceId}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` + + `Hub: ${this.device.hubDeviceId}`, + ); this.offlineOff(); break; case 190: @@ -257,8 +401,10 @@ export class Hub { this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Request successful, statusCode: ${statusCode}`); break; default: - this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode: ` - + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`); + this.infoLog( + `${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode: ` + + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`, + ); } } @@ -271,6 +417,25 @@ export class Hub { async apiError(e: any): Promise { this.hubTemperatureSensor?.updateCharacteristic(this.platform.Characteristic.CurrentTemperature, e); this.hubHumiditySensor?.updateCharacteristic(this.platform.Characteristic.CurrentRelativeHumidity, e); + this.hubLightSensor?.updateCharacteristic(this.platform.Characteristic.CurrentAmbientLightLevel, e); + } + + minLux(): number { + if (this.device.curtain?.set_minLux) { + this.set_minLux = this.device.curtain?.set_minLux; + } else { + this.set_minLux = 1; + } + return this.set_minLux; + } + + maxLux(): number { + if (this.device.curtain?.set_maxLux) { + this.set_maxLux = this.device.curtain?.set_maxLux; + } else { + this.set_maxLux = 6001; + } + return this.set_maxLux; } FirmwareRevision(accessory: PlatformAccessory, device: device & devicesConfig): CharacteristicValue { @@ -280,10 +445,12 @@ export class Hub { ); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} device.firmware: ${device.firmware}`); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`); - if (accessory.context.FirmwareRevision) { - FirmwareRevision = accessory.context.FirmwareRevision; - } else if (device.firmware) { + if (device.firmware) { FirmwareRevision = device.firmware; + } else if (device.version) { + FirmwareRevision = JSON.stringify(device.version); + } else if (accessory.context.FirmwareRevision) { + FirmwareRevision = accessory.context.FirmwareRevision; } else { FirmwareRevision = this.platform.version; } @@ -309,6 +476,28 @@ export class Hub { } } + async config(device: device & devicesConfig): Promise { + let config = {}; + if (device.hub) { + config = device.hub; + } + if (device.connectionType !== undefined) { + config['connectionType'] = device.connectionType; + } + if (device.external !== undefined) { + config['external'] = device.external; + } + if (device.logging !== undefined) { + config['logging'] = device.logging; + } + if (device.refreshRate !== undefined) { + config['refreshRate'] = device.refreshRate; + } + if (Object.entries(config).length !== 0) { + this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); + } + } + async logs(device: device & devicesConfig): Promise { if (this.platform.debugMode) { this.deviceLogging = this.accessory.context.logging = 'debugMode'; diff --git a/src/device/humidifier.ts b/src/device/humidifier.ts index e8789d24..e43a9a21 100644 --- a/src/device/humidifier.ts +++ b/src/device/humidifier.ts @@ -1,3 +1,4 @@ +/* eslint-disable brace-style */ import { Context } from 'vm'; import { request } from 'undici'; import { sleep } from '../utils'; @@ -54,16 +55,20 @@ export class Humidifier { doHumidifierUpdate!: Subject; // Connection - private readonly BLE = (this.device.connectionType === 'BLE' || this.device.connectionType === 'BLE/OpenAPI'); - private readonly OpenAPI = (this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'BLE/OpenAPI'); - - constructor(private readonly platform: SwitchBotPlatform, private accessory: PlatformAccessory, public device: device & devicesConfig) { + private readonly BLE = this.device.connectionType === 'BLE' || this.device.connectionType === 'BLE/OpenAPI'; + private readonly OpenAPI = this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'BLE/OpenAPI'; + + constructor( + private readonly platform: SwitchBotPlatform, + private accessory: PlatformAccessory, + public device: device & devicesConfig, + ) { // default placeholders this.logs(device); this.scan(device); this.refreshRate(device); - this.config(device); this.context(); + this.config(device); // this is subject we use to track when we need to POST changes to the SwitchBot API this.doHumidifierUpdate = new Subject(); @@ -184,8 +189,10 @@ export class Humidifier { await this.pushChanges(); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType} Connection,` - + ` Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType} Connection,` + + ` Error Message: ${JSON.stringify(e.message)}`, + ); } this.humidifierUpdateInProgress = false; }); @@ -203,8 +210,9 @@ export class Humidifier { await this.openAPIparseStatus(); } else { await this.offlineOff(); - this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` - + ` ${this.device.connectionType}, parseStatus will not happen.`); + this.debugWarnLog( + `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + ` ${this.device.connectionType}, parseStatus will not happen.`, + ); } } @@ -254,14 +262,16 @@ export class Humidifier { this.CurrentHumidifierDehumidifierState = this.platform.Characteristic.CurrentHumidifierDehumidifierState.HUMIDIFYING; } } - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}` - + ` TargetHumidifierDehumidifierState: ${this.TargetHumidifierDehumidifierState}`); this.debugLog( - `${this.device.deviceType}: ${this.accessory.displayName}` - + ` RelativeHumidityHumidifierThreshold: ${this.RelativeHumidityHumidifierThreshold}`, + `${this.device.deviceType}: ${this.accessory.displayName}` + ` TargetHumidifierDehumidifierState: ${this.TargetHumidifierDehumidifierState}`, + ); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName}` + + ` RelativeHumidityHumidifierThreshold: ${this.RelativeHumidityHumidifierThreshold}`, + ); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName}` + ` CurrentHumidifierDehumidifierState: ${this.CurrentHumidifierDehumidifierState}`, ); - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}` - + ` CurrentHumidifierDehumidifierState: ${this.CurrentHumidifierDehumidifierState}`); // Active switch (this.power) { case 'on': @@ -278,7 +288,6 @@ export class Humidifier { this.WaterLevel = 100; } this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} WaterLevel: ${this.WaterLevel}`); - } /** @@ -293,8 +302,10 @@ export class Humidifier { await this.openAPIRefreshStatus(); } else { await this.offlineOff(); - this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` - + ` ${this.device.connectionType}, refreshStatus will not happen.`); + this.debugWarnLog( + `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + + ` ${this.device.connectionType}, refreshStatus will not happen.`, + ); } } @@ -319,8 +330,10 @@ export class Humidifier { // Set an event hander switchbot.onadvertisement = async (ad: ad) => { this.address = ad.address; - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Config BLE Address: ${this.device.bleMac},` - + ` BLE Address Found: ${this.address}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} Config BLE Address: ${this.device.bleMac},` + + ` BLE Address Found: ${this.address}`, + ); this.serviceData = ad.serviceData; this.autoMode = ad.serviceData.autoMode; this.onState = ad.serviceData.onState; @@ -349,8 +362,10 @@ export class Humidifier { }) .catch(async (e: any) => { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLERefreshStatus with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed BLERefreshStatus with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + ); await this.BLERefreshConnection(switchbot); }); } else { @@ -364,14 +379,11 @@ export class Humidifier { const { body, statusCode, headers } = await request(`${Devices}/${this.device.deviceId}/status`, { headers: this.platform.generateHeaders(), }); - const deviceStatus = await body.json(); + const deviceStatus: any = await body.json(); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`); this.statusCode(statusCode); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`); - this.debugLog( - `${this.device.deviceType}: ${this.accessory.displayName - } refreshStatus: ${JSON.stringify(deviceStatus)}`, - ); + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} refreshStatus: ${JSON.stringify(deviceStatus)}`); this.auto = deviceStatus.body.auto; this.power = deviceStatus.body.power; this.lackWater = deviceStatus.body.lackWater; @@ -382,8 +394,10 @@ export class Humidifier { this.updateHomeKitCharacteristics(); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + ); } } @@ -393,14 +407,15 @@ export class Humidifier { async pushChanges(): Promise { if (!this.device.enableCloudService && this.OpenAPI) { this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} pushChanges enableCloudService: ${this.device.enableCloudService}`); - } else /*if (this.BLE) { + } /*if (this.BLE) { await this.BLEpushChanges(); - } else*/ if (this.OpenAPI && this.platform.config.credentials?.token) { + } else*/ else if (this.OpenAPI && this.platform.config.credentials?.token) { await this.openAPIpushChanges(); } else { await this.offlineOff(); - this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` - + ` ${this.device.connectionType}, pushChanges will not happen.`); + this.debugWarnLog( + `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + ` ${this.device.connectionType}, pushChanges will not happen.`, + ); } interval(5000) .pipe(take(1)) @@ -433,21 +448,25 @@ export class Humidifier { }) .catch(async (e: any) => { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushChanges with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushChanges with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + ); await this.BLEPushConnection(); }); } async openAPIpushChanges(): Promise { this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIpushChanges`); - if (this.TargetHumidifierDehumidifierState === this.platform.Characteristic.TargetHumidifierDehumidifierState.HUMIDIFIER && - this.Active === this.platform.Characteristic.Active.ACTIVE) { + if ( + this.TargetHumidifierDehumidifierState === this.platform.Characteristic.TargetHumidifierDehumidifierState.HUMIDIFIER && + this.Active === this.platform.Characteristic.Active.ACTIVE + ) { this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Pushing Manual: ${this.RelativeHumidityHumidifierThreshold}!`); const bodyChange = JSON.stringify({ - 'command': 'setMode', - 'parameter': `${this.RelativeHumidityHumidifierThreshold}`, - 'commandType': 'command', + command: 'setMode', + parameter: `${this.RelativeHumidityHumidifierThreshold}`, + commandType: 'command', }); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${bodyChange},`); try { @@ -456,14 +475,15 @@ export class Humidifier { method: 'POST', headers: this.platform.generateHeaders(), }); - const deviceStatus = await body.json(); + const deviceStatus: any = await body.json(); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`); this.statusCode(statusCode); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIpushChanges with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed openAPIpushChanges with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, ); } } else if ( @@ -481,13 +501,15 @@ export class Humidifier { */ async pushAutoChanges(): Promise { this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} pushAutoChanges`); - if (this.TargetHumidifierDehumidifierState === this.platform.Characteristic.TargetHumidifierDehumidifierState.HUMIDIFIER_OR_DEHUMIDIFIER && - this.Active === this.platform.Characteristic.Active.ACTIVE) { + if ( + this.TargetHumidifierDehumidifierState === this.platform.Characteristic.TargetHumidifierDehumidifierState.HUMIDIFIER_OR_DEHUMIDIFIER && + this.Active === this.platform.Characteristic.Active.ACTIVE + ) { this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Pushing Auto`); const bodyChange = JSON.stringify({ - 'command': 'setMode', - 'parameter': 'auto', - 'commandType': 'command', + command: 'setMode', + parameter: 'auto', + commandType: 'command', }); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${bodyChange},`); try { @@ -496,19 +518,22 @@ export class Humidifier { method: 'POST', headers: this.platform.generateHeaders(), }); - const deviceStatus = await body.json(); + const deviceStatus: any = await body.json(); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`); this.statusCode(statusCode); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushAutoChanges with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed pushAutoChanges with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, ); } } else { - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No pushAutoChanges.` + - `TargetHumidifierDehumidifierState: ${this.TargetHumidifierDehumidifierState}, Active: ${this.Active}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} No pushAutoChanges.` + + `TargetHumidifierDehumidifierState: ${this.TargetHumidifierDehumidifierState}, Active: ${this.Active}`, + ); } } @@ -520,9 +545,9 @@ export class Humidifier { if (this.Active === this.platform.Characteristic.Active.INACTIVE) { this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Pushing Off`); const bodyChange = JSON.stringify({ - 'command': 'turnOff', - 'parameter': 'default', - 'commandType': 'command', + command: 'turnOff', + parameter: 'default', + commandType: 'command', }); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${bodyChange},`); try { @@ -531,14 +556,15 @@ export class Humidifier { method: 'POST', headers: this.platform.generateHeaders(), }); - const deviceStatus = await body.json(); + const deviceStatus: any = await body.json(); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`); this.statusCode(statusCode); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushActiveChanges with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed pushActiveChanges with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, ); } } else { @@ -600,8 +626,9 @@ export class Humidifier { this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentRelativeHumidity: ${this.CurrentRelativeHumidity}`); } else { this.humidifierService.updateCharacteristic(this.platform.Characteristic.CurrentRelativeHumidity, this.CurrentRelativeHumidity); - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}` - + ` updateCharacteristic CurrentRelativeHumidity: ${this.CurrentRelativeHumidity}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName}` + ` updateCharacteristic CurrentRelativeHumidity: ${this.CurrentRelativeHumidity}`, + ); this.accessory.context.CurrentRelativeHumidity = this.CurrentRelativeHumidity; } if (this.OpenAPI) { @@ -614,23 +641,34 @@ export class Humidifier { } } if (this.CurrentHumidifierDehumidifierState === undefined) { - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}` - + ` CurrentHumidifierDehumidifierState: ${this.CurrentHumidifierDehumidifierState}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName}` + + ` CurrentHumidifierDehumidifierState: ${this.CurrentHumidifierDehumidifierState}`, + ); } else { - this.humidifierService.updateCharacteristic(this.platform.Characteristic.CurrentHumidifierDehumidifierState, - this.CurrentHumidifierDehumidifierState); - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}` + - ` updateCharacteristic CurrentHumidifierDehumidifierState: ${this.CurrentHumidifierDehumidifierState}`); + this.humidifierService.updateCharacteristic( + this.platform.Characteristic.CurrentHumidifierDehumidifierState, + this.CurrentHumidifierDehumidifierState, + ); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName}` + + ` updateCharacteristic CurrentHumidifierDehumidifierState: ${this.CurrentHumidifierDehumidifierState}`, + ); this.accessory.context.CurrentHumidifierDehumidifierState = this.CurrentHumidifierDehumidifierState; } if (this.TargetHumidifierDehumidifierState === undefined) { - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}` - + ` TargetHumidifierDehumidifierState: ${this.TargetHumidifierDehumidifierState}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName}` + ` TargetHumidifierDehumidifierState: ${this.TargetHumidifierDehumidifierState}`, + ); } else { - this.humidifierService.updateCharacteristic(this.platform.Characteristic.TargetHumidifierDehumidifierState, - this.TargetHumidifierDehumidifierState); - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}` + - ` updateCharacteristic TargetHumidifierDehumidifierState: ${this.TargetHumidifierDehumidifierState}`); + this.humidifierService.updateCharacteristic( + this.platform.Characteristic.TargetHumidifierDehumidifierState, + this.TargetHumidifierDehumidifierState, + ); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName}` + + ` updateCharacteristic TargetHumidifierDehumidifierState: ${this.TargetHumidifierDehumidifierState}`, + ); this.accessory.context.TargetHumidifierDehumidifierState = this.TargetHumidifierDehumidifierState; } if (this.Active === undefined) { @@ -641,13 +679,19 @@ export class Humidifier { this.accessory.context.Active = this.Active; } if (this.RelativeHumidityHumidifierThreshold === undefined) { - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}` - + ` RelativeHumidityHumidifierThreshold: ${this.RelativeHumidityHumidifierThreshold}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName}` + + ` RelativeHumidityHumidifierThreshold: ${this.RelativeHumidityHumidifierThreshold}`, + ); } else { - this.humidifierService.updateCharacteristic(this.platform.Characteristic.RelativeHumidityHumidifierThreshold, - this.RelativeHumidityHumidifierThreshold); - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}` + - ` updateCharacteristic RelativeHumidityHumidifierThreshold: ${this.RelativeHumidityHumidifierThreshold}`); + this.humidifierService.updateCharacteristic( + this.platform.Characteristic.RelativeHumidityHumidifierThreshold, + this.RelativeHumidityHumidifierThreshold, + ); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName}` + + ` updateCharacteristic RelativeHumidityHumidifierThreshold: ${this.RelativeHumidityHumidifierThreshold}`, + ); this.accessory.context.RelativeHumidityHumidifierThreshold = this.RelativeHumidityHumidifierThreshold; } if (!this.device.humidifier?.hide_temperature && !this.BLE) { @@ -743,8 +787,10 @@ export class Humidifier { this.offlineOff(); break; case 171: - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` - + `Hub: ${this.device.hubDeviceId}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` + + `Hub: ${this.device.hubDeviceId}`, + ); this.offlineOff(); break; case 190: @@ -760,8 +806,10 @@ export class Humidifier { this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Request successful, statusCode: ${statusCode}`); break; default: - this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode: ` - + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`); + this.infoLog( + `${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode: ` + + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`, + ); } } @@ -792,14 +840,17 @@ export class Humidifier { FirmwareRevision(accessory: PlatformAccessory, device: device & devicesConfig): CharacteristicValue { let FirmwareRevision: string; - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}` - + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName}` + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`, + ); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} device.firmware: ${device.firmware}`); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`); - if (accessory.context.FirmwareRevision) { - FirmwareRevision = accessory.context.FirmwareRevision; - } else if (device.firmware) { + if (device.firmware) { FirmwareRevision = device.firmware; + } else if (device.version) { + FirmwareRevision = JSON.stringify(device.version); + } else if (accessory.context.FirmwareRevision) { + FirmwareRevision = accessory.context.FirmwareRevision; } else { FirmwareRevision = this.platform.version; } @@ -882,7 +933,7 @@ export class Humidifier { config['offline'] = device.offline; } if (Object.entries(config).length !== 0) { - this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); + this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); } } diff --git a/src/device/iosensor.ts b/src/device/iosensor.ts index e5f55061..6602e8ee 100644 --- a/src/device/iosensor.ts +++ b/src/device/iosensor.ts @@ -29,6 +29,7 @@ export class IOSensor { StatusLowBattery?: CharacteristicValue; // OpenAPI Others + Version: deviceStatus['version']; Battery: deviceStatus['battery']; Temperature: deviceStatus['temperature']; Humidity: deviceStatus['humidity']; @@ -61,18 +62,22 @@ export class IOSensor { doIOSensorUpdate: Subject; // Connection - private readonly BLE = (this.device.connectionType === 'BLE' || this.device.connectionType === 'BLE/OpenAPI'); - private readonly OpenAPI = (this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'BLE/OpenAPI'); - - constructor(private readonly platform: SwitchBotPlatform, private accessory: PlatformAccessory, public device: device & devicesConfig) { + private readonly BLE = this.device.connectionType === 'BLE' || this.device.connectionType === 'BLE/OpenAPI'; + private readonly OpenAPI = this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'BLE/OpenAPI'; + + constructor( + private readonly platform: SwitchBotPlatform, + private accessory: PlatformAccessory, + public device: device & devicesConfig, + ) { // default placeholders this.logs(device); this.scan(device); this.refreshRate(device); - this.config(device); this.context(); this.setupHistoryService(device); this.setupMqtt(device); + this.config(device); // this is subject we use to track when we need to POST changes to the SwitchBot API this.doIOSensorUpdate = new Subject(); @@ -182,8 +187,9 @@ export class IOSensor { await this.openAPIparseStatus(); } else { await this.offlineOff(); - this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` - + ` ${this.device.connectionType}, parseStatus will not happen.`); + this.debugWarnLog( + `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + ` ${this.device.connectionType}, parseStatus will not happen.`, + ); } } @@ -213,7 +219,6 @@ export class IOSensor { } } - async openAPIparseStatus(): Promise { this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIparseStatus`); // Battery @@ -250,8 +255,10 @@ export class IOSensor { await this.openAPIRefreshStatus(); } else { await this.offlineOff(); - this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` - + ` ${this.device.connectionType}, refreshStatus will not happen.`); + this.debugWarnLog( + `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + + ` ${this.device.connectionType}, refreshStatus will not happen.`, + ); } } @@ -276,8 +283,10 @@ export class IOSensor { // Set an event hander switchbot.onadvertisement = async (ad: ad) => { this.address = ad.address; - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Config BLE Address: ${this.device.bleMac},` - + ` BLE Address Found: ${this.address}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} Config BLE Address: ${this.device.bleMac},` + + ` BLE Address Found: ${this.address}`, + ); if (ad.serviceData.humidity! > 0) { // reject unreliable data this.humidity = ad.serviceData.humidity; @@ -312,8 +321,10 @@ export class IOSensor { }) .catch(async (e: any) => { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLERefreshStatus with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed BLERefreshStatus with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + ); await this.BLERefreshConnection(switchbot); }); } else { @@ -327,23 +338,23 @@ export class IOSensor { const { body, statusCode, headers } = await request(`${Devices}/${this.device.deviceId}/status`, { headers: this.platform.generateHeaders(), }); - const deviceStatus = await body.json(); + const deviceStatus: any = await body.json(); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`); this.statusCode(statusCode); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`); - this.debugLog( - `${this.device.deviceType}: ${this.accessory.displayName - } refreshStatus: ${JSON.stringify(deviceStatus)}`, - ); + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} refreshStatus: ${JSON.stringify(deviceStatus)}`); this.Humidity = deviceStatus.body.humidity!; this.Temperature = deviceStatus.body.temperature!; - this.Battery = deviceStatus.body.battery!; + this.Battery = deviceStatus.body.battery; + this.Version = deviceStatus.body.version; this.openAPIparseStatus(); this.updateHomeKitCharacteristics(); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + ); } } @@ -359,8 +370,10 @@ export class IOSensor { } else { this.accessory.context.CurrentRelativeHumidity = this.CurrentRelativeHumidity; this.humidityservice?.updateCharacteristic(this.platform.Characteristic.CurrentRelativeHumidity, this.CurrentRelativeHumidity); - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}` - + ` updateCharacteristic CurrentRelativeHumidity: ${this.CurrentRelativeHumidity}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName}` + + ` updateCharacteristic CurrentRelativeHumidity: ${this.CurrentRelativeHumidity}`, + ); if (this.device.mqttURL) { mqttmessage.push(`"humidity": ${this.CurrentRelativeHumidity}`); } @@ -530,8 +543,10 @@ export class IOSensor { this.offlineOff(); break; case 171: - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` - + `Hub: ${this.device.hubDeviceId}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` + + `Hub: ${this.device.hubDeviceId}`, + ); this.offlineOff(); break; case 190: @@ -547,8 +562,10 @@ export class IOSensor { this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Request successful, statusCode: ${statusCode}`); break; default: - this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode: ` - + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`); + this.infoLog( + `${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode: ` + + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`, + ); } } @@ -572,14 +589,17 @@ export class IOSensor { FirmwareRevision(accessory: PlatformAccessory, device: device & devicesConfig): CharacteristicValue { let FirmwareRevision: string; - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}` - + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName}` + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`, + ); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} device.firmware: ${device.firmware}`); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`); - if (accessory.context.FirmwareRevision) { - FirmwareRevision = accessory.context.FirmwareRevision; - } else if (device.firmware) { + if (device.firmware) { FirmwareRevision = device.firmware; + } else if (device.version) { + FirmwareRevision = JSON.stringify(device.version); + } else if (accessory.context.FirmwareRevision) { + FirmwareRevision = accessory.context.FirmwareRevision; } else { FirmwareRevision = this.platform.version; } @@ -644,7 +664,7 @@ export class IOSensor { config['scanDuration'] = device.scanDuration; } if (Object.entries(config).length !== 0) { - this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); + this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); } } diff --git a/src/device/lightstrip.ts b/src/device/lightstrip.ts index a40de3a1..a124f793 100644 --- a/src/device/lightstrip.ts +++ b/src/device/lightstrip.ts @@ -1,3 +1,4 @@ +/* eslint-disable brace-style */ import { Context } from 'vm'; import { request } from 'undici'; import { sleep } from '../utils'; @@ -24,6 +25,7 @@ export class StripLight { ColorTemperature?: CharacteristicValue; // OpenAPI Others + Version: deviceStatus['version']; power: deviceStatus['power']; color: deviceStatus['color']; brightness: deviceStatus['brightness']; @@ -59,16 +61,21 @@ export class StripLight { doStripLightUpdate!: Subject; // Connection - private readonly BLE = (this.device.connectionType === 'BLE' || this.device.connectionType === 'BLE/OpenAPI'); - private readonly OpenAPI = (this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'BLE/OpenAPI'); - - constructor(private readonly platform: SwitchBotPlatform, private accessory: PlatformAccessory, public device: device & devicesConfig) { + private readonly BLE = this.device.connectionType === 'BLE' || this.device.connectionType === 'BLE/OpenAPI'; + private readonly OpenAPI = this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'BLE/OpenAPI'; + + constructor( + private readonly platform: SwitchBotPlatform, + private accessory: PlatformAccessory, + public device: device & devicesConfig, + ) { // default placeholders this.logs(device); this.scan(device); this.refreshRate(device); - this.config(device); this.context(); + this.config(device); + // this is subject we use to track when we need to POST changes to the SwitchBot API this.doStripLightUpdate = new Subject(); this.stripLightUpdateInProgress = false; @@ -91,7 +98,6 @@ export class StripLight { (this.lightBulbService = accessory.getService(this.platform.Service.Lightbulb) || accessory.addService(this.platform.Service.Lightbulb)), `${accessory.displayName} ${device.deviceType}`; - if (this.adaptiveLightingShift === -1 && this.accessory.context.adaptiveLighting) { this.accessory.removeService(this.lightBulbService); this.lightBulbService = this.accessory.addService(this.platform.Service.Lightbulb); @@ -202,8 +208,10 @@ export class StripLight { await this.pushChanges(); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType} Connection,` - + ` Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType} Connection,` + + ` Error Message: ${JSON.stringify(e.message)}`, + ); } this.stripLightUpdateInProgress = false; }); @@ -221,8 +229,9 @@ export class StripLight { await this.openAPIparseStatus(); } else { await this.offlineOff(); - this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` - + ` ${this.device.connectionType}, parseStatus will not happen.`); + this.debugWarnLog( + `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + ` ${this.device.connectionType}, parseStatus will not happen.`, + ); } } @@ -263,8 +272,9 @@ export class StripLight { this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} blue: ${JSON.stringify(blue)}`); const [hue, saturation] = rgb2hs(Number(red), Number(green), Number(blue)); - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}` - + ` hs: ${JSON.stringify(rgb2hs(Number(red), Number(green), Number(blue)))}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName}` + ` hs: ${JSON.stringify(rgb2hs(Number(red), Number(green), Number(blue)))}`, + ); // Hue this.Hue = hue; @@ -288,8 +298,10 @@ export class StripLight { await this.openAPIRefreshStatus(); } else { await this.offlineOff(); - this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` - + ` ${this.device.connectionType}, refreshStatus will not happen.`); + this.debugWarnLog( + `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + + ` ${this.device.connectionType}, refreshStatus will not happen.`, + ); } } @@ -314,8 +326,10 @@ export class StripLight { // Set an event hander switchbot.onadvertisement = async (ad: any) => { this.address = ad.address; - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Config BLE Address: ${this.device.bleMac},` - + ` BLE Address Found: ${this.address}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} Config BLE Address: ${this.device.bleMac},` + + ` BLE Address Found: ${this.address}`, + ); this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} serviceData: ${JSON.stringify(ad.serviceData)}`); this.serviceData = ad.serviceData; //this.state = ad.serviceData.state; @@ -350,8 +364,10 @@ export class StripLight { }) .catch(async (e: any) => { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLERefreshStatus with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed BLERefreshStatus with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + ); await this.BLERefreshConnection(switchbot); }); } else { @@ -365,14 +381,11 @@ export class StripLight { const { body, statusCode, headers } = await request(`${Devices}/${this.device.deviceId}/status`, { headers: this.platform.generateHeaders(), }); - const deviceStatus = await body.json(); + const deviceStatus: any = await body.json(); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`); this.statusCode(statusCode); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`); - this.debugLog( - `${this.device.deviceType}: ${this.accessory.displayName - } refreshStatus: ${JSON.stringify(deviceStatus)}`, - ); + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} refreshStatus: ${JSON.stringify(deviceStatus)}`); this.power = deviceStatus.body.power; this.color = deviceStatus.body.color; this.brightness = deviceStatus.body.brightness; @@ -380,8 +393,10 @@ export class StripLight { this.updateHomeKitCharacteristics(); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + ); } } @@ -398,14 +413,15 @@ export class StripLight { async pushChanges(): Promise { if (!this.device.enableCloudService && this.OpenAPI) { this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} pushChanges enableCloudService: ${this.device.enableCloudService}`); - } else /*if (this.BLE) { + } /*if (this.BLE) { await this.BLEpushChanges(); - } else*/ if (this.OpenAPI && this.platform.config.credentials?.token) { + } else*/ else if (this.OpenAPI && this.platform.config.credentials?.token) { await this.openAPIpushChanges(); } else { await this.offlineOff(); - this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` - + ` ${this.device.connectionType}, pushChanges will not happen.`); + this.debugWarnLog( + `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + ` ${this.device.connectionType}, pushChanges will not happen.`, + ); } // Refresh the status from the API interval(15000) @@ -451,8 +467,10 @@ export class StripLight { }) .catch(async (e: any) => { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushChanges with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushChanges with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + ); await this.BLEPushConnection(); }); // Push Brightness Update @@ -464,8 +482,9 @@ export class StripLight { await this.BLEpushRGBChanges(); } } else { - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No BLEpushChanges.` + `On: ${this.On}, ` - + `OnCached: ${this.accessory.context.On}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} No BLEpushChanges.` + `On: ${this.On}, ` + `OnCached: ${this.accessory.context.On}`, + ); } } @@ -494,13 +513,18 @@ export class StripLight { }) .catch(async (e: any) => { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushBrightnessChanges with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushBrightnessChanges with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + ); await this.BLEPushConnection(); }); } else { - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No BLEpushBrightnessChanges.` + `Brightness: ${this.Brightness}, ` - + `BrightnessCached: ${this.accessory.context.Brightness}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} No BLEpushBrightnessChanges.` + + `Brightness: ${this.Brightness}, ` + + `BrightnessCached: ${this.accessory.context.Brightness}`, + ); } } @@ -526,7 +550,7 @@ export class StripLight { id: this.device.bleMac, }) .then(async (device_list: any) => { - this.infoLog(`${this.accessory.displayName} Target RGB: ${this.Brightness, red, green, blue}`); + this.infoLog(`${this.accessory.displayName} Target RGB: ${(this.Brightness, red, green, blue)}`); return await device_list[0].setRGB(this.Brightness, red, green, blue); }) .then(() => { @@ -535,13 +559,17 @@ export class StripLight { }) .catch(async (e: any) => { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushRGBChanges with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushRGBChanges with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + ); await this.BLEPushConnection(); }); } else { - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No BLEpushRGBChanges. Hue: ${this.Hue}, ` - + `HueCached: ${this.accessory.context.Hue}, Saturation: ${this.Saturation}, SaturationCached: ${this.accessory.context.Saturation}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} No BLEpushRGBChanges. Hue: ${this.Hue}, ` + + `HueCached: ${this.accessory.context.Hue}, Saturation: ${this.Saturation}, SaturationCached: ${this.accessory.context.Saturation}`, + ); } } @@ -555,9 +583,9 @@ export class StripLight { command = 'turnOff'; }*/ const bodyChange = JSON.stringify({ - 'command': `${command}`, - 'parameter': 'default', - 'commandType': 'command', + command: `${command}`, + parameter: 'default', + commandType: 'command', }); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${bodyChange},`); try { @@ -566,19 +594,23 @@ export class StripLight { method: 'POST', headers: this.platform.generateHeaders(), }); - const deviceStatus = await body.json(); + const deviceStatus: any = await body.json(); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`); this.statusCode(statusCode); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIpushChanges with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed openAPIpushChanges with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, ); } } else { - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No openAPIpushChanges.` + `On: ${this.On}, ` - + `OnCached: ${this.accessory.context.On}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} No openAPIpushChanges.` + + `On: ${this.On}, ` + + `OnCached: ${this.accessory.context.On}`, + ); } // Push Hue & Saturation Update if (this.On) { @@ -599,9 +631,9 @@ export class StripLight { this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} rgb: ${JSON.stringify([red, green, blue])}`); // Make Push On request to the API const bodyChange = JSON.stringify({ - 'command': 'setColor', - 'parameter': `${red}:${green}:${blue}`, - 'commandType': 'command', + command: 'setColor', + parameter: `${red}:${green}:${blue}`, + commandType: 'command', }); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${bodyChange},`); try { @@ -610,19 +642,22 @@ export class StripLight { method: 'POST', headers: this.platform.generateHeaders(), }); - const deviceStatus = await body.json(); + const deviceStatus: any = await body.json(); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`); this.statusCode(statusCode); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushHueSaturationChanges with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed pushHueSaturationChanges with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, ); } } else { - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No pushHueSaturationChanges. Hue: ${this.Hue}, ` - + `HueCached: ${this.accessory.context.Hue}, Saturation: ${this.Saturation}, SaturationCached: ${this.accessory.context.Saturation}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} No pushHueSaturationChanges. Hue: ${this.Hue}, ` + + `HueCached: ${this.accessory.context.Hue}, Saturation: ${this.Saturation}, SaturationCached: ${this.accessory.context.Saturation}`, + ); } } @@ -630,9 +665,9 @@ export class StripLight { this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} pushBrightnessChanges`); if (this.Brightness !== this.accessory.context.Brightness) { const bodyChange = JSON.stringify({ - 'command': 'setBrightness', - 'parameter': `${this.Brightness}`, - 'commandType': 'command', + command: 'setBrightness', + parameter: `${this.Brightness}`, + commandType: 'command', }); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${bodyChange},`); try { @@ -641,19 +676,23 @@ export class StripLight { method: 'POST', headers: this.platform.generateHeaders(), }); - const deviceStatus = await body.json(); + const deviceStatus: any = await body.json(); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`); this.statusCode(statusCode); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushBrightnessChanges with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed pushBrightnessChanges with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, ); } } else { - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No pushBrightnessChanges,` + `Brightness: ${this.Brightness}, ` - + `BrightnessCached: ${this.accessory.context.Brightness}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} No pushBrightnessChanges,` + + `Brightness: ${this.Brightness}, ` + + `BrightnessCached: ${this.accessory.context.Brightness}`, + ); } } @@ -905,8 +944,10 @@ export class StripLight { this.offlineOff(); break; case 171: - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` - + `Hub: ${this.device.hubDeviceId}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` + + `Hub: ${this.device.hubDeviceId}`, + ); this.offlineOff(); break; case 190: @@ -922,8 +963,10 @@ export class StripLight { this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Request successful, statusCode: ${statusCode}`); break; default: - this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode: ` - + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`); + this.infoLog( + `${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode: ` + + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`, + ); } } @@ -943,14 +986,17 @@ export class StripLight { FirmwareRevision(accessory: PlatformAccessory, device: device & devicesConfig): CharacteristicValue { let FirmwareRevision: string; - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ` - + `accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} ` + `accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`, + ); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} device.firmware: ${device.firmware}`); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`); - if (accessory.context.FirmwareRevision) { - FirmwareRevision = accessory.context.FirmwareRevision; - } else if (device.firmware) { + if (device.firmware) { FirmwareRevision = device.firmware; + } else if (device.version) { + FirmwareRevision = JSON.stringify(device.version); + } else if (accessory.context.FirmwareRevision) { + FirmwareRevision = accessory.context.FirmwareRevision; } else { FirmwareRevision = this.platform.version; } @@ -1024,7 +1070,7 @@ export class StripLight { config['maxRetry'] = device.maxRetry; } if (Object.entries(config).length !== 0) { - this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); + this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); } } diff --git a/src/device/lock.ts b/src/device/lock.ts index da958bb8..a75e3016 100644 --- a/src/device/lock.ts +++ b/src/device/lock.ts @@ -1,3 +1,4 @@ +/* eslint-disable brace-style */ import { Context } from 'vm'; import { request } from 'undici'; import { sleep } from '../utils'; @@ -18,6 +19,8 @@ export class Lock { LockTargetState!: CharacteristicValue; // OpenAPI Others + Version: deviceStatus['version']; + Battery: deviceStatus['battery']; doorState!: deviceStatus['doorState']; lockState!: deviceStatus['lockState']; deviceStatus!: any; //deviceStatusResponse; @@ -38,8 +41,8 @@ export class Lock { doLockUpdate!: Subject; // Connection - private readonly BLE = (this.device.connectionType === 'BLE' || this.device.connectionType === 'BLE/OpenAPI'); - private readonly OpenAPI = (this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'BLE/OpenAPI'); + private readonly BLE = this.device.connectionType === 'BLE' || this.device.connectionType === 'BLE/OpenAPI'; + private readonly OpenAPI = this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'BLE/OpenAPI'; battery: any; calibration: any; status: any; @@ -50,13 +53,17 @@ export class Lock { unlocked_alarm: any; auto_lock_paused: any; - constructor(private readonly platform: SwitchBotPlatform, private accessory: PlatformAccessory, public device: device & devicesConfig) { + constructor( + private readonly platform: SwitchBotPlatform, + private accessory: PlatformAccessory, + public device: device & devicesConfig, + ) { // default placeholders this.logs(device); this.scan(device); this.refreshRate(device); - this.config(device); this.context(); + this.config(device); // this is subject we use to track when we need to POST changes to the SwitchBot API this.doLockUpdate = new Subject(); @@ -140,8 +147,10 @@ export class Lock { await this.pushChanges(); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType} Connection,` - + ` Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType} Connection,` + + ` Error Message: ${JSON.stringify(e.message)}`, + ); } this.lockUpdateInProgress = false; }); @@ -153,14 +162,15 @@ export class Lock { async parseStatus(): Promise { if (!this.device.enableCloudService && this.OpenAPI) { this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} parseStatus enableCloudService: ${this.device.enableCloudService}`); - } else/*if (this.BLE) { + } /*if (this.BLE) { await this.BLEparseStatus(); - } else*/ if (this.OpenAPI && this.platform.config.credentials?.token) { + } else*/ else if (this.OpenAPI && this.platform.config.credentials?.token) { await this.openAPIparseStatus(); } else { await this.offlineOff(); - this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` - + ` ${this.device.connectionType}, parseStatus will not happen.`); + this.debugWarnLog( + `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + ` ${this.device.connectionType}, parseStatus will not happen.`, + ); } } @@ -218,8 +228,10 @@ export class Lock { await this.openAPIRefreshStatus(); } else { await this.offlineOff(); - this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` - + ` ${this.device.connectionType}, refreshStatus will not happen.`); + this.debugWarnLog( + `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + + ` ${this.device.connectionType}, refreshStatus will not happen.`, + ); } } @@ -244,8 +256,10 @@ export class Lock { // Set an event hander switchbot.onadvertisement = async (ad: any) => { this.address = ad.address; - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Config BLE Address: ${this.device.bleMac},` - + ` BLE Address Found: ${this.address}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} Config BLE Address: ${this.device.bleMac},` + + ` BLE Address Found: ${this.address}`, + ); this.serviceData = ad.serviceData; this.battery = ad.serviceData.battery; this.calibration = ad.serviceData.calibration; @@ -260,7 +274,8 @@ export class Lock { this.debugLog( `${this.device.deviceType}: ${this.accessory.displayName} battery: ${ad.serviceData.battery}, ` + `calibration: ${ad.serviceData.calibration}, status: ${ad.serviceData.status}, battery: ${ad.serviceData.battery}, ` + - `door_open: ${ad.serviceData.door_open}`); + `door_open: ${ad.serviceData.door_open}`, + ); if (this.serviceData) { this.connected = true; @@ -280,8 +295,10 @@ export class Lock { }) .catch(async (e: any) => { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLERefreshStatus with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed BLERefreshStatus with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + ); await this.BLERefreshConnection(switchbot); }); } else { @@ -295,22 +312,23 @@ export class Lock { const { body, statusCode, headers } = await request(`${Devices}/${this.device.deviceId}/status`, { headers: this.platform.generateHeaders(), }); - const deviceStatus = await body.json(); + const deviceStatus: any = await body.json(); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`); this.statusCode(statusCode); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`); - this.debugLog( - `${this.device.deviceType}: ${this.accessory.displayName - } refreshStatus: ${JSON.stringify(deviceStatus)}`, - ); + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} refreshStatus: ${JSON.stringify(deviceStatus)}`); this.lockState = deviceStatus.body.lockState; this.doorState = deviceStatus.body.doorState; + this.Battery = deviceStatus.body.battery; + this.Version = deviceStatus.body.version; this.openAPIparseStatus(); this.updateHomeKitCharacteristics(); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + ); } } @@ -323,14 +341,15 @@ export class Lock { async pushChanges(): Promise { if (!this.device.enableCloudService && this.OpenAPI) { this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} pushChanges enableCloudService: ${this.device.enableCloudService}`); - } else /*if (this.BLE) { + } /*if (this.BLE) { await this.BLEpushChanges(); - } else*/ if (this.OpenAPI && this.platform.config.credentials?.token) { + } else*/ else if (this.OpenAPI && this.platform.config.credentials?.token) { await this.openAPIpushChanges(); } else { await this.offlineOff(); - this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` - + ` ${this.device.connectionType}, pushChanges will not happen.`); + this.debugWarnLog( + `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + ` ${this.device.connectionType}, pushChanges will not happen.`, + ); } // Refresh the status from the API interval(15000) @@ -344,8 +363,10 @@ export class Lock { async BLEpushChanges(): Promise { this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEpushChanges`); if (this.LockTargetState !== this.accessory.context.LockTargetState) { - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEpushChanges LockTargetState: ${this.LockTargetState}` - + ` LockTargetStateCached: ${this.accessory.context.LockTargetState}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} BLEpushChanges LockTargetState: ${this.LockTargetState}` + + ` LockTargetStateCached: ${this.accessory.context.LockTargetState}`, + ); const switchbot = await this.platform.connectBLE(); // Convert to BLE Address this.device.bleMac = this.device @@ -364,14 +385,17 @@ export class Lock { }) .catch(async (e: any) => { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushChanges with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushChanges with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + ); await this.BLEPushConnection(); }); } else { this.debugLog( - `${this.device.deviceType}: ${this.accessory.displayName} No BLEpushChanges.` + `LockTargetState: ${this.LockTargetState}, ` - + `LockTargetStateCached: ${this.accessory.context.LockTargetState}`, + `${this.device.deviceType}: ${this.accessory.displayName} No BLEpushChanges.` + + `LockTargetState: ${this.LockTargetState}, ` + + `LockTargetStateCached: ${this.accessory.context.LockTargetState}`, ); } } @@ -386,9 +410,9 @@ export class Lock { command = 'unlock'; } const bodyChange = JSON.stringify({ - 'command': `${command}`, - 'parameter': 'default', - 'commandType': 'command', + command: `${command}`, + parameter: 'default', + commandType: 'command', }); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${bodyChange},`); try { @@ -397,19 +421,23 @@ export class Lock { method: 'POST', headers: this.platform.generateHeaders(), }); - const deviceStatus = await body.json(); + const deviceStatus: any = await body.json(); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`); this.statusCode(statusCode); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIpushChanges with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed openAPIpushChanges with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, ); } } else { - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No openAPIpushChanges.` + `LockTargetState: ${this.LockTargetState}, ` - + `LockTargetStateCached: ${this.accessory.context.LockTargetState}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} No openAPIpushChanges.` + + `LockTargetState: ${this.LockTargetState}, ` + + `LockTargetStateCached: ${this.accessory.context.LockTargetState}`, + ); } } @@ -526,8 +554,10 @@ export class Lock { this.offlineOff(); break; case 171: - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` - + `Hub: ${this.device.hubDeviceId}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` + + `Hub: ${this.device.hubDeviceId}`, + ); this.offlineOff(); break; case 190: @@ -543,8 +573,10 @@ export class Lock { this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Request successful, statusCode: ${statusCode}`); break; default: - this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode: ` - + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`); + this.infoLog( + `${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode: ` + + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`, + ); } } @@ -565,14 +597,17 @@ export class Lock { FirmwareRevision(accessory: PlatformAccessory, device: device & devicesConfig): CharacteristicValue { let FirmwareRevision: string; - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}` - + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName}` + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`, + ); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} device.firmware: ${device.firmware}`); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`); - if (accessory.context.FirmwareRevision) { - FirmwareRevision = accessory.context.FirmwareRevision; - } else if (device.firmware) { + if (device.firmware) { FirmwareRevision = device.firmware; + } else if (device.version) { + FirmwareRevision = JSON.stringify(device.version); + } else if (accessory.context.FirmwareRevision) { + FirmwareRevision = accessory.context.FirmwareRevision; } else { FirmwareRevision = this.platform.version; } @@ -618,7 +653,7 @@ export class Lock { config['scanDuration'] = device.scanDuration; } if (Object.entries(config).length !== 0) { - this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); + this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); } } diff --git a/src/device/meter.ts b/src/device/meter.ts index 615202f7..c3ee5fbe 100644 --- a/src/device/meter.ts +++ b/src/device/meter.ts @@ -1,14 +1,14 @@ -import { Context } from 'vm'; -import { hostname } from 'os'; -import { request } from 'undici'; -import { sleep } from '../utils'; -import { MqttClient } from 'mqtt'; -import { interval, Subject } from 'rxjs'; import { connectAsync } from 'async-mqtt'; +import { CharacteristicValue, PlatformAccessory, Service, Units } from 'homebridge'; +import { MqttClient } from 'mqtt'; +import { hostname } from 'os'; +import { Subject, interval } from 'rxjs'; import { skipWhile } from 'rxjs/operators'; +import { request } from 'undici'; +import { Context } from 'vm'; import { SwitchBotPlatform } from '../platform'; -import { Service, PlatformAccessory, Units, CharacteristicValue } from 'homebridge'; -import { device, devicesConfig, serviceData, ad, switchbot, temperature, deviceStatus, Devices } from '../settings'; +import { Devices, ad, device, deviceStatus, devicesConfig, serviceData, switchbot, temperature } from '../settings'; +import { sleep } from '../utils'; /** * Platform Accessory @@ -29,6 +29,8 @@ export class Meter { StatusLowBattery?: CharacteristicValue; // OpenAPI Others + Version: deviceStatus['version']; + Battery: deviceStatus['battery']; Temperature: deviceStatus['temperature']; Humidity: deviceStatus['humidity']; deviceStatus!: any; //deviceStatusResponse; @@ -60,18 +62,22 @@ export class Meter { doMeterUpdate: Subject; // Connection - private readonly BLE = (this.device.connectionType === 'BLE' || this.device.connectionType === 'BLE/OpenAPI'); - private readonly OpenAPI = (this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'BLE/OpenAPI'); - - constructor(private readonly platform: SwitchBotPlatform, private accessory: PlatformAccessory, public device: device & devicesConfig) { + private readonly BLE = this.device.connectionType === 'BLE' || this.device.connectionType === 'BLE/OpenAPI'; + private readonly OpenAPI = this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'BLE/OpenAPI'; + + constructor( + private readonly platform: SwitchBotPlatform, + private accessory: PlatformAccessory, + public device: device & devicesConfig, + ) { // default placeholders this.logs(device); this.scan(device); this.refreshRate(device); - this.config(device); this.context(); this.setupHistoryService(device); this.setupMqtt(device); + this.config(device); // this is subject we use to track when we need to POST changes to the SwitchBot API this.doMeterUpdate = new Subject(); @@ -149,11 +155,7 @@ export class Meter { } // Battery Service - if (!this.BLE) { - this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Removing Battery Service`); - this.batteryService = this.accessory.getService(this.platform.Service.Battery); - accessory.removeService(this.batteryService!); - } else if (this.BLE && !this.batteryService) { + if (!this.batteryService) { this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Add Battery Service`); (this.batteryService = this.accessory.getService(this.platform.Service.Battery) || this.accessory.addService(this.platform.Service.Battery)), `${accessory.displayName} Battery`; @@ -190,8 +192,9 @@ export class Meter { await this.openAPIparseStatus(); } else { await this.offlineOff(); - this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` - + ` ${this.device.connectionType}, parseStatus will not happen.`); + this.debugWarnLog( + `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + ` ${this.device.connectionType}, parseStatus will not happen.`, + ); } } @@ -223,6 +226,16 @@ export class Meter { async openAPIparseStatus(): Promise { this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIparseStatus`); + + // Battery + this.BatteryLevel = Number(this.Battery); + if (this.BatteryLevel < 15) { + this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW; + } else { + this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL; + } + this.debugLog(`${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}, StatusLowBattery: ${this.StatusLowBattery}`); + // Current Relative Humidity if (!this.device.meter?.hide_humidity) { this.CurrentRelativeHumidity = this.Humidity!; @@ -248,8 +261,10 @@ export class Meter { await this.openAPIRefreshStatus(); } else { await this.offlineOff(); - this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` - + ` ${this.device.connectionType}, refreshStatus will not happen.`); + this.debugWarnLog( + `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + + ` ${this.device.connectionType}, refreshStatus will not happen.`, + ); } } @@ -274,8 +289,10 @@ export class Meter { // Set an event hander switchbot.onadvertisement = async (ad: ad) => { this.address = ad.address; - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Config BLE Address: ${this.device.bleMac},` - + ` BLE Address Found: ${this.address}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} Config BLE Address: ${this.device.bleMac},` + + ` BLE Address Found: ${this.address}`, + ); if (ad.serviceData.humidity! > 0) { // reject unreliable data this.humidity = ad.serviceData.humidity; @@ -310,8 +327,10 @@ export class Meter { }) .catch(async (e: any) => { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLERefreshStatus with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed BLERefreshStatus with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + ); await this.BLERefreshConnection(switchbot); }); } else { @@ -325,22 +344,23 @@ export class Meter { const { body, statusCode, headers } = await request(`${Devices}/${this.device.deviceId}/status`, { headers: this.platform.generateHeaders(), }); - const deviceStatus = await body.json(); + const deviceStatus: any = await body.json(); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`); this.statusCode(statusCode); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`); - this.debugLog( - `${this.device.deviceType}: ${this.accessory.displayName - } refreshStatus: ${JSON.stringify(deviceStatus)}`, - ); + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} refreshStatus: ${JSON.stringify(deviceStatus)}`); this.Humidity = deviceStatus.body.humidity!; this.Temperature = deviceStatus.body.temperature!; + this.Battery = deviceStatus.body.battery; + this.Version = deviceStatus.body.version; this.openAPIparseStatus(); this.updateHomeKitCharacteristics(); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + ); } } @@ -356,8 +376,10 @@ export class Meter { } else { this.accessory.context.CurrentRelativeHumidity = this.CurrentRelativeHumidity; this.humidityservice?.updateCharacteristic(this.platform.Characteristic.CurrentRelativeHumidity, this.CurrentRelativeHumidity); - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic` - + ` CurrentRelativeHumidity: ${this.CurrentRelativeHumidity}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic` + + ` CurrentRelativeHumidity: ${this.CurrentRelativeHumidity}`, + ); if (this.device.mqttURL) { mqttmessage.push(`"humidity": ${this.CurrentRelativeHumidity}`); } @@ -379,31 +401,30 @@ export class Meter { this.accessory.context.CurrentTemperature = this.CurrentTemperature; this.temperatureservice?.updateCharacteristic(this.platform.Characteristic.CurrentTemperature, this.CurrentTemperature); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic CurrentTemperature: ${this.CurrentTemperature}`); - } } - if (this.BLE) { - if (this.BatteryLevel === undefined) { - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}`); - } else { - if (this.device.mqttURL) { - mqttmessage.push(`"battery": ${this.BatteryLevel}`); - } - this.accessory.context.BatteryLevel = this.BatteryLevel; - this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, this.BatteryLevel); - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic BatteryLevel: ${this.BatteryLevel}`); + + if (this.BatteryLevel === undefined) { + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}`); + } else { + if (this.device.mqttURL) { + mqttmessage.push(`"battery": ${this.BatteryLevel}`); } - if (this.StatusLowBattery === undefined) { - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} StatusLowBattery: ${this.StatusLowBattery}`); - } else { - if (this.device.mqttURL) { - mqttmessage.push(`"lowBattery": ${this.StatusLowBattery}`); - } - this.accessory.context.StatusLowBattery = this.StatusLowBattery; - this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, this.StatusLowBattery); - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic StatusLowBattery: ${this.StatusLowBattery}`); + this.accessory.context.BatteryLevel = this.BatteryLevel; + this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, this.BatteryLevel); + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic BatteryLevel: ${this.BatteryLevel}`); + } + if (this.StatusLowBattery === undefined) { + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} StatusLowBattery: ${this.StatusLowBattery}`); + } else { + if (this.device.mqttURL) { + mqttmessage.push(`"lowBattery": ${this.StatusLowBattery}`); } + this.accessory.context.StatusLowBattery = this.StatusLowBattery; + this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, this.StatusLowBattery); + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic StatusLowBattery: ${this.StatusLowBattery}`); } + if (this.device.mqttURL) { this.mqttPublish(`{${mqttmessage.join(',')}}`); } @@ -530,8 +551,10 @@ export class Meter { this.offlineOff(); break; case 171: - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` - + `Hub: ${this.device.hubDeviceId}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` + + `Hub: ${this.device.hubDeviceId}`, + ); this.offlineOff(); break; case 190: @@ -547,8 +570,10 @@ export class Meter { this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Request successful, statusCode: ${statusCode}`); break; default: - this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode: ` - + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`); + this.infoLog( + `${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode: ` + + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`, + ); } } @@ -566,22 +591,23 @@ export class Meter { if (!this.device.meter?.hide_temperature) { this.temperatureservice?.updateCharacteristic(this.platform.Characteristic.CurrentTemperature, e); } - if (this.BLE) { - this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, e); - this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, e); - } + this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, e); + this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, e); } FirmwareRevision(accessory: PlatformAccessory, device: device & devicesConfig): CharacteristicValue { let FirmwareRevision: string; - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}` - + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName}` + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`, + ); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} device.firmware: ${device.firmware}`); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`); - if (accessory.context.FirmwareRevision) { - FirmwareRevision = accessory.context.FirmwareRevision; - } else if (device.firmware) { + if (device.firmware) { FirmwareRevision = device.firmware; + } else if (device.version) { + FirmwareRevision = JSON.stringify(device.version); + } else if (accessory.context.FirmwareRevision) { + FirmwareRevision = accessory.context.FirmwareRevision; } else { FirmwareRevision = this.platform.version; } @@ -599,18 +625,16 @@ export class Meter { } else { this.CurrentTemperature = this.accessory.context.CurrentTemperature; } - if (this.BLE) { - if (this.BatteryLevel === undefined) { - this.BatteryLevel = 100; - } else { - this.BatteryLevel = this.accessory.context.BatteryLevel; - } - if (this.StatusLowBattery === undefined) { - this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL; - this.accessory.context.StatusLowBattery = this.StatusLowBattery; - } else { - this.StatusLowBattery = this.accessory.context.StatusLowBattery; - } + if (this.BatteryLevel === undefined) { + this.BatteryLevel = 100; + } else { + this.BatteryLevel = this.accessory.context.BatteryLevel; + } + if (this.StatusLowBattery === undefined) { + this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL; + this.accessory.context.StatusLowBattery = this.StatusLowBattery; + } else { + this.StatusLowBattery = this.accessory.context.StatusLowBattery; } } @@ -648,7 +672,7 @@ export class Meter { config['scanDuration'] = device.scanDuration; } if (Object.entries(config).length !== 0) { - this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); + this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); } } diff --git a/src/device/meterplus.ts b/src/device/meterplus.ts index b8afa510..9a47203f 100644 --- a/src/device/meterplus.ts +++ b/src/device/meterplus.ts @@ -1,14 +1,14 @@ -import { Context } from 'vm'; -import { hostname } from 'os'; -import { request } from 'undici'; -import { sleep } from '../utils'; -import { MqttClient } from 'mqtt'; -import { interval, Subject } from 'rxjs'; import { connectAsync } from 'async-mqtt'; +import { CharacteristicValue, PlatformAccessory, Service, Units } from 'homebridge'; +import { MqttClient } from 'mqtt'; +import { hostname } from 'os'; +import { Subject, interval } from 'rxjs'; import { skipWhile } from 'rxjs/operators'; +import { request } from 'undici'; +import { Context } from 'vm'; import { SwitchBotPlatform } from '../platform'; -import { Service, PlatformAccessory, Units, CharacteristicValue } from 'homebridge'; -import { device, devicesConfig, serviceData, ad, switchbot, temperature, deviceStatus, Devices } from '../settings'; +import { Devices, ad, device, deviceStatus, devicesConfig, serviceData, switchbot, temperature } from '../settings'; +import { sleep } from '../utils'; /** * Platform Accessory @@ -29,6 +29,7 @@ export class MeterPlus { StatusLowBattery?: CharacteristicValue; // OpenAPI Others + Version: deviceStatus['version']; Battery: deviceStatus['battery']; Temperature: deviceStatus['temperature']; Humidity: deviceStatus['humidity']; @@ -61,18 +62,22 @@ export class MeterPlus { doMeterUpdate: Subject; // Connection - private readonly BLE = (this.device.connectionType === 'BLE' || this.device.connectionType === 'BLE/OpenAPI'); - private readonly OpenAPI = (this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'BLE/OpenAPI'); - - constructor(private readonly platform: SwitchBotPlatform, private accessory: PlatformAccessory, public device: device & devicesConfig) { + private readonly BLE = this.device.connectionType === 'BLE' || this.device.connectionType === 'BLE/OpenAPI'; + private readonly OpenAPI = this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'BLE/OpenAPI'; + + constructor( + private readonly platform: SwitchBotPlatform, + private accessory: PlatformAccessory, + public device: device & devicesConfig, + ) { // default placeholders this.logs(device); this.scan(device); this.refreshRate(device); - this.config(device); this.context(); this.setupHistoryService(device); this.setupMqtt(device); + this.config(device); // this is subject we use to track when we need to POST changes to the SwitchBot API this.doMeterUpdate = new Subject(); @@ -150,11 +155,7 @@ export class MeterPlus { } // Battery Service - if (!this.BLE) { - this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Removing Battery Service`); - this.batteryService = this.accessory.getService(this.platform.Service.Battery); - accessory.removeService(this.batteryService!); - } else if (this.BLE && !this.batteryService) { + if (!this.batteryService) { this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Add Battery Service`); (this.batteryService = this.accessory.getService(this.platform.Service.Battery) || this.accessory.addService(this.platform.Service.Battery)), `${accessory.displayName} Battery`; @@ -191,8 +192,9 @@ export class MeterPlus { await this.openAPIparseStatus(); } else { await this.offlineOff(); - this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` - + ` ${this.device.connectionType}, parseStatus will not happen.`); + this.debugWarnLog( + `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + ` ${this.device.connectionType}, parseStatus will not happen.`, + ); } } @@ -222,9 +224,18 @@ export class MeterPlus { } } - async openAPIparseStatus(): Promise { this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIparseStatus`); + + // Battery + this.BatteryLevel = Number(this.Battery); + if (this.BatteryLevel < 15) { + this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW; + } else { + this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL; + } + this.debugLog(`${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}, StatusLowBattery: ${this.StatusLowBattery}`); + // Current Relative Humidity if (!this.device.meter?.hide_humidity) { this.CurrentRelativeHumidity = this.Humidity!; @@ -250,8 +261,10 @@ export class MeterPlus { await this.openAPIRefreshStatus(); } else { await this.offlineOff(); - this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` - + ` ${this.device.connectionType}, refreshStatus will not happen.`); + this.debugWarnLog( + `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + + ` ${this.device.connectionType}, refreshStatus will not happen.`, + ); } } @@ -276,8 +289,10 @@ export class MeterPlus { // Set an event hander switchbot.onadvertisement = async (ad: ad) => { this.address = ad.address; - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Config BLE Address: ${this.device.bleMac},` - + ` BLE Address Found: ${this.address}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} Config BLE Address: ${this.device.bleMac},` + + ` BLE Address Found: ${this.address}`, + ); if (ad.serviceData.humidity! > 0) { // reject unreliable data this.humidity = ad.serviceData.humidity; @@ -312,8 +327,10 @@ export class MeterPlus { }) .catch(async (e: any) => { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLERefreshStatus with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed BLERefreshStatus with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + ); await this.BLERefreshConnection(switchbot); }); } else { @@ -327,23 +344,23 @@ export class MeterPlus { const { body, statusCode, headers } = await request(`${Devices}/${this.device.deviceId}/status`, { headers: this.platform.generateHeaders(), }); - const deviceStatus = await body.json(); + const deviceStatus: any = await body.json(); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`); this.statusCode(statusCode); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`); - this.debugLog( - `${this.device.deviceType}: ${this.accessory.displayName - } refreshStatus: ${JSON.stringify(deviceStatus)}`, - ); + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} refreshStatus: ${JSON.stringify(deviceStatus)}`); this.Humidity = deviceStatus.body.humidity!; this.Temperature = deviceStatus.body.temperature!; - this.Battery = deviceStatus.body.battery!; + this.Battery = deviceStatus.body.battery; + this.Version = deviceStatus.body.version; this.openAPIparseStatus(); this.updateHomeKitCharacteristics(); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + ); } } @@ -359,8 +376,10 @@ export class MeterPlus { } else { this.accessory.context.CurrentRelativeHumidity = this.CurrentRelativeHumidity; this.humidityservice?.updateCharacteristic(this.platform.Characteristic.CurrentRelativeHumidity, this.CurrentRelativeHumidity); - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}` - + ` updateCharacteristic CurrentRelativeHumidity: ${this.CurrentRelativeHumidity}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName}` + + ` updateCharacteristic CurrentRelativeHumidity: ${this.CurrentRelativeHumidity}`, + ); if (this.device.mqttURL) { mqttmessage.push(`"humidity": ${this.CurrentRelativeHumidity}`); } @@ -384,28 +403,29 @@ export class MeterPlus { this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic CurrentTemperature: ${this.CurrentTemperature}`); } } - if (this.BLE) { - if (this.BatteryLevel === undefined) { - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}`); - } else { - if (this.device.mqttURL) { - mqttmessage.push(`"battery": ${this.BatteryLevel}`); - } - this.accessory.context.BatteryLevel = this.BatteryLevel; - this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, this.BatteryLevel); - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic BatteryLevel: ${this.BatteryLevel}`); + + if (this.BatteryLevel === undefined) { + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}`); + } else { + if (this.device.mqttURL) { + mqttmessage.push(`"battery": ${this.BatteryLevel}`); } - if (this.StatusLowBattery === undefined) { - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} StatusLowBattery: ${this.StatusLowBattery}`); - } else { - if (this.device.mqttURL) { - mqttmessage.push(`"lowBattery": ${this.StatusLowBattery}`); - } - this.accessory.context.StatusLowBattery = this.StatusLowBattery; - this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, this.StatusLowBattery); - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic StatusLowBattery: ${this.StatusLowBattery}`); + this.accessory.context.BatteryLevel = this.BatteryLevel; + this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, this.BatteryLevel); + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic BatteryLevel: ${this.BatteryLevel}`); + } + + if (this.StatusLowBattery === undefined) { + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} StatusLowBattery: ${this.StatusLowBattery}`); + } else { + if (this.device.mqttURL) { + mqttmessage.push(`"lowBattery": ${this.StatusLowBattery}`); } + this.accessory.context.StatusLowBattery = this.StatusLowBattery; + this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, this.StatusLowBattery); + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic StatusLowBattery: ${this.StatusLowBattery}`); } + if (this.device.mqttURL) { this.mqttPublish(`{${mqttmessage.join(',')}}`); } @@ -542,8 +562,10 @@ export class MeterPlus { this.offlineOff(); break; case 171: - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` - + `Hub: ${this.device.hubDeviceId}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` + + `Hub: ${this.device.hubDeviceId}`, + ); this.offlineOff(); break; case 190: @@ -559,8 +581,10 @@ export class MeterPlus { this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Request successful, statusCode: ${statusCode}`); break; default: - this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode: ` - + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`); + this.infoLog( + `${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode: ` + + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`, + ); } } @@ -578,22 +602,23 @@ export class MeterPlus { if (!this.device.meter?.hide_temperature) { this.temperatureservice?.updateCharacteristic(this.platform.Characteristic.CurrentTemperature, e); } - if (this.BLE) { - this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, e); - this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, e); - } + this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, e); + this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, e); } FirmwareRevision(accessory: PlatformAccessory, device: device & devicesConfig): CharacteristicValue { let FirmwareRevision: string; - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}` - + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName}` + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`, + ); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} device.firmware: ${device.firmware}`); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`); - if (accessory.context.FirmwareRevision) { - FirmwareRevision = accessory.context.FirmwareRevision; - } else if (device.firmware) { + if (device.firmware) { FirmwareRevision = device.firmware; + } else if (device.version) { + FirmwareRevision = JSON.stringify(device.version); + } else if (accessory.context.FirmwareRevision) { + FirmwareRevision = accessory.context.FirmwareRevision; } else { FirmwareRevision = this.platform.version; } @@ -611,18 +636,16 @@ export class MeterPlus { } else { this.CurrentTemperature = this.accessory.context.CurrentTemperature; } - if (this.BLE) { - if (this.BatteryLevel === undefined) { - this.BatteryLevel = 100; - } else { - this.BatteryLevel = this.accessory.context.BatteryLevel; - } - if (this.StatusLowBattery === undefined) { - this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL; - this.accessory.context.StatusLowBattery = this.StatusLowBattery; - } else { - this.StatusLowBattery = this.accessory.context.StatusLowBattery; - } + if (this.BatteryLevel === undefined) { + this.BatteryLevel = 100; + } else { + this.BatteryLevel = this.accessory.context.BatteryLevel; + } + if (this.StatusLowBattery === undefined) { + this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL; + this.accessory.context.StatusLowBattery = this.StatusLowBattery; + } else { + this.StatusLowBattery = this.accessory.context.StatusLowBattery; } } @@ -660,7 +683,7 @@ export class MeterPlus { config['scanDuration'] = device.scanDuration; } if (Object.entries(config).length !== 0) { - this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); + this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); } } diff --git a/src/device/motion.ts b/src/device/motion.ts index d518d57b..f23eedb4 100644 --- a/src/device/motion.ts +++ b/src/device/motion.ts @@ -25,6 +25,8 @@ export class Motion { StatusLowBattery?: CharacteristicValue; // OpenAPI Others + Version: deviceStatus['version']; + Battery: deviceStatus['battery']; deviceStatus!: any; //deviceStatusResponse; moveDetected: deviceStatus['moveDetected']; brightness: deviceStatus['brightness']; @@ -38,7 +40,7 @@ export class Motion { battery!: serviceData['battery']; movement!: serviceData['movement']; lightLevel!: serviceData['lightLevel']; - is_light!: any;//serviceData['is_light']; + is_light!: any; //serviceData['is_light']; tested!: any; led!: any; iot!: any; @@ -56,16 +58,20 @@ export class Motion { doMotionUpdate!: Subject; // Connection - private readonly BLE = (this.device.connectionType === 'BLE' || this.device.connectionType === 'BLE/OpenAPI'); - private readonly OpenAPI = (this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'BLE/OpenAPI'); - - constructor(private readonly platform: SwitchBotPlatform, private accessory: PlatformAccessory, public device: device & devicesConfig) { + private readonly BLE = this.device.connectionType === 'BLE' || this.device.connectionType === 'BLE/OpenAPI'; + private readonly OpenAPI = this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'BLE/OpenAPI'; + + constructor( + private readonly platform: SwitchBotPlatform, + private accessory: PlatformAccessory, + public device: device & devicesConfig, + ) { // default placeholders this.logs(device); this.scan(device); this.refreshRate(device); - this.config(device); this.context(); + this.config(device); // this is subject we use to track when we need to POST changes to the SwitchBot API this.doMotionUpdate = new Subject(); @@ -120,17 +126,16 @@ export class Motion { } // Battery Service - if (!this.BLE) { - this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Removing Battery Service`); - this.batteryService = this.accessory.getService(this.platform.Service.Battery); - accessory.removeService(this.batteryService!); - } else if (this.BLE && !this.batteryService) { + if (!this.batteryService) { this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Add Battery Service`); (this.batteryService = this.accessory.getService(this.platform.Service.Battery) || this.accessory.addService(this.platform.Service.Battery)), `${accessory.displayName} Battery`; this.batteryService.setCharacteristic(this.platform.Characteristic.Name, `${accessory.displayName} Battery`); - this.batteryService.setCharacteristic(this.platform.Characteristic.ConfiguredName, `${accessory.displayName} Battery`); + if (!this.batteryService.testCharacteristic(this.platform.Characteristic.ConfiguredName)) { + this.batteryService.addCharacteristic(this.platform.Characteristic.ConfiguredName, `${accessory.displayName} Battery`); + } + this.batteryService.setCharacteristic(this.platform.Characteristic.ChargingState, this.platform.Characteristic.ChargingState.NOT_CHARGEABLE); } else { this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Battery Service Not Added`); } @@ -158,8 +163,9 @@ export class Motion { await this.openAPIparseStatus(); } else { await this.offlineOff(); - this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` - + ` ${this.device.connectionType}, parseStatus will not happen.`); + this.debugWarnLog( + `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + ` ${this.device.connectionType}, parseStatus will not happen.`, + ); } } @@ -168,7 +174,7 @@ export class Motion { // Movement this.MotionDetected = this.movement!; this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} MotionDetected: ${this.MotionDetected}`); - if ((this.MotionDetected !== this.accessory.context.MotionDetected) && this.MotionDetected) { + if (this.MotionDetected !== this.accessory.context.MotionDetected && this.MotionDetected) { this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Detected Motion`); } // Light Level @@ -183,8 +189,10 @@ export class Motion { default: this.CurrentAmbientLightLevel = this.set_maxLux; } - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.lightLevel},` + - ` CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.lightLevel},` + + ` CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`, + ); if (this.CurrentAmbientLightLevel !== this.accessory.context.CurrentAmbientLightLevel) { this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`); } @@ -199,8 +207,9 @@ export class Motion { } else { this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL; } - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel},` - + ` StatusLowBattery: ${this.StatusLowBattery}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel},` + ` StatusLowBattery: ${this.StatusLowBattery}`, + ); } async openAPIparseStatus(): Promise { @@ -222,6 +231,19 @@ export class Motion { } this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`); } + // Battery + if (this.battery === undefined) { + this.battery = 100; + } + this.BatteryLevel = this.Battery!; + if (this.BatteryLevel < 10) { + this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW; + } else { + this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL; + } + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel},` + ` StatusLowBattery: ${this.StatusLowBattery}`, + ); } /** @@ -236,8 +258,10 @@ export class Motion { await this.openAPIRefreshStatus(); } else { await this.offlineOff(); - this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` - + ` ${this.device.connectionType}, refreshStatus will not happen.`); + this.debugWarnLog( + `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + + ` ${this.device.connectionType}, refreshStatus will not happen.`, + ); } } @@ -268,8 +292,10 @@ export class Motion { this.scanning = true; switchbot.onadvertisement = async (ad: any) => { this.address = ad.address; - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Config BLE Address: ${this.device.bleMac},` - + ` BLE Address Found: ${this.address}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} Config BLE Address: ${this.device.bleMac},` + + ` BLE Address Found: ${this.address}`, + ); this.serviceData = ad.serviceData; this.movement = ad.serviceData.movement; this.tested = ad.serviceData.tested; @@ -312,8 +338,10 @@ export class Motion { }) .catch(async (e: any) => { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLERefreshStatus with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed BLERefreshStatus with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + ); this.debugErrorLog('3'); await this.BLERefreshConnection(switchbot); }); @@ -329,22 +357,23 @@ export class Motion { const { body, statusCode, headers } = await request(`${Devices}/${this.device.deviceId}/status`, { headers: this.platform.generateHeaders(), }); - const deviceStatus = await body.json(); + const deviceStatus: any = await body.json(); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`); this.statusCode(statusCode); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`); - this.debugLog( - `${this.device.deviceType}: ${this.accessory.displayName - } refreshStatus: ${JSON.stringify(deviceStatus)}`, - ); + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} refreshStatus: ${JSON.stringify(deviceStatus)}`); this.moveDetected = deviceStatus.body.moveDetected; this.brightness = deviceStatus.body.brightness; + this.Battery = deviceStatus.body.battery; + this.Version = deviceStatus.body.version; this.openAPIparseStatus(); this.updateHomeKitCharacteristics(); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + ); } } @@ -359,29 +388,29 @@ export class Motion { this.motionSensorService.updateCharacteristic(this.platform.Characteristic.MotionDetected, this.MotionDetected); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic MotionDetected: ${this.MotionDetected}`); } + if (this.BatteryLevel === undefined) { + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}`); + } else { + this.accessory.context.BatteryLevel = this.BatteryLevel; + this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, this.BatteryLevel); + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic BatteryLevel: ${this.BatteryLevel}`); + } + if (this.StatusLowBattery === undefined) { + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} StatusLowBattery: ${this.StatusLowBattery}`); + } else { + this.accessory.context.StatusLowBattery = this.StatusLowBattery; + this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, this.StatusLowBattery); + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic StatusLowBattery: ${this.StatusLowBattery}`); + } if (this.BLE) { - if (this.BatteryLevel === undefined) { - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}`); - } else { - this.accessory.context.BatteryLevel = this.BatteryLevel; - this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, this.BatteryLevel); - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic BatteryLevel: ${this.BatteryLevel}`); - } - if (this.StatusLowBattery === undefined) { - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} StatusLowBattery: ${this.StatusLowBattery}`); - } else { - this.accessory.context.StatusLowBattery = this.StatusLowBattery; - this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, this.StatusLowBattery); - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic StatusLowBattery: ${this.StatusLowBattery}`); - } if (this.CurrentAmbientLightLevel === undefined) { this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`); } else { this.accessory.context.CurrentAmbientLightLevel = this.CurrentAmbientLightLevel; this.lightSensorService?.updateCharacteristic(this.platform.Characteristic.CurrentAmbientLightLevel, this.CurrentAmbientLightLevel); this.debugLog( - `${this.device.deviceType}: ${this.accessory.displayName}` - + ` updateCharacteristic CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`, + `${this.device.deviceType}: ${this.accessory.displayName}` + + ` updateCharacteristic CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`, ); } } @@ -491,8 +520,10 @@ export class Motion { this.offlineOff(); break; case 171: - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` - + `Hub: ${this.device.hubDeviceId}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` + + `Hub: ${this.device.hubDeviceId}`, + ); this.offlineOff(); break; case 190: @@ -508,8 +539,10 @@ export class Motion { this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Request successful, statusCode: ${statusCode}`); break; default: - this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode: ` - + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`); + this.infoLog( + `${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode: ` + + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`, + ); } } @@ -522,23 +555,26 @@ export class Motion { async apiError(e: any): Promise { this.motionSensorService.updateCharacteristic(this.platform.Characteristic.MotionDetected, e); + this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, e); + this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, e); if (this.BLE) { - this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, e); - this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, e); this.lightSensorService?.updateCharacteristic(this.platform.Characteristic.CurrentAmbientLightLevel, e); } } FirmwareRevision(accessory: PlatformAccessory, device: device & devicesConfig): CharacteristicValue { let FirmwareRevision: string; - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}` - + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName}` + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`, + ); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} device.firmware: ${device.firmware}`); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`); - if (accessory.context.FirmwareRevision) { - FirmwareRevision = accessory.context.FirmwareRevision; - } else if (device.firmware) { + if (device.firmware) { FirmwareRevision = device.firmware; + } else if (device.version) { + FirmwareRevision = JSON.stringify(device.version); + } else if (accessory.context.FirmwareRevision) { + FirmwareRevision = accessory.context.FirmwareRevision; } else { FirmwareRevision = this.platform.version; } @@ -587,7 +623,7 @@ export class Motion { config['offline'] = device.offline; } if (Object.entries(config).length !== 0) { - this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); + this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); } } diff --git a/src/device/plug.ts b/src/device/plug.ts index ea8c60a8..6950755b 100644 --- a/src/device/plug.ts +++ b/src/device/plug.ts @@ -15,6 +15,7 @@ export class Plug { On!: CharacteristicValue; // OpenAPI Others + Version: deviceStatus['version']; power: deviceStatus['power']; deviceStatus!: any; //deviceStatusResponse; @@ -41,16 +42,20 @@ export class Plug { doPlugUpdate!: Subject; // Connection - private readonly BLE = (this.device.connectionType === 'BLE' || this.device.connectionType === 'BLE/OpenAPI'); - private readonly OpenAPI = (this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'BLE/OpenAPI'); - - constructor(private readonly platform: SwitchBotPlatform, private accessory: PlatformAccessory, public device: device & devicesConfig) { + private readonly BLE = this.device.connectionType === 'BLE' || this.device.connectionType === 'BLE/OpenAPI'; + private readonly OpenAPI = this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'BLE/OpenAPI'; + + constructor( + private readonly platform: SwitchBotPlatform, + private accessory: PlatformAccessory, + public device: device & devicesConfig, + ) { // default placeholders this.logs(device); this.scan(device); this.refreshRate(device); - this.config(device); this.context(); + this.config(device); // this is subject we use to track when we need to POST changes to the SwitchBot API this.doPlugUpdate = new Subject(); @@ -114,8 +119,10 @@ export class Plug { await this.pushChanges(); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType} Connection,` - + ` Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType} Connection,` + + ` Error Message: ${JSON.stringify(e.message)}`, + ); } this.plugUpdateInProgress = false; }); @@ -133,8 +140,9 @@ export class Plug { await this.openAPIparseStatus(); } else { await this.offlineOff(); - this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` - + ` ${this.device.connectionType}, parseStatus will not happen.`); + this.debugWarnLog( + `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + ` ${this.device.connectionType}, parseStatus will not happen.`, + ); } } @@ -175,8 +183,10 @@ export class Plug { await this.openAPIRefreshStatus(); } else { await this.offlineOff(); - this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` - + ` ${this.device.connectionType}, refreshStatus will not happen.`); + this.debugWarnLog( + `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + + ` ${this.device.connectionType}, refreshStatus will not happen.`, + ); } } @@ -201,8 +211,10 @@ export class Plug { // Set an event hander switchbot.onadvertisement = async (ad: any) => { this.address = ad.address; - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Config BLE Address: ${this.device.bleMac},` - + ` BLE Address Found: ${this.address}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} Config BLE Address: ${this.device.bleMac},` + + ` BLE Address Found: ${this.address}`, + ); this.serviceData = ad.serviceData; this.state = ad.serviceData.state; this.delay = ad.serviceData.delay; @@ -236,8 +248,10 @@ export class Plug { }) .catch(async (e: any) => { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLERefreshStatus with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed BLERefreshStatus with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + ); await this.BLERefreshConnection(switchbot); }); } else { @@ -251,21 +265,20 @@ export class Plug { const { body, statusCode, headers } = await request(`${Devices}/${this.device.deviceId}/status`, { headers: this.platform.generateHeaders(), }); - const deviceStatus = await body.json(); + const deviceStatus: any = await body.json(); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`); this.statusCode(statusCode); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`); - this.debugLog( - `${this.device.deviceType}: ${this.accessory.displayName - } refreshStatus: ${JSON.stringify(deviceStatus)}`, - ); + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} refreshStatus: ${JSON.stringify(deviceStatus)}`); this.power = deviceStatus.body.power; this.openAPIparseStatus(); this.updateHomeKitCharacteristics(); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + ); } } @@ -288,8 +301,9 @@ export class Plug { await this.openAPIpushChanges(); } else { await this.offlineOff(); - this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` - + ` ${this.device.connectionType}, pushChanges will not happen.`); + this.debugWarnLog( + `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + ` ${this.device.connectionType}, pushChanges will not happen.`, + ); } // Refresh the status from the API interval(15000) @@ -335,14 +349,15 @@ export class Plug { }) .catch(async (e: any) => { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushChanges with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushChanges with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + ); await this.BLEPushConnection(); }); } else { this.debugLog( - `${this.device.deviceType}: ${this.accessory.displayName} No BLEpushChanges.` + `On: ${this.On}, ` - + `OnCached: ${this.accessory.context.On}`, + `${this.device.deviceType}: ${this.accessory.displayName} No BLEpushChanges.` + `On: ${this.On}, ` + `OnCached: ${this.accessory.context.On}`, ); } } @@ -357,9 +372,9 @@ export class Plug { command = 'turnOff'; } const bodyChange = JSON.stringify({ - 'command': `${command}`, - 'parameter': 'default', - 'commandType': 'command', + command: `${command}`, + parameter: 'default', + commandType: 'command', }); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${bodyChange},`); try { @@ -368,19 +383,23 @@ export class Plug { method: 'POST', headers: this.platform.generateHeaders(), }); - const deviceStatus = await body.json(); + const deviceStatus: any = await body.json(); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`); this.statusCode(statusCode); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIpushChanges with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed openAPIpushChanges with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, ); } } else { - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No openAPIpushChanges.` + `On: ${this.On}, ` - + `OnCached: ${this.accessory.context.On}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} No openAPIpushChanges.` + + `On: ${this.On}, ` + + `OnCached: ${this.accessory.context.On}`, + ); } } @@ -521,8 +540,10 @@ export class Plug { this.offlineOff(); break; case 171: - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` - + `Hub: ${this.device.hubDeviceId}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` + + `Hub: ${this.device.hubDeviceId}`, + ); this.offlineOff(); break; case 190: @@ -538,8 +559,10 @@ export class Plug { this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Request successful, statusCode: ${statusCode}`); break; default: - this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode: ` - + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`); + this.infoLog( + `${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode: ` + + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`, + ); } } @@ -556,14 +579,17 @@ export class Plug { FirmwareRevision(accessory: PlatformAccessory, device: device & devicesConfig): CharacteristicValue { let FirmwareRevision: string; - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}` - + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName}` + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`, + ); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} device.firmware: ${device.firmware}`); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`); - if (accessory.context.FirmwareRevision) { - FirmwareRevision = accessory.context.FirmwareRevision; - } else if (device.firmware) { + if (device.firmware) { FirmwareRevision = device.firmware; + } else if (device.version) { + FirmwareRevision = JSON.stringify(device.version); + } else if (accessory.context.FirmwareRevision) { + FirmwareRevision = accessory.context.FirmwareRevision; } else { FirmwareRevision = this.platform.version; } @@ -615,7 +641,7 @@ export class Plug { config['maxRetry'] = device.maxRetry; } if (Object.entries(config).length !== 0) { - this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); + this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); } } diff --git a/src/device/robotvacuumcleaner.ts b/src/device/robotvacuumcleaner.ts index 14374dcb..0ef4816e 100644 --- a/src/device/robotvacuumcleaner.ts +++ b/src/device/robotvacuumcleaner.ts @@ -1,3 +1,4 @@ +/* eslint-disable brace-style */ import { Context } from 'vm'; import { request } from 'undici'; import { sleep } from '../utils'; @@ -19,6 +20,8 @@ export class RobotVacuumCleaner { StatusLowBattery?: CharacteristicValue; // OpenAPI Others + Version: deviceStatus['version']; + Battery: deviceStatus['battery']; power: deviceStatus['power']; deviceStatus!: any; //deviceStatusResponse; @@ -39,16 +42,20 @@ export class RobotVacuumCleaner { doRobotVacuumCleanerUpdate!: Subject; // Connection - private readonly BLE = (this.device.connectionType === 'BLE' || this.device.connectionType === 'BLE/OpenAPI'); - private readonly OpenAPI = (this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'BLE/OpenAPI'); - - constructor(private readonly platform: SwitchBotPlatform, private accessory: PlatformAccessory, public device: device & devicesConfig) { + private readonly BLE = this.device.connectionType === 'BLE' || this.device.connectionType === 'BLE/OpenAPI'; + private readonly OpenAPI = this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'BLE/OpenAPI'; + + constructor( + private readonly platform: SwitchBotPlatform, + private accessory: PlatformAccessory, + public device: device & devicesConfig, + ) { // default placeholders this.logs(device); this.scan(device); this.refreshRate(device); - this.config(device); this.context(); + this.config(device); // this is subject we use to track when we need to POST changes to the SwitchBot API this.doRobotVacuumCleanerUpdate = new Subject(); @@ -103,6 +110,21 @@ export class RobotVacuumCleaner { }) .onSet(this.BrightnessSet.bind(this)); + // Battery Service + if (!this.batteryService) { + this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Add Battery Service`); + (this.batteryService = this.accessory.getService(this.platform.Service.Battery) || this.accessory.addService(this.platform.Service.Battery)), + `${accessory.displayName} Battery`; + + this.batteryService.setCharacteristic(this.platform.Characteristic.Name, `${accessory.displayName} Battery`); + if (!this.batteryService.testCharacteristic(this.platform.Characteristic.ConfiguredName)) { + this.batteryService.addCharacteristic(this.platform.Characteristic.ConfiguredName, `${accessory.displayName} Battery`); + } + this.batteryService.setCharacteristic(this.platform.Characteristic.ChargingState, this.platform.Characteristic.ChargingState.NOT_CHARGEABLE); + } else { + this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Battery Service Not Added`); + } + // Update Homekit this.updateHomeKitCharacteristics(); @@ -127,13 +149,15 @@ export class RobotVacuumCleaner { if (this.On !== this.accessory.context.On) { await this.pushChanges(); } - if (this.On && (this.Brightness !== this.accessory.context.Brightness)) { + if (this.On && this.Brightness !== this.accessory.context.Brightness) { await this.openAPIpushBrightnessChanges(); } } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType} Connection,` - + ` Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType} Connection,` + + ` Error Message: ${JSON.stringify(e.message)}`, + ); } this.robotVacuumCleanerUpdateInProgress = false; }); @@ -145,14 +169,15 @@ export class RobotVacuumCleaner { async parseStatus(): Promise { if (!this.device.enableCloudService && this.OpenAPI) { this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} parseStatus enableCloudService: ${this.device.enableCloudService}`); - } else/*if (this.BLE) { + } /*if (this.BLE) { await this.BLEparseStatus(); - } else*/if (this.OpenAPI && this.platform.config.credentials?.token) { + } else*/ else if (this.OpenAPI && this.platform.config.credentials?.token) { await this.openAPIparseStatus(); } else { await this.offlineOff(); - this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` - + ` ${this.device.connectionType}, parseStatus will not happen.`); + this.debugWarnLog( + `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + ` ${this.device.connectionType}, parseStatus will not happen.`, + ); } } @@ -179,6 +204,15 @@ export class RobotVacuumCleaner { this.On = false; } this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`); + + // Battery + this.BatteryLevel = Number(this.Battery); + if (this.BatteryLevel < 15) { + this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW; + } else { + this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL; + } + this.debugLog(`${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}, StatusLowBattery: ${this.StatusLowBattery}`); } /** @@ -187,14 +221,16 @@ export class RobotVacuumCleaner { async refreshStatus(): Promise { if (!this.device.enableCloudService && this.OpenAPI) { this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} refreshStatus enableCloudService: ${this.device.enableCloudService}`); - } else/*if (this.BLE) { + } /*if (this.BLE) { await this.BLERefreshStatus(); - } else*/if (this.OpenAPI && this.platform.config.credentials?.token) { + } else*/ else if (this.OpenAPI && this.platform.config.credentials?.token) { await this.openAPIRefreshStatus(); } else { await this.offlineOff(); - this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` - + ` ${this.device.connectionType}, refreshStatus will not happen.`); + this.debugWarnLog( + `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + + ` ${this.device.connectionType}, refreshStatus will not happen.`, + ); } } @@ -219,8 +255,10 @@ export class RobotVacuumCleaner { // Set an event hander switchbot.onadvertisement = async (ad: any) => { this.address = ad.address; - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Config BLE Address: ${this.device.bleMac},` - + ` BLE Address Found: ${this.address}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} Config BLE Address: ${this.device.bleMac},` + + ` BLE Address Found: ${this.address}`, + ); this.serviceData = ad.serviceData; this.state = ad.serviceData.state; this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} serviceData: ${JSON.stringify(ad.serviceData)}`); @@ -248,8 +286,10 @@ export class RobotVacuumCleaner { }) .catch(async (e: any) => { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLERefreshStatus with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed BLERefreshStatus with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + ); await this.BLERefreshConnection(switchbot); }); } else { @@ -263,21 +303,22 @@ export class RobotVacuumCleaner { const { body, statusCode, headers } = await request(`${Devices}/${this.device.deviceId}/status`, { headers: this.platform.generateHeaders(), }); - const deviceStatus = await body.json(); + const deviceStatus: any = await body.json(); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`); this.statusCode(statusCode); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`); - this.debugLog( - `${this.device.deviceType}: ${this.accessory.displayName - } refreshStatus: ${JSON.stringify(deviceStatus)}`, - ); + this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} refreshStatus: ${JSON.stringify(deviceStatus)}`); this.power = deviceStatus.body.power; + this.Battery = deviceStatus.body.battery; + this.Version = deviceStatus.body.version; this.openAPIparseStatus(); this.updateHomeKitCharacteristics(); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + ); } } @@ -293,14 +334,15 @@ export class RobotVacuumCleaner { async pushChanges(): Promise { if (!this.device.enableCloudService && this.OpenAPI) { this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} pushChanges enableCloudService: ${this.device.enableCloudService}`); - } else/* if (this.BLE) { + } /* if (this.BLE) { await this.BLEpushChanges(); - } else*/if (this.OpenAPI && this.platform.config.credentials?.token) { + } else*/ else if (this.OpenAPI && this.platform.config.credentials?.token) { await this.openAPIpushChanges(); } else { await this.offlineOff(); - this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` - + ` ${this.device.connectionType}, pushChanges will not happen.`); + this.debugWarnLog( + `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + ` ${this.device.connectionType}, pushChanges will not happen.`, + ); } // Refresh the status from the API interval(15000) @@ -346,14 +388,15 @@ export class RobotVacuumCleaner { }) .catch(async (e: any) => { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushChanges with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushChanges with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + ); await this.BLEPushConnection(); }); } else { this.debugLog( - `${this.device.deviceType}: ${this.accessory.displayName} No BLEpushChanges.` + `On: ${this.On}, ` - + `OnCached: ${this.accessory.context.On}`, + `${this.device.deviceType}: ${this.accessory.displayName} No BLEpushChanges.` + `On: ${this.On}, ` + `OnCached: ${this.accessory.context.On}`, ); } } @@ -368,9 +411,9 @@ export class RobotVacuumCleaner { command = 'turnOff'; } const bodyChange = JSON.stringify({ - 'command': `${command}`, - 'parameter': 'default', - 'commandType': 'command', + command: `${command}`, + parameter: 'default', + commandType: 'command', }); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${bodyChange},`); try { @@ -379,19 +422,23 @@ export class RobotVacuumCleaner { method: 'POST', headers: this.platform.generateHeaders(), }); - const deviceStatus = await body.json(); + const deviceStatus: any = await body.json(); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`); this.statusCode(statusCode); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIpushChanges with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed openAPIpushChanges with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, ); } } else { - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No openAPIpushChanges.` + `On: ${this.On}, ` - + `OnCached: ${this.accessory.context.On}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName} No openAPIpushChanges.` + + `On: ${this.On}, ` + + `OnCached: ${this.accessory.context.On}`, + ); } } @@ -404,14 +451,15 @@ export class RobotVacuumCleaner { method: 'POST', headers: this.platform.generateHeaders(), }); - const deviceStatus = await body.json(); + const deviceStatus: any = await body.json(); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`); this.statusCode(statusCode); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIpushChanges with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} failed openAPIpushChanges with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, ); } } @@ -427,9 +475,9 @@ export class RobotVacuumCleaner { parameter = 'default'; } const body = JSON.stringify({ - 'command': `${command}`, - 'parameter': `${parameter}`, - 'commandType': 'command', + command: `${command}`, + parameter: `${parameter}`, + commandType: 'command', }); return body; } @@ -454,9 +502,9 @@ export class RobotVacuumCleaner { parameter = 'default'; } const body = JSON.stringify({ - 'command': `${command}`, - 'parameter': `${parameter}`, - 'commandType': 'command', + command: `${command}`, + parameter: `${parameter}`, + commandType: 'command', }); return body; } @@ -635,8 +683,10 @@ export class RobotVacuumCleaner { this.offlineOff(); break; case 171: - this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` - + `Hub: ${this.device.hubDeviceId}`); + this.errorLog( + `${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` + + `Hub: ${this.device.hubDeviceId}`, + ); this.offlineOff(); break; case 190: @@ -652,8 +702,10 @@ export class RobotVacuumCleaner { this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Request successful, statusCode: ${statusCode}`); break; default: - this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode: ` - + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`); + this.infoLog( + `${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode: ` + + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`, + ); } } @@ -670,8 +722,9 @@ export class RobotVacuumCleaner { FirmwareRevision(accessory: PlatformAccessory, device: device & devicesConfig): CharacteristicValue { let FirmwareRevision: string; - this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}` - + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`); + this.debugLog( + `${this.device.deviceType}: ${this.accessory.displayName}` + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`, + ); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} device.firmware: ${device.firmware}`); this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`); if (accessory.context.FirmwareRevision) { @@ -734,7 +787,7 @@ export class RobotVacuumCleaner { config['maxRetry'] = device.maxRetry; } if (Object.entries(config).length !== 0) { - this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); + this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); } } diff --git a/src/irdevice/airconditioner.ts b/src/irdevice/airconditioner.ts index a92cce65..7ab90b9e 100644 --- a/src/irdevice/airconditioner.ts +++ b/src/irdevice/airconditioner.ts @@ -43,14 +43,18 @@ export class AirConditioner { private readonly valid12 = [1, 2]; private readonly valid012 = [0, 1, 2]; - constructor(private readonly platform: SwitchBotPlatform, private accessory: PlatformAccessory, public device: irdevice & irDevicesConfig) { + constructor( + private readonly platform: SwitchBotPlatform, + private accessory: PlatformAccessory, + public device: irdevice & irDevicesConfig, + ) { // default placeholders this.logs({ device }); - this.config({ device }); this.context(); this.disablePushOnChanges({ device }); this.disablePushOffChanges({ device }); this.disablePushDetailChanges({ device }); + this.config({ device }); // set accessory information accessory @@ -65,7 +69,7 @@ export class AirConditioner { // get the Television service if it exists, otherwise create a new Television service // you can create multiple services for each accessory (this.coolerService = accessory.getService(this.platform.Service.HeaterCooler) || accessory.addService(this.platform.Service.HeaterCooler)), - `${accessory.displayName} ${device.remoteType}`; + `${accessory.displayName} ${device.remoteType}`; // To avoid "Cannot add a Service with the same UUID another Service without also defining a unique 'subtype' property." error, // when creating multiple services of the same type, you need to use the following syntax to specify a name and subtype id: @@ -79,62 +83,55 @@ export class AirConditioner { } // handle on / off events using the Active characteristic - this.coolerService.getCharacteristic(this.platform.Characteristic.Active) - .onSet(this.ActiveSet.bind(this)); + this.coolerService.getCharacteristic(this.platform.Characteristic.Active).onSet(this.ActiveSet.bind(this)); - this.coolerService.getCharacteristic(this.platform.Characteristic.CurrentTemperature) - .onGet(this.CurrentTemperatureGet.bind(this)); + this.coolerService.getCharacteristic(this.platform.Characteristic.CurrentTemperature).onGet(this.CurrentTemperatureGet.bind(this)); - if (this.hide_automode) { - this.TargetHeaterCoolerState = 1 || 2; - this.ValidValues = [1, 2]; - this.debugLog( - `${this.device.remoteType}: ${this.accessory.displayName} ValidValues: ${JSON.stringify(this.ValidValues)},` + - ` hide_automode: ${this.hide_automode}, TargetHeaterCoolerState: ${this.TargetHeaterCoolerState}`, - ); - } else { - this.TargetHeaterCoolerState = 0 || 1 || 2; - this.ValidValues = [0, 1, 2]; - this.debugLog( - `${this.device.remoteType}: ${this.accessory.displayName} ValidValues: ${JSON.stringify(this.ValidValues)},` + - ` hide_automode: ${this.hide_automode}, TargetHeaterCoolerState: ${this.TargetHeaterCoolerState}`, - ); + this.ValidValues = this.hide_automode ? [1, 2] : [0, 1, 2]; + + if (this.device.irair?.meterType && this.device.irair?.meterId) { + const meterUuid = this.platform.api.hap.uuid.generate(`${this.device.irair.meterId}-${this.device.irair.meterType}`); + this.meter = this.platform.accessories.find((accessory) => accessory.UUID === meterUuid); } if (this.meter) { - this.coolerService - .getCharacteristic(this.platform.Characteristic.CurrentRelativeHumidity) - .onGet(this.CurrentRelativeHumidityGet.bind(this)); + this.coolerService.getCharacteristic(this.platform.Characteristic.CurrentRelativeHumidity).onGet(this.CurrentRelativeHumidityGet.bind(this)); } - this.coolerService.getCharacteristic(this.platform.Characteristic.TargetHeaterCoolerState) + this.coolerService + .getCharacteristic(this.platform.Characteristic.TargetHeaterCoolerState) .setProps({ validValues: this.ValidValues, }) .onGet(this.TargetHeaterCoolerStateGet.bind(this)) .onSet(this.TargetHeaterCoolerStateSet.bind(this)); - this.coolerService.getCharacteristic(this.platform.Characteristic.CurrentHeaterCoolerState) - .onGet(this.CurrentHeaterCoolerStateGet.bind(this)); + this.coolerService.getCharacteristic(this.platform.Characteristic.CurrentHeaterCoolerState).onGet(this.CurrentHeaterCoolerStateGet.bind(this)); - - this.coolerService.getCharacteristic(this.platform.Characteristic.HeatingThresholdTemperature) + this.coolerService + .getCharacteristic(this.platform.Characteristic.HeatingThresholdTemperature) .setProps({ + minValue: 0, + maxValue: 35, minStep: 0.5, }) .onGet(this.ThresholdTemperatureGet.bind(this)) .onSet(this.ThresholdTemperatureSet.bind(this)); - this.coolerService.getCharacteristic(this.platform.Characteristic.CoolingThresholdTemperature) + this.coolerService + .getCharacteristic(this.platform.Characteristic.CoolingThresholdTemperature) .setProps({ + minValue: 0, + maxValue: 35, minStep: 0.5, }) .onGet(this.ThresholdTemperatureGet.bind(this)) .onSet(this.ThresholdTemperatureSet.bind(this)); - this.coolerService.getCharacteristic(this.platform.Characteristic.RotationSpeed) + this.coolerService + .getCharacteristic(this.platform.Characteristic.RotationSpeed) .setProps({ - format: "int", + format: 'int', minStep: 1, minValue: 1, maxValue: 4, @@ -153,38 +150,44 @@ export class AirConditioner { * AirConditioner: "command" "highSpeed" "default" = fan speed to high */ async pushAirConditionerOnChanges(): Promise { - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushAirConditionerOnChanges Active: ${this.Active},` - + ` disablePushOn: ${this.disablePushOn}`); + this.debugLog( + `${this.device.remoteType}: ${this.accessory.displayName} pushAirConditionerOnChanges Active: ${this.Active},` + + ` disablePushOn: ${this.disablePushOn}`, + ); if (this.Active === this.platform.Characteristic.Active.ACTIVE && !this.disablePushOn) { const commandType: string = await this.commandType(); const command: string = await this.commandOn(); const bodyChange = JSON.stringify({ - 'command': command, - 'parameter': 'default', - 'commandType': commandType, + command: command, + parameter: 'default', + commandType: commandType, }); await this.pushChanges(bodyChange); } } async pushAirConditionerOffChanges(): Promise { - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushAirConditionerOffChanges Active: ${this.Active},` - + ` disablePushOff: ${this.disablePushOff}`); + this.debugLog( + `${this.device.remoteType}: ${this.accessory.displayName} pushAirConditionerOffChanges Active: ${this.Active},` + + ` disablePushOff: ${this.disablePushOff}`, + ); if (this.Active === this.platform.Characteristic.Active.INACTIVE && !this.disablePushOff) { const commandType: string = await this.commandType(); const command: string = await this.commandOff(); const bodyChange = JSON.stringify({ - 'command': command, - 'parameter': 'default', - 'commandType': commandType, + command: command, + parameter: 'default', + commandType: commandType, }); await this.pushChanges(bodyChange); } } async pushAirConditionerStatusChanges(): Promise { - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushAirConditionerStatusChanges Active: ${this.Active},` - + ` disablePushOff: ${this.disablePushOff}, disablePushOn: ${this.disablePushOn}`); + this.debugLog( + `${this.device.remoteType}: ${this.accessory.displayName} pushAirConditionerStatusChanges Active: ${this.Active},` + + ` disablePushOff: ${this.disablePushOff}, disablePushOn: ${this.disablePushOn}`, + ); if (!this.Busy) { this.Busy = true; this.CurrentHeaterCoolerState = this.platform.Characteristic.CurrentHeaterCoolerState.IDLE; @@ -196,8 +199,10 @@ export class AirConditioner { } async pushAirConditionerDetailsChanges(): Promise { - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushAirConditionerDetailsChanges Active: ${this.Active},` - + ` disablePushOff: ${this.disablePushOff}, disablePushOn: ${this.disablePushOn}`); + this.debugLog( + `${this.device.remoteType}: ${this.accessory.displayName} pushAirConditionerDetailsChanges Active: ${this.Active},` + + ` disablePushOff: ${this.disablePushOff}, disablePushOn: ${this.disablePushOn}`, + ); //await this.context(); if (this.CurrentMode === undefined) { this.CurrentMode = 1; @@ -214,89 +219,98 @@ export class AirConditioner { // Remove or make configurable? this.ThresholdTemperature = 25; this.debugLog( - `${this.device.remoteType}: ${this.accessory.displayName} CurrentMode: ${this.CurrentMode},` - + ` ThresholdTemperature: ${this.ThresholdTemperature}`, + `${this.device.remoteType}: ${this.accessory.displayName} CurrentMode: ${this.CurrentMode},` + + ` ThresholdTemperature: ${this.ThresholdTemperature}`, ); } const parameter = `${this.ThresholdTemperature},${this.CurrentMode},${this.CurrentFanSpeed},${this.state}`; + await this.UpdateCurrentHeaterCoolerState(); + const bodyChange = JSON.stringify({ + command: 'setAll', + parameter: `${parameter}`, + commandType: 'command', + }); + + await this.pushChanges(bodyChange); + } + + private async UpdateCurrentHeaterCoolerState() { if (this.Active === this.platform.Characteristic.Active.ACTIVE) { await this.context(); - if (this.ThresholdTemperature < this.accessory.context.CurrentTemperature) { + if (this.ThresholdTemperature < this.CurrentTemperature && + this.TargetHeaterCoolerState !== this.platform.Characteristic.TargetHeaterCoolerState.HEAT) { this.CurrentHeaterCoolerState = this.platform.Characteristic.CurrentHeaterCoolerState.COOLING; - } else if (this.ThresholdTemperature > this.accessory.context.CurrentTemperature) { + } else if (this.ThresholdTemperature > this.CurrentTemperature && + this.TargetHeaterCoolerState !== this.platform.Characteristic.TargetHeaterCoolerState.COOL) { this.CurrentHeaterCoolerState = this.platform.Characteristic.CurrentHeaterCoolerState.HEATING; + } else { + this.CurrentHeaterCoolerState = this.platform.Characteristic.CurrentHeaterCoolerState.IDLE; } } else { this.CurrentHeaterCoolerState = this.platform.Characteristic.CurrentHeaterCoolerState.INACTIVE; } - const bodyChange = JSON.stringify({ - 'command': 'setAll', - 'parameter': `${parameter}`, - 'commandType': 'command', - }); - - await this.pushChanges(bodyChange); } async pushChanges(bodyChange: any): Promise { this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushChanges`); if (this.device.connectionType === 'OpenAPI' && !this.disablePushDetail) { - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${bodyChange},`); + this.infoLog(`${this.device.remoteType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${bodyChange},`); try { const { body, statusCode, headers } = await request(`${Devices}/${this.device.deviceId}/commands`, { body: bodyChange, method: 'POST', headers: this.platform.generateHeaders(), }); - const deviceStatus = await body.json(); + const deviceStatus: any = await body.json(); this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`); this.statusCode(statusCode); this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`); this.updateHomeKitCharacteristics(); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + this.errorLog( + `${this.device.remoteType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, ); } } else { - this.warnLog(`${this.device.remoteType}: ${this.accessory.displayName}` - + ` Connection Type: ${this.device.connectionType}, commands will not be sent to OpenAPI`); - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName}` - + ` Connection Type: ${this.device.connectionType}, disablePushDetails: ${this.disablePushDetail}`); + this.warnLog( + `${this.device.remoteType}: ${this.accessory.displayName}` + + ` Connection Type: ${this.device.connectionType}, commands will not be sent to OpenAPI`, + ); + this.debugLog( + `${this.device.remoteType}: ${this.accessory.displayName}` + + ` Connection Type: ${this.device.connectionType}, disablePushDetails: ${this.disablePushDetail}`, + ); this.updateHomeKitCharacteristics(); } } async CurrentTemperatureGet(): Promise { - if (this.meter) { - this.CurrentTemperature = this.meter.context?.CurrentTemperature - || this.meter.getService(this.platform.Service.TemperatureSensor)?.getCharacteristic(this.platform.Characteristic.CurrentTemperature).value - || 24; - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Using CurrentTemperature from ${this.meter.context?.deviceType} (${this.meter.context?.deviceID})`) - } else if (this.CurrentTemperature === undefined) { - this.CurrentTemperature = 24; - } else { - this.CurrentTemperature = this.accessory.context.CurrentTemperature; + if (this.meter?.context?.CurrentTemperature) { + this.accessory.context.CurrentTemperature = this.meter.context.CurrentTemperature; + this.debugLog( + `${this.device.remoteType}: ${this.accessory.displayName} ` + + `Using CurrentTemperature from ${this.meter.context.deviceType} (${this.meter.context.deviceID})`, + ); } + + this.CurrentTemperature = this.accessory.context.CurrentTemperature || 24; this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Get CurrentTemperature: ${this.CurrentTemperature}`); return this.CurrentTemperature; } async CurrentRelativeHumidityGet(): Promise { - if (this.meter) { - this.CurrentRelativeHumidity = this.meter.context?.CurrentRelativeHumidity - || this.meter.getService(this.platform.Service.HumiditySensor)?.getCharacteristic(this.platform.Characteristic.CurrentRelativeHumidity).value - || 0; - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Using CurrentRelativeHumidity from ${this.meter.context?.deviceType} (${this.meter.context?.deviceID})`) - } - else if (this.CurrentRelativeHumidity === undefined) { - this.CurrentRelativeHumidity = 0; - } - else { - this.CurrentRelativeHumidity = this.accessory.context.CurrentRelativeHumidity; + if (this.meter?.context?.CurrentRelativeHumidity) { + this.accessory.context.CurrentRelativeHumidity = this.meter.context.CurrentRelativeHumidity; + this.debugLog( + `${this.device.remoteType}: ${this.accessory.displayName} ` + + `Using CurrentRelativeHumidity from ${this.meter.context.deviceType} (${this.meter.context.deviceID})`, + ); } + + this.CurrentRelativeHumidity = this.accessory.context.CurrentRelativeHumidity || 0; this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Get CurrentRelativeHumidity: ${this.CurrentRelativeHumidity}`); return this.CurrentRelativeHumidity as CharacteristicValue; } @@ -317,7 +331,9 @@ export class AirConditioner { } else { this.CurrentFanSpeed = Number(value) + 1; } - this.RotationSpeed = this.CurrentFanSpeed; + this.RotationSpeed = value; + this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName}` + + `Set RotationSpeed: ${this.RotationSpeed}, CurrentFanSpeed: ${this.CurrentFanSpeed}`); this.pushAirConditionerStatusChanges(); } @@ -339,25 +355,12 @@ export class AirConditioner { } async TargetHeaterCoolerStateGet(): Promise { - if (this.ValidValues === this.valid012) { - this.TargetHeaterCoolerState = this.platform.Characteristic.TargetHeaterCoolerState.AUTO; - this.debugLog( - `${this.device.remoteType}: ${this.accessory.displayName} Get (AUTO) TargetHeaterCoolerState: ${this.CurrentHeaterCoolerState},` + - ` ValidValues: ${this.ValidValues}`, - ); - } else if (this.ValidValues === this.valid12) { - this.TargetHeaterCoolerState = - this.platform.Characteristic.TargetHeaterCoolerState.COOL || this.platform.Characteristic.TargetHeaterCoolerState.HEAT; - this.debugLog( - `${this.device.remoteType}: ${this.accessory.displayName} Get (COOL/HEAT) TargetHeaterCoolerState: ${this.CurrentHeaterCoolerState},` + - ` ValidValues: ${this.ValidValues}`, - ); - } else { - this.debugLog( - `${this.device.remoteType}: ${this.accessory.displayName} Get TargetHeaterCoolerState: ${this.CurrentHeaterCoolerState},` + - ` ValidValues: ${this.ValidValues}`, - ); - } + const targetState = this.TargetHeaterCoolerState || this.accessory.context.TargetHeaterCoolerState; + this.TargetHeaterCoolerState = this.ValidValues.includes(targetState) ? targetState : this.ValidValues[0]; + this.debugLog( + `${this.device.remoteType}: ${this.accessory.displayName} Get (${this.getTargetHeaterCoolerStateName()})` + + ` TargetHeaterCoolerState: ${this.TargetHeaterCoolerState}, ValidValues: ${this.ValidValues}, hide_automode: ${this.hide_automode}`, + ); return this.TargetHeaterCoolerState; } @@ -399,24 +402,29 @@ export class AirConditioner { } async CurrentHeaterCoolerStateGet(): Promise { - if (this.Active === this.platform.Characteristic.Active.ACTIVE) { - if (this.ThresholdTemperature < this.accessory.context.CurrentTemperature) { - this.CurrentHeaterCoolerState = this.platform.Characteristic.CurrentHeaterCoolerState.COOLING; - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName}` - + ` Get (COOLING) CurrentHeaterCoolerState: ${this.CurrentHeaterCoolerState}`); - } else if (this.ThresholdTemperature > this.accessory.context.CurrentTemperature) { - this.CurrentHeaterCoolerState = this.platform.Characteristic.CurrentHeaterCoolerState.HEATING; - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName}` - + ` Get (HEATING) CurrentHeaterCoolerState: ${this.CurrentHeaterCoolerState}`); - } - } else { - this.CurrentHeaterCoolerState = this.platform.Characteristic.CurrentHeaterCoolerState.INACTIVE; - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName}` - + ` Get (INACTIVE) CurrentHeaterCoolerState: ${this.CurrentHeaterCoolerState}`); - } + await this.UpdateCurrentHeaterCoolerState(); + this.debugLog( + `${this.device.remoteType}: ${this.accessory.displayName}` + + ` Get (${this.getTargetHeaterCoolerStateName()}) CurrentHeaterCoolerState: ${this.CurrentHeaterCoolerState}`, + ); + return this.CurrentHeaterCoolerState; } + + private getTargetHeaterCoolerStateName(): string { + switch (this.TargetHeaterCoolerState) { + case this.platform.Characteristic.TargetHeaterCoolerState.AUTO: + return 'AUTO'; + case this.platform.Characteristic.TargetHeaterCoolerState.HEAT: + return 'HEAT'; + case this.platform.Characteristic.TargetHeaterCoolerState.COOL: + return 'COOL'; + default: + return this.TargetHeaterCoolerState.toString(); + } + } + async ThresholdTemperatureGet(): Promise { await this.context(); this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Get ThresholdTemperature: ${this.ThresholdTemperature}`); @@ -425,8 +433,10 @@ export class AirConditioner { async ThresholdTemperatureSet(value: CharacteristicValue): Promise { this.ThresholdTemperature = value; - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Set ThresholdTemperature: ${this.ThresholdTemperature},` + - ` ThresholdTemperatureCached: ${this.accessory.context.ThresholdTemperature}`); + this.debugLog( + `${this.device.remoteType}: ${this.accessory.displayName} Set ThresholdTemperature: ${this.ThresholdTemperature},` + + ` ThresholdTemperatureCached: ${this.accessory.context.ThresholdTemperature}`, + ); this.pushAirConditionerStatusChanges(); } @@ -455,11 +465,12 @@ export class AirConditioner { if (this.meter) { if (this.CurrentRelativeHumidity === undefined) { this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} CurrentRelativeHumidity: ${this.CurrentRelativeHumidity}`); - } - else { + } else { this.accessory.context.CurrentRelativeHumidity = this.CurrentRelativeHumidity; this.coolerService?.updateCharacteristic(this.platform.Characteristic.CurrentRelativeHumidity, this.CurrentRelativeHumidity); - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} updateCharacteristic CurrentRelativeHumidity: ${this.CurrentRelativeHumidity}`); + this.debugLog( + `${this.device.remoteType}: ${this.accessory.displayName} updateCharacteristic CurrentRelativeHumidity: ${this.CurrentRelativeHumidity}`, + ); } } if (this.TargetHeaterCoolerState === undefined) { @@ -477,8 +488,8 @@ export class AirConditioner { this.accessory.context.CurrentHeaterCoolerState = this.CurrentHeaterCoolerState; this.coolerService?.updateCharacteristic(this.platform.Characteristic.CurrentHeaterCoolerState, this.CurrentHeaterCoolerState); this.debugLog( - `${this.device.remoteType}: ${this.accessory.displayName}` - + ` updateCharacteristic CurrentHeaterCoolerState: ${this.CurrentHeaterCoolerState}`, + `${this.device.remoteType}: ${this.accessory.displayName}` + + ` updateCharacteristic CurrentHeaterCoolerState: ${this.CurrentHeaterCoolerState}`, ); } if (this.ThresholdTemperature === undefined) { @@ -488,13 +499,12 @@ export class AirConditioner { this.coolerService?.updateCharacteristic(this.platform.Characteristic.HeatingThresholdTemperature, this.ThresholdTemperature); this.coolerService?.updateCharacteristic(this.platform.Characteristic.CoolingThresholdTemperature, this.ThresholdTemperature); this.debugLog( - `${this.device.remoteType}: ${this.accessory.displayName}` - + ` updateCharacteristic ThresholdTemperature: ${this.ThresholdTemperature}`, + `${this.device.remoteType}: ${this.accessory.displayName}` + ` updateCharacteristic ThresholdTemperature: ${this.ThresholdTemperature}`, ); } } - async disablePushOnChanges({ device }: { device: irdevice & irDevicesConfig; }): Promise { + async disablePushOnChanges({ device }: { device: irdevice & irDevicesConfig }): Promise { if (device.disablePushOn === undefined) { this.disablePushOn = false; } else { @@ -502,7 +512,7 @@ export class AirConditioner { } } - async disablePushOffChanges({ device }: { device: irdevice & irDevicesConfig; }): Promise { + async disablePushOffChanges({ device }: { device: irdevice & irDevicesConfig }): Promise { if (device.disablePushOff === undefined) { this.disablePushOff = false; } else { @@ -510,7 +520,7 @@ export class AirConditioner { } } - async disablePushDetailChanges({ device }: { device: irdevice & irDevicesConfig; }): Promise { + async disablePushDetailChanges({ device }: { device: irdevice & irDevicesConfig }): Promise { if (device.disablePushDetail === undefined) { this.disablePushDetail = false; } else { @@ -563,8 +573,10 @@ export class AirConditioner { this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Device is offline, statusCode: ${statusCode}`); break; case 171: - this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` - + `Hub: ${this.device.hubDeviceId}`); + this.errorLog( + `${this.device.remoteType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` + + `Hub: ${this.device.hubDeviceId}`, + ); break; case 190: this.errorLog( @@ -579,12 +591,14 @@ export class AirConditioner { this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Request successful, statusCode: ${statusCode}`); break; default: - this.infoLog(`${this.device.remoteType}: ${this.accessory.displayName} Unknown statusCode: ` - + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`); + this.infoLog( + `${this.device.remoteType}: ${this.accessory.displayName} Unknown statusCode: ` + + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`, + ); } } - async apiError({ e }: { e: any; }): Promise { + async apiError({ e }: { e: any }): Promise { this.coolerService.updateCharacteristic(this.platform.Characteristic.Active, e); this.coolerService.updateCharacteristic(this.platform.Characteristic.RotationSpeed, e); this.coolerService.updateCharacteristic(this.platform.Characteristic.CurrentTemperature, e); @@ -595,10 +609,11 @@ export class AirConditioner { this.coolerService.updateCharacteristic(this.platform.Characteristic.CoolingThresholdTemperature, e); } - FirmwareRevision({ accessory, device }: { accessory: PlatformAccessory; device: irdevice & irDevicesConfig; }): string { + FirmwareRevision({ accessory, device }: { accessory: PlatformAccessory; device: irdevice & irDevicesConfig }): string { let FirmwareRevision: string; - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName}` - + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`); + this.debugLog( + `${this.device.remoteType}: ${this.accessory.displayName}` + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`, + ); this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} device.firmware: ${device.firmware}`); this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`); if (accessory.context.FirmwareRevision) { @@ -619,18 +634,23 @@ export class AirConditioner { } else { this.Active = this.accessory.context.Active; } - if (this.CurrentTemperature === undefined) { - this.CurrentTemperature = 24; - } else if (this.CurrentTemperature) { - this.CurrentTemperature; - } else if (this.accessory.context.CurrentTemperature === undefined) { + + if (this.CurrentTemperature === undefined && this.accessory.context.CurrentTemperature === undefined) { this.CurrentTemperature = 24; } else { - this.CurrentTemperature = this.accessory.context.CurrentTemperature; + this.CurrentTemperature = this.CurrentTemperature || this.accessory.context.CurrentTemperature; } - if (this.ThresholdTemperature === undefined) { + if (this.ThresholdTemperature === undefined && this.accessory.context.ThresholdTemperature === undefined) { this.ThresholdTemperature = 24; + } else { + this.ThresholdTemperature = this.ThresholdTemperature || this.accessory.context.ThresholdTemperature; + } + + if (this.RotationSpeed === undefined && this.accessory.context.RotationSpeed === undefined) { + this.RotationSpeed = 4; + } else { + this.RotationSpeed = this.RotationSpeed || this.accessory.context.RotationSpeed; } if (this.device.irair?.hide_automode) { @@ -641,19 +661,16 @@ export class AirConditioner { this.accessory.context.hide_automode = this.hide_automode; } - if (this.device.irair?.meterUuid) { - this.meter = this.platform.accessories.find((accessory) => accessory.UUID === this.device.irair?.meterUuid); - } if (this.meter) { - if (this.CurrentRelativeHumidity === undefined) { + if (this.CurrentRelativeHumidity === undefined && this.accessory.context.CurrentRelativeHumidity === undefined) { this.CurrentRelativeHumidity = 0; } else { - this.CurrentRelativeHumidity = this.accessory.context.CurrentRelativeHumidity; + this.CurrentRelativeHumidity = this.CurrentRelativeHumidity || this.accessory.context.CurrentRelativeHumidity; } } } - async config({ device }: { device: irdevice & irDevicesConfig; }): Promise { + async config({ device }: { device: irdevice & irDevicesConfig }): Promise { let config = {}; if (device.irair) { config = device.irair; @@ -686,11 +703,11 @@ export class AirConditioner { config['disablePushDetail'] = device.disablePushDetail; } if (Object.entries(config).length !== 0) { - this.infoLog(`${this.device.remoteType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); + this.debugWarnLog(`${this.device.remoteType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); } } - async logs({ device }: { device: irdevice & irDevicesConfig; }): Promise { + async logs({ device }: { device: irdevice & irDevicesConfig }): Promise { if (this.platform.debugMode) { this.deviceLogging = this.accessory.context.logging = 'debugMode'; this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Using Debug Mode Logging: ${this.deviceLogging}`); @@ -753,4 +770,3 @@ export class AirConditioner { return this.deviceLogging.includes('debug') || this.deviceLogging === 'standard'; } } - diff --git a/src/irdevice/airpurifier.ts b/src/irdevice/airpurifier.ts index 7ba4cdec..db6e898b 100644 --- a/src/irdevice/airpurifier.ts +++ b/src/irdevice/airpurifier.ts @@ -1,7 +1,7 @@ +import { CharacteristicValue, PlatformAccessory, Service } from 'homebridge'; import { request } from 'undici'; import { SwitchBotPlatform } from '../platform'; -import { irDevicesConfig, irdevice, Devices } from '../settings'; -import { CharacteristicValue, PlatformAccessory, Service } from 'homebridge'; +import { Devices, irDevicesConfig, irdevice } from '../settings'; /** * Platform Accessory @@ -38,13 +38,17 @@ export class AirPurifier { disablePushOff?: boolean; deviceLogging!: string; - constructor(private readonly platform: SwitchBotPlatform, private accessory: PlatformAccessory, public device: irdevice & irDevicesConfig) { + constructor( + private readonly platform: SwitchBotPlatform, + private accessory: PlatformAccessory, + public device: irdevice & irDevicesConfig, + ) { // default placeholders this.logs(device); - this.config(device); this.context(); this.disablePushOnChanges({ device }); this.disablePushOffChanges({ device }); + this.config(device); // set accessory information accessory @@ -129,38 +133,44 @@ export class AirPurifier { * AirPurifier: "command" "highSpeed" "default" = fan speed to high */ async pushAirPurifierOnChanges(): Promise { - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushAirPurifierOnChanges Active: ${this.Active},` - + ` disablePushOn: ${this.disablePushOn}`); + this.debugLog( + `${this.device.remoteType}: ${this.accessory.displayName} pushAirPurifierOnChanges Active: ${this.Active},` + + ` disablePushOn: ${this.disablePushOn}`, + ); if (this.Active === this.platform.Characteristic.Active.ACTIVE && !this.disablePushOn) { const commandType: string = await this.commandType(); const command: string = await this.commandOn(); const bodyChange = JSON.stringify({ - 'command': command, - 'parameter': 'default', - 'commandType': commandType, + command: command, + parameter: 'default', + commandType: commandType, }); await this.pushChanges(bodyChange); } } async pushAirPurifierOffChanges(): Promise { - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushAirPurifierOffChanges Active: ${this.Active},` - + ` disablePushOff: ${this.disablePushOff}`); + this.debugLog( + `${this.device.remoteType}: ${this.accessory.displayName} pushAirPurifierOffChanges Active: ${this.Active},` + + ` disablePushOff: ${this.disablePushOff}`, + ); if (this.Active === this.platform.Characteristic.Active.INACTIVE && !this.disablePushOn) { const commandType: string = await this.commandType(); const command: string = await this.commandOff(); const bodyChange = JSON.stringify({ - 'command': command, - 'parameter': 'default', - 'commandType': commandType, + command: command, + parameter: 'default', + commandType: commandType, }); await this.pushChanges(bodyChange); } } async pushAirPurifierStatusChanges(): Promise { - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushAirPurifierStatusChanges Active: ${this.Active},` - + ` disablePushOff: ${this.disablePushOff}, disablePushOn: ${this.disablePushOn}`); + this.debugLog( + `${this.device.remoteType}: ${this.accessory.displayName} pushAirPurifierStatusChanges Active: ${this.Active},` + + ` disablePushOff: ${this.disablePushOff}, disablePushOn: ${this.disablePushOn}`, + ); if (!this.Busy) { this.Busy = true; this.CurrentHeaterCoolerState = this.platform.Characteristic.CurrentHeaterCoolerState.IDLE; @@ -172,17 +182,19 @@ export class AirPurifier { } async pushAirPurifierDetailsChanges(): Promise { - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushAirPurifierDetailsChanges Active: ${this.Active},` - + ` disablePushOff: ${this.disablePushOff}, disablePushOn: ${this.disablePushOn}`); + this.debugLog( + `${this.device.remoteType}: ${this.accessory.displayName} pushAirPurifierDetailsChanges Active: ${this.Active},` + + ` disablePushOff: ${this.disablePushOff}, disablePushOn: ${this.disablePushOn}`, + ); this.CurrentAPTemp = this.CurrentTemperature || 24; this.CurrentAPMode = this.CurrentMode || 1; this.CurrentAPFanSpeed = this.CurrentFanSpeed || 1; this.APActive = this.Active === 1 ? 'on' : 'off'; const parameter = `${this.CurrentAPTemp},${this.CurrentAPMode},${this.CurrentAPFanSpeed},${this.APActive}`; const bodyChange = JSON.stringify({ - 'command': 'setAll', - 'parameter': `${parameter}`, - 'commandType': 'command', + command: 'setAll', + parameter: `${parameter}`, + commandType: 'command', }); if (this.Active === 1) { if ((Number(this.CurrentTemperature) || 24) < (this.LastTemperature || 30)) { @@ -199,27 +211,30 @@ export class AirPurifier { async pushChanges(bodyChange: any): Promise { this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushChanges`); if (this.device.connectionType === 'OpenAPI') { - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${bodyChange},`); + this.infoLog(`${this.device.remoteType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${bodyChange},`); try { const { body, statusCode, headers } = await request(`${Devices}/${this.device.deviceId}/commands`, { body: bodyChange, method: 'POST', headers: this.platform.generateHeaders(), }); - const deviceStatus = await body.json(); + const deviceStatus: any = await body.json(); this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`); this.statusCode(statusCode); this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`); this.updateHomeKitCharacteristics(); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + this.errorLog( + `${this.device.remoteType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, ); } } else { - this.warnLog(`${this.device.remoteType}: ${this.accessory.displayName}` - + ` Connection Type: ${this.device.connectionType}, commands will not be sent to OpenAPI`); + this.warnLog( + `${this.device.remoteType}: ${this.accessory.displayName}` + + ` Connection Type: ${this.device.connectionType}, commands will not be sent to OpenAPI`, + ); } } @@ -236,8 +251,9 @@ export class AirPurifier { } else { this.accessory.context.CurrentAirPurifierState = this.CurrentAirPurifierState; this.airPurifierService?.updateCharacteristic(this.platform.Characteristic.CurrentAirPurifierState, this.CurrentAirPurifierState); - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName}` - + ` updateCharacteristic CurrentAirPurifierState: ${this.CurrentAirPurifierState}`); + this.debugLog( + `${this.device.remoteType}: ${this.accessory.displayName}` + ` updateCharacteristic CurrentAirPurifierState: ${this.CurrentAirPurifierState}`, + ); } if (this.CurrentHeaterCoolerState === undefined) { this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} CurrentHeaterCoolerState: ${this.CurrentHeaterCoolerState}`); @@ -245,13 +261,13 @@ export class AirPurifier { this.accessory.context.CurrentHeaterCoolerState = this.CurrentHeaterCoolerState; this.airPurifierService?.updateCharacteristic(this.platform.Characteristic.CurrentHeaterCoolerState, this.CurrentHeaterCoolerState); this.debugLog( - `${this.device.remoteType}: ${this.accessory.displayName}` - + ` updateCharacteristic CurrentHeaterCoolerState: ${this.CurrentHeaterCoolerState}`, + `${this.device.remoteType}: ${this.accessory.displayName}` + + ` updateCharacteristic CurrentHeaterCoolerState: ${this.CurrentHeaterCoolerState}`, ); } } - async disablePushOnChanges({ device }: { device: irdevice & irDevicesConfig; }): Promise { + async disablePushOnChanges({ device }: { device: irdevice & irDevicesConfig }): Promise { if (device.disablePushOn === undefined) { this.disablePushOn = false; } else { @@ -259,7 +275,7 @@ export class AirPurifier { } } - async disablePushOffChanges({ device }: { device: irdevice & irDevicesConfig; }): Promise { + async disablePushOffChanges({ device }: { device: irdevice & irDevicesConfig }): Promise { if (device.disablePushOff === undefined) { this.disablePushOff = false; } else { @@ -312,8 +328,10 @@ export class AirPurifier { this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Device is offline, statusCode: ${statusCode}`); break; case 171: - this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` - + `Hub: ${this.device.hubDeviceId}`); + this.errorLog( + `${this.device.remoteType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` + + `Hub: ${this.device.hubDeviceId}`, + ); break; case 190: this.errorLog( @@ -328,8 +346,10 @@ export class AirPurifier { this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Request successful, statusCode: ${statusCode}`); break; default: - this.infoLog(`${this.device.remoteType}: ${this.accessory.displayName} Unknown statusCode: ` - + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`); + this.infoLog( + `${this.device.remoteType}: ${this.accessory.displayName} Unknown statusCode: ` + + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`, + ); } } @@ -342,8 +362,9 @@ export class AirPurifier { FirmwareRevision(accessory: PlatformAccessory, device: irdevice & irDevicesConfig): string { let FirmwareRevision: string; - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName}` - + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`); + this.debugLog( + `${this.device.remoteType}: ${this.accessory.displayName}` + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`, + ); this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} device.firmware: ${device.firmware}`); this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`); if (accessory.context.FirmwareRevision) { @@ -399,7 +420,7 @@ export class AirPurifier { config['disablePushOff'] = device.disablePushOff; } if (Object.entries(config).length !== 0) { - this.infoLog(`${this.device.remoteType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); + this.debugWarnLog(`${this.device.remoteType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); } } diff --git a/src/irdevice/camera.ts b/src/irdevice/camera.ts index f2fe4dea..80e9a0c3 100644 --- a/src/irdevice/camera.ts +++ b/src/irdevice/camera.ts @@ -1,7 +1,7 @@ +import { CharacteristicValue, PlatformAccessory, Service } from 'homebridge'; import { request } from 'undici'; import { SwitchBotPlatform } from '../platform'; -import { irDevicesConfig, irdevice, Devices } from '../settings'; -import { CharacteristicValue, PlatformAccessory, Service } from 'homebridge'; +import { Devices, irDevicesConfig, irdevice } from '../settings'; /** * Platform Accessory @@ -20,13 +20,17 @@ export class Camera { disablePushOff?: boolean; deviceLogging!: string; - constructor(private readonly platform: SwitchBotPlatform, private accessory: PlatformAccessory, public device: irdevice & irDevicesConfig) { + constructor( + private readonly platform: SwitchBotPlatform, + private accessory: PlatformAccessory, + public device: irdevice & irDevicesConfig, + ) { // default placeholders this.logs(device); - this.config(device); this.context(); this.disablePushOnChanges({ device }); this.disablePushOffChanges({ device }); + this.config(device); // set accessory information accessory @@ -80,30 +84,30 @@ export class Camera { * Camera - "command" "channelSub" "default" = previous channel */ async pushOnChanges(): Promise { - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushOnChanges On: ${this.On},` - + ` disablePushOn: ${this.disablePushOn}`); + this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushOnChanges On: ${this.On},` + ` disablePushOn: ${this.disablePushOn}`); if (this.On && !this.disablePushOn) { const commandType: string = await this.commandType(); const command: string = await this.commandOn(); const bodyChange = JSON.stringify({ - 'command': command, - 'parameter': 'default', - 'commandType': commandType, + command: command, + parameter: 'default', + commandType: commandType, }); await this.pushChanges(bodyChange); } } async pushOffChanges(): Promise { - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushOffChanges On: ${this.On},` - + ` disablePushOff: ${this.disablePushOff}`); + this.debugLog( + `${this.device.remoteType}: ${this.accessory.displayName} pushOffChanges On: ${this.On},` + ` disablePushOff: ${this.disablePushOff}`, + ); if (!this.On && !this.disablePushOff) { const commandType: string = await this.commandType(); const command: string = await this.commandOff(); const bodyChange = JSON.stringify({ - 'command': command, - 'parameter': 'default', - 'commandType': commandType, + command: command, + parameter: 'default', + commandType: commandType, }); await this.pushChanges(bodyChange); } @@ -112,27 +116,30 @@ export class Camera { async pushChanges(bodyChange: any): Promise { this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushChanges`); if (this.device.connectionType === 'OpenAPI') { - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${bodyChange},`); + this.infoLog(`${this.device.remoteType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${bodyChange},`); try { const { body, statusCode, headers } = await request(`${Devices}/${this.device.deviceId}/commands`, { body: bodyChange, method: 'POST', headers: this.platform.generateHeaders(), }); - const deviceStatus = await body.json(); + const deviceStatus: any = await body.json(); this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`); this.statusCode(statusCode); this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`); this.updateHomeKitCharacteristics(); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + this.errorLog( + `${this.device.remoteType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, ); } } else { - this.warnLog(`${this.device.remoteType}: ${this.accessory.displayName}` - + ` Connection Type: ${this.device.connectionType}, commands will not be sent to OpenAPI`); + this.warnLog( + `${this.device.remoteType}: ${this.accessory.displayName}` + + ` Connection Type: ${this.device.connectionType}, commands will not be sent to OpenAPI`, + ); } } @@ -146,7 +153,7 @@ export class Camera { } } - async disablePushOnChanges({ device }: { device: irdevice & irDevicesConfig; }): Promise { + async disablePushOnChanges({ device }: { device: irdevice & irDevicesConfig }): Promise { if (device.disablePushOn === undefined) { this.disablePushOn = false; } else { @@ -154,7 +161,7 @@ export class Camera { } } - async disablePushOffChanges({ device }: { device: irdevice & irDevicesConfig; }): Promise { + async disablePushOffChanges({ device }: { device: irdevice & irDevicesConfig }): Promise { if (device.disablePushOff === undefined) { this.disablePushOff = false; } else { @@ -207,8 +214,10 @@ export class Camera { this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Device is offline, statusCode: ${statusCode}`); break; case 171: - this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` - + `Hub: ${this.device.hubDeviceId}`); + this.errorLog( + `${this.device.remoteType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` + + `Hub: ${this.device.hubDeviceId}`, + ); break; case 190: this.errorLog( @@ -223,8 +232,10 @@ export class Camera { this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Request successful, statusCode: ${statusCode}`); break; default: - this.infoLog(`${this.device.remoteType}: ${this.accessory.displayName} Unknown statusCode: ` - + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`); + this.infoLog( + `${this.device.remoteType}: ${this.accessory.displayName} Unknown statusCode: ` + + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`, + ); } } @@ -234,8 +245,9 @@ export class Camera { FirmwareRevision(accessory: PlatformAccessory, device: irdevice & irDevicesConfig): string { let FirmwareRevision: string; - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName}` - + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`); + this.debugLog( + `${this.device.remoteType}: ${this.accessory.displayName}` + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`, + ); this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} device.firmware: ${device.firmware}`); this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`); if (accessory.context.FirmwareRevision) { @@ -286,7 +298,7 @@ export class Camera { config['disablePushOff'] = device.disablePushOff; } if (Object.entries(config).length !== 0) { - this.infoLog(`${this.device.remoteType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); + this.debugWarnLog(`${this.device.remoteType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); } } diff --git a/src/irdevice/fan.ts b/src/irdevice/fan.ts index d00aba09..62ec5d8c 100644 --- a/src/irdevice/fan.ts +++ b/src/irdevice/fan.ts @@ -1,7 +1,7 @@ +import { CharacteristicValue, PlatformAccessory, Service } from 'homebridge'; import { request } from 'undici'; import { SwitchBotPlatform } from '../platform'; -import { CharacteristicValue, PlatformAccessory, Service } from 'homebridge'; -import { irdevice, irDevicesConfig, Devices } from '../settings'; +import { Devices, irDevicesConfig, irdevice } from '../settings'; /** * Platform Accessory @@ -30,13 +30,17 @@ export class Fan { disablePushOff?: boolean; deviceLogging!: string; - constructor(private readonly platform: SwitchBotPlatform, private accessory: PlatformAccessory, public device: irdevice & irDevicesConfig) { + constructor( + private readonly platform: SwitchBotPlatform, + private accessory: PlatformAccessory, + public device: irdevice & irDevicesConfig, + ) { // default placeholders this.logs(device); - this.config(device); this.context(); this.disablePushOnChanges({ device }); this.disablePushOffChanges({ device }); + this.config(device); // set accessory information accessory @@ -170,30 +174,33 @@ export class Fan { * Fan - "command" "highSpeed" "default" = fan speed to high */ async pushFanOnChanges(): Promise { - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushFanOnChanges Active: ${this.Active},` - + ` disablePushOn: ${this.disablePushOn}`); + this.debugLog( + `${this.device.remoteType}: ${this.accessory.displayName} pushFanOnChanges Active: ${this.Active},` + ` disablePushOn: ${this.disablePushOn}`, + ); if (this.Active === this.platform.Characteristic.Active.ACTIVE && !this.disablePushOn) { const commandType: string = await this.commandType(); const command: string = await this.commandOn(); const bodyChange = JSON.stringify({ - 'command': command, - 'parameter': 'default', - 'commandType': commandType, + command: command, + parameter: 'default', + commandType: commandType, }); await this.pushChanges(bodyChange); } } async pushFanOffChanges(): Promise { - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushLightOffChanges Active: ${this.Active},` - + ` disablePushOff: ${this.disablePushOff}`); + this.debugLog( + `${this.device.remoteType}: ${this.accessory.displayName} pushLightOffChanges Active: ${this.Active},` + + ` disablePushOff: ${this.disablePushOff}`, + ); if (this.Active === this.platform.Characteristic.Active.INACTIVE && !this.disablePushOff) { const commandType: string = await this.commandType(); const command: string = await this.commandOff(); const bodyChange = JSON.stringify({ - 'command': command, - 'parameter': 'default', - 'commandType': commandType, + command: command, + parameter: 'default', + commandType: commandType, }); await this.pushChanges(bodyChange); } @@ -201,27 +208,27 @@ export class Fan { async pushFanSpeedUpChanges(): Promise { const bodyChange = JSON.stringify({ - 'command': 'highSpeed', - 'parameter': 'default', - 'commandType': 'command', + command: 'highSpeed', + parameter: 'default', + commandType: 'command', }); await this.pushChanges(bodyChange); } async pushFanSpeedDownChanges(): Promise { const bodyChange = JSON.stringify({ - 'command': 'lowSpeed', - 'parameter': 'default', - 'commandType': 'command', + command: 'lowSpeed', + parameter: 'default', + commandType: 'command', }); await this.pushChanges(bodyChange); } async pushFanSwingChanges(): Promise { const bodyChange = JSON.stringify({ - 'command': 'swing', - 'parameter': 'default', - 'commandType': 'command', + command: 'swing', + parameter: 'default', + commandType: 'command', }); await this.pushChanges(bodyChange); } @@ -229,27 +236,30 @@ export class Fan { async pushChanges(bodyChange: any): Promise { this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushChanges`); if (this.device.connectionType === 'OpenAPI') { - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${bodyChange},`); + this.infoLog(`${this.device.remoteType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${bodyChange},`); try { const { body, statusCode, headers } = await request(`${Devices}/${this.device.deviceId}/commands`, { body: bodyChange, method: 'POST', headers: this.platform.generateHeaders(), }); - const deviceStatus = await body.json(); + const deviceStatus: any = await body.json(); this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`); this.statusCode(statusCode); this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`); this.updateHomeKitCharacteristics(); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + this.errorLog( + `${this.device.remoteType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, ); } } else { - this.warnLog(`${this.device.remoteType}: ${this.accessory.displayName}` - + ` Connection Type: ${this.device.connectionType}, commands will not be sent to OpenAPI`); + this.warnLog( + `${this.device.remoteType}: ${this.accessory.displayName}` + + ` Connection Type: ${this.device.connectionType}, commands will not be sent to OpenAPI`, + ); } } @@ -277,7 +287,7 @@ export class Fan { } } - async disablePushOnChanges({ device }: { device: irdevice & irDevicesConfig; }): Promise { + async disablePushOnChanges({ device }: { device: irdevice & irDevicesConfig }): Promise { if (device.disablePushOn === undefined) { this.disablePushOn = false; } else { @@ -285,7 +295,7 @@ export class Fan { } } - async disablePushOffChanges({ device }: { device: irdevice & irDevicesConfig; }): Promise { + async disablePushOffChanges({ device }: { device: irdevice & irDevicesConfig }): Promise { if (device.disablePushOff === undefined) { this.disablePushOff = false; } else { @@ -338,8 +348,10 @@ export class Fan { this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Device is offline, statusCode: ${statusCode}`); break; case 171: - this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` - + `Hub: ${this.device.hubDeviceId}`); + this.errorLog( + `${this.device.remoteType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` + + `Hub: ${this.device.hubDeviceId}`, + ); break; case 190: this.errorLog( @@ -354,8 +366,10 @@ export class Fan { this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Request successful, statusCode: ${statusCode}`); break; default: - this.infoLog(`${this.device.remoteType}: ${this.accessory.displayName} Unknown statusCode: ` - + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`); + this.infoLog( + `${this.device.remoteType}: ${this.accessory.displayName} Unknown statusCode: ` + + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`, + ); } } @@ -367,8 +381,9 @@ export class Fan { FirmwareRevision(accessory: PlatformAccessory, device: irdevice & irDevicesConfig): string { let FirmwareRevision: string; - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName}` - + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`); + this.debugLog( + `${this.device.remoteType}: ${this.accessory.displayName}` + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`, + ); this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} device.firmware: ${device.firmware}`); this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`); if (accessory.context.FirmwareRevision) { @@ -389,7 +404,6 @@ export class Fan { } } - async config(device: irdevice & irDevicesConfig): Promise { let config = {}; if (device.irfan) { @@ -420,7 +434,7 @@ export class Fan { config['disablePushOff'] = device.disablePushOff; } if (Object.entries(config).length !== 0) { - this.infoLog(`${this.device.remoteType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); + this.debugWarnLog(`${this.device.remoteType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); } } diff --git a/src/irdevice/light.ts b/src/irdevice/light.ts index b95286aa..76af0463 100644 --- a/src/irdevice/light.ts +++ b/src/irdevice/light.ts @@ -1,7 +1,7 @@ +import { CharacteristicValue, PlatformAccessory, Service } from 'homebridge'; import { request } from 'undici'; import { SwitchBotPlatform } from '../platform'; -import { irDevicesConfig, irdevice, Devices } from '../settings'; -import { CharacteristicValue, PlatformAccessory, Service } from 'homebridge'; +import { Devices, irDevicesConfig, irdevice } from '../settings'; /** * Platform Accessory @@ -20,13 +20,17 @@ export class Light { disablePushOff?: boolean; deviceLogging!: string; - constructor(private readonly platform: SwitchBotPlatform, private accessory: PlatformAccessory, public device: irdevice & irDevicesConfig) { + constructor( + private readonly platform: SwitchBotPlatform, + private accessory: PlatformAccessory, + public device: irdevice & irDevicesConfig, + ) { // default placeholders this.logs(device); - this.config(device); this.context(); this.disablePushOnChanges({ device }); this.disablePushOffChanges({ device }); + this.config(device); // set accessory information accessory @@ -84,30 +88,32 @@ export class Light { * Light - "command" "channelSub" "default" = previous channel */ async pushLightOnChanges(): Promise { - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushLightOnChanges On: ${this.On},` - + ` disablePushOn: ${this.disablePushOn}`); + this.debugLog( + `${this.device.remoteType}: ${this.accessory.displayName} pushLightOnChanges On: ${this.On},` + ` disablePushOn: ${this.disablePushOn}`, + ); if (this.On && !this.disablePushOn) { const commandType: string = await this.commandType(); const command: string = await this.commandOn(); const bodyChange = JSON.stringify({ - 'command': command, - 'parameter': 'default', - 'commandType': commandType, + command: command, + parameter: 'default', + commandType: commandType, }); await this.pushChanges(bodyChange); } } async pushLightOffChanges(): Promise { - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushLightOffChanges On: ${this.On},` - + ` disablePushOff: ${this.disablePushOff}`); + this.debugLog( + `${this.device.remoteType}: ${this.accessory.displayName} pushLightOffChanges On: ${this.On},` + ` disablePushOff: ${this.disablePushOff}`, + ); if (!this.On && !this.disablePushOff) { const commandType: string = await this.commandType(); const command: string = await this.commandOff(); const bodyChange = JSON.stringify({ - 'command': command, - 'parameter': 'default', - 'commandType': commandType, + command: command, + parameter: 'default', + commandType: commandType, }); await this.pushChanges(bodyChange); } @@ -115,18 +121,18 @@ export class Light { async pushLightBrightnessUpChanges(): Promise { const bodyChange = JSON.stringify({ - 'command': 'brightnessUp', - 'parameter': 'default', - 'commandType': 'command', + command: 'brightnessUp', + parameter: 'default', + commandType: 'command', }); await this.pushChanges(bodyChange); } async pushLightBrightnessDownChanges(): Promise { const bodyChange = JSON.stringify({ - 'command': 'brightnessDown', - 'parameter': 'default', - 'commandType': 'command', + command: 'brightnessDown', + parameter: 'default', + commandType: 'command', }); await this.pushChanges(bodyChange); } @@ -134,14 +140,14 @@ export class Light { async pushChanges(bodyChange: any): Promise { this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushChanges`); if (this.device.connectionType === 'OpenAPI') { - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${bodyChange},`); + this.infoLog(`${this.device.remoteType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${bodyChange},`); try { const { body, statusCode, headers } = await request(`${Devices}/${this.device.deviceId}/commands`, { body: bodyChange, method: 'POST', headers: this.platform.generateHeaders(), }); - const deviceStatus = await body.json(); + const deviceStatus: any = await body.json(); this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`); this.statusCode(statusCode); this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`); @@ -149,13 +155,16 @@ export class Light { this.updateHomeKitCharacteristics(); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + this.errorLog( + `${this.device.remoteType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, ); } } else { - this.warnLog(`${this.device.remoteType}: ${this.accessory.displayName}` - + ` Connection Type: ${this.device.connectionType}, commands will not be sent to OpenAPI`); + this.warnLog( + `${this.device.remoteType}: ${this.accessory.displayName}` + + ` Connection Type: ${this.device.connectionType}, commands will not be sent to OpenAPI`, + ); } } @@ -169,7 +178,7 @@ export class Light { } } - async disablePushOnChanges({ device }: { device: irdevice & irDevicesConfig; }): Promise { + async disablePushOnChanges({ device }: { device: irdevice & irDevicesConfig }): Promise { if (device.disablePushOn === undefined) { this.disablePushOn = false; } else { @@ -177,7 +186,7 @@ export class Light { } } - async disablePushOffChanges({ device }: { device: irdevice & irDevicesConfig; }): Promise { + async disablePushOffChanges({ device }: { device: irdevice & irDevicesConfig }): Promise { if (device.disablePushOff === undefined) { this.disablePushOff = false; } else { @@ -230,8 +239,10 @@ export class Light { this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Device is offline, statusCode: ${statusCode}`); break; case 171: - this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` - + `Hub: ${this.device.hubDeviceId}`); + this.errorLog( + `${this.device.remoteType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` + + `Hub: ${this.device.hubDeviceId}`, + ); break; case 190: this.errorLog( @@ -246,8 +257,10 @@ export class Light { this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Request successful, statusCode: ${statusCode}`); break; default: - this.infoLog(`${this.device.remoteType}: ${this.accessory.displayName} Unknown statusCode: ` - + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`); + this.infoLog( + `${this.device.remoteType}: ${this.accessory.displayName} Unknown statusCode: ` + + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`, + ); } } @@ -257,8 +270,9 @@ export class Light { FirmwareRevision(accessory: PlatformAccessory, device: irdevice & irDevicesConfig): string { let FirmwareRevision: string; - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName}` - + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`); + this.debugLog( + `${this.device.remoteType}: ${this.accessory.displayName}` + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`, + ); this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} device.firmware: ${device.firmware}`); this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`); if (accessory.context.FirmwareRevision) { @@ -309,7 +323,7 @@ export class Light { config['disablePushOff'] = device.disablePushOff; } if (Object.entries(config).length !== 0) { - this.infoLog(`${this.device.remoteType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); + this.debugWarnLog(`${this.device.remoteType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); } } diff --git a/src/irdevice/other.ts b/src/irdevice/other.ts index 67c6e694..33c31fbd 100644 --- a/src/irdevice/other.ts +++ b/src/irdevice/other.ts @@ -1,7 +1,7 @@ +import { CharacteristicValue, PlatformAccessory, Service } from 'homebridge'; import { request } from 'undici'; import { SwitchBotPlatform } from '../platform'; -import { irDevicesConfig, irdevice, Devices } from '../settings'; -import { CharacteristicValue, PlatformAccessory, Service } from 'homebridge'; +import { Devices, irDevicesConfig, irdevice } from '../settings'; /** * Platform Accessory @@ -21,14 +21,18 @@ export class Others { deviceLogging!: string; otherDeviceType?: string; - constructor(private readonly platform: SwitchBotPlatform, private accessory: PlatformAccessory, public device: irdevice & irDevicesConfig) { + constructor( + private readonly platform: SwitchBotPlatform, + private accessory: PlatformAccessory, + public device: irdevice & irDevicesConfig, + ) { // default placeholders this.logs(device); this.deviceType(device); - this.config(device); this.context(); this.disablePushOnChanges({ device }); this.disablePushOffChanges({ device }); + this.config(device); // set accessory information accessory @@ -87,16 +91,18 @@ export class Others { * Other - "command" "channelSub" "default" = previous channel */ async pushOnChanges(): Promise { - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushOnChanges Active: ${this.Active},` - + ` disablePushOn: ${this.disablePushOn}, customize: ${this.device.customize}, customOn: ${this.device.customOn}`); + this.debugLog( + `${this.device.remoteType}: ${this.accessory.displayName} pushOnChanges Active: ${this.Active},` + + ` disablePushOn: ${this.disablePushOn}, customize: ${this.device.customize}, customOn: ${this.device.customOn}`, + ); if (this.device.customize) { if (this.Active === this.platform.Characteristic.Active.ACTIVE && !this.disablePushOn) { const commandType: string = await this.commandType(); const command: string = await this.commandOn(); const bodyChange = JSON.stringify({ - 'command': command, - 'parameter': 'default', - 'commandType': commandType, + command: command, + parameter: 'default', + commandType: commandType, }); await this.pushChanges(bodyChange); } @@ -106,16 +112,18 @@ export class Others { } async pushOffChanges(): Promise { - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushOffChanges Active: ${this.Active},` - + ` disablePushOff: ${this.disablePushOff}, customize: ${this.device.customize}, customOff: ${this.device.customOff}`); + this.debugLog( + `${this.device.remoteType}: ${this.accessory.displayName} pushOffChanges Active: ${this.Active},` + + ` disablePushOff: ${this.disablePushOff}, customize: ${this.device.customize}, customOff: ${this.device.customOff}`, + ); if (this.device.customize) { if (this.Active === this.platform.Characteristic.Active.INACTIVE && !this.disablePushOff) { const commandType: string = await this.commandType(); const command: string = await this.commandOff(); const bodyChange = JSON.stringify({ - 'command': command, - 'parameter': 'default', - 'commandType': commandType, + command: command, + parameter: 'default', + commandType: commandType, }); await this.pushChanges(bodyChange); } @@ -127,27 +135,30 @@ export class Others { async pushChanges(bodyChange: any): Promise { this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushChanges`); if (this.device.connectionType === 'OpenAPI') { - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${bodyChange},`); + this.infoLog(`${this.device.remoteType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${bodyChange},`); try { const { body, statusCode, headers } = await request(`${Devices}/${this.device.deviceId}/commands`, { body: bodyChange, method: 'POST', headers: this.platform.generateHeaders(), }); - const deviceStatus = await body.json(); + const deviceStatus: any = await body.json(); this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`); this.statusCode(statusCode); this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`); this.updateHomeKitCharacteristics(); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + this.errorLog( + `${this.device.remoteType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, ); } } else { - this.warnLog(`${this.device.remoteType}: ${this.accessory.displayName}` - + ` Connection Type: ${this.device.connectionType}, commands will not be sent to OpenAPI`); + this.warnLog( + `${this.device.remoteType}: ${this.accessory.displayName}` + + ` Connection Type: ${this.device.connectionType}, commands will not be sent to OpenAPI`, + ); } } @@ -161,7 +172,7 @@ export class Others { } } - async disablePushOnChanges({ device }: { device: irdevice & irDevicesConfig; }): Promise { + async disablePushOnChanges({ device }: { device: irdevice & irDevicesConfig }): Promise { if (device.disablePushOn === undefined) { this.disablePushOn = false; } else { @@ -169,7 +180,7 @@ export class Others { } } - async disablePushOffChanges({ device }: { device: irdevice & irDevicesConfig; }): Promise { + async disablePushOffChanges({ device }: { device: irdevice & irDevicesConfig }): Promise { if (device.disablePushOff === undefined) { this.disablePushOff = false; } else { @@ -222,8 +233,10 @@ export class Others { this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Device is offline, statusCode: ${statusCode}`); break; case 171: - this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` - + `Hub: ${this.device.hubDeviceId}`); + this.errorLog( + `${this.device.remoteType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` + + `Hub: ${this.device.hubDeviceId}`, + ); break; case 190: this.errorLog( @@ -238,8 +251,10 @@ export class Others { this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Request successful, statusCode: ${statusCode}`); break; default: - this.infoLog(`${this.device.remoteType}: ${this.accessory.displayName} Unknown statusCode: ` - + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`); + this.infoLog( + `${this.device.remoteType}: ${this.accessory.displayName} Unknown statusCode: ` + + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`, + ); } } @@ -261,8 +276,9 @@ export class Others { FirmwareRevision(accessory: PlatformAccessory, device: irdevice & irDevicesConfig): string { let FirmwareRevision: string; - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName}` - + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`); + this.debugLog( + `${this.device.remoteType}: ${this.accessory.displayName}` + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`, + ); this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} device.firmware: ${device.firmware}`); this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`); if (accessory.context.FirmwareRevision) { @@ -313,7 +329,7 @@ export class Others { config['disablePushOff'] = device.disablePushOff; } if (Object.entries(config).length !== 0) { - this.infoLog(`${this.device.remoteType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); + this.debugWarnLog(`${this.device.remoteType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); } } diff --git a/src/irdevice/tv.ts b/src/irdevice/tv.ts index e0b77c0f..36262376 100644 --- a/src/irdevice/tv.ts +++ b/src/irdevice/tv.ts @@ -1,7 +1,7 @@ +import { CharacteristicValue, PlatformAccessory, Service } from 'homebridge'; import { request } from 'undici'; import { SwitchBotPlatform } from '../platform'; -import { CharacteristicValue, PlatformAccessory, Service } from 'homebridge'; -import { irdevice, irDevicesConfig, Devices } from '../settings'; +import { Devices, irDevicesConfig, irdevice } from '../settings'; /** * Platform Accessory @@ -26,14 +26,18 @@ export class TV { disablePushDetail?: boolean; deviceLogging!: string; - constructor(private readonly platform: SwitchBotPlatform, private accessory: PlatformAccessory, public device: irdevice & irDevicesConfig) { + constructor( + private readonly platform: SwitchBotPlatform, + private accessory: PlatformAccessory, + public device: irdevice & irDevicesConfig, + ) { // default placeholders this.logs(device); - this.config(device); this.context(); this.disablePushOnChanges({ device }); this.disablePushOffChanges({ device }); this.disablePushDetailChanges({ device }); + this.config(device); // set accessory information accessory @@ -222,30 +226,32 @@ export class TV { * TV "command" "channelSub" "default" previous channel */ async pushTvOnChanges(): Promise { - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushTvOnChanges Active: ${this.Active},` - + ` disablePushOn: ${this.disablePushOn}`); + this.debugLog( + `${this.device.remoteType}: ${this.accessory.displayName} pushTvOnChanges Active: ${this.Active},` + ` disablePushOn: ${this.disablePushOn}`, + ); if (this.Active === this.platform.Characteristic.Active.ACTIVE && !this.disablePushOn) { const commandType: string = await this.commandType(); const command: string = await this.commandOn(); const bodyChange = JSON.stringify({ - 'command': command, - 'parameter': 'default', - 'commandType': commandType, + command: command, + parameter: 'default', + commandType: commandType, }); await this.pushTVChanges(bodyChange); } } async pushTvOffChanges(): Promise { - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushTvOffChanges Active: ${this.Active},` - + ` disablePushOff: ${this.disablePushOff}`); + this.debugLog( + `${this.device.remoteType}: ${this.accessory.displayName} pushTvOffChanges Active: ${this.Active},` + ` disablePushOff: ${this.disablePushOff}`, + ); if (this.Active === this.platform.Characteristic.Active.INACTIVE && !this.disablePushOff) { const commandType: string = await this.commandType(); const command: string = await this.commandOff(); const bodyChange = JSON.stringify({ - 'command': command, - 'parameter': 'default', - 'commandType': commandType, + command: command, + parameter: 'default', + commandType: commandType, }); await this.pushTVChanges(bodyChange); } @@ -255,9 +261,9 @@ export class TV { this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushOkChanges disablePushDetail: ${this.disablePushDetail}`); if (!this.disablePushDetail) { const bodyChange = JSON.stringify({ - 'command': 'Ok', - 'parameter': 'default', - 'commandType': 'command', + command: 'Ok', + parameter: 'default', + commandType: 'command', }); await this.pushTVChanges(bodyChange); } @@ -267,9 +273,9 @@ export class TV { this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushBackChanges disablePushDetail: ${this.disablePushDetail}`); if (!this.disablePushDetail) { const bodyChange = JSON.stringify({ - 'command': 'Back', - 'parameter': 'default', - 'commandType': 'command', + command: 'Back', + parameter: 'default', + commandType: 'command', }); await this.pushTVChanges(bodyChange); } @@ -279,9 +285,9 @@ export class TV { this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushMenuChanges disablePushDetail: ${this.disablePushDetail}`); if (!this.disablePushDetail) { const bodyChange = JSON.stringify({ - 'command': 'Menu', - 'parameter': 'default', - 'commandType': 'command', + command: 'Menu', + parameter: 'default', + commandType: 'command', }); await this.pushTVChanges(bodyChange); } @@ -291,9 +297,9 @@ export class TV { this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushUpChanges disablePushDetail: ${this.disablePushDetail}`); if (!this.disablePushDetail) { const bodyChange = JSON.stringify({ - 'command': 'Up', - 'parameter': 'default', - 'commandType': 'command', + command: 'Up', + parameter: 'default', + commandType: 'command', }); await this.pushTVChanges(bodyChange); } @@ -303,9 +309,9 @@ export class TV { this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushDownChanges disablePushDetail: ${this.disablePushDetail}`); if (!this.disablePushDetail) { const bodyChange = JSON.stringify({ - 'command': 'Down', - 'parameter': 'default', - 'commandType': 'command', + command: 'Down', + parameter: 'default', + commandType: 'command', }); await this.pushTVChanges(bodyChange); } @@ -315,9 +321,9 @@ export class TV { this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushRightChanges disablePushDetail: ${this.disablePushDetail}`); if (!this.disablePushDetail) { const bodyChange = JSON.stringify({ - 'command': 'Right', - 'parameter': 'default', - 'commandType': 'command', + command: 'Right', + parameter: 'default', + commandType: 'command', }); await this.pushTVChanges(bodyChange); } @@ -327,9 +333,9 @@ export class TV { this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushLeftChanges disablePushDetail: ${this.disablePushDetail}`); if (!this.disablePushDetail) { const bodyChange = JSON.stringify({ - 'command': 'Left', - 'parameter': 'default', - 'commandType': 'command', + command: 'Left', + parameter: 'default', + commandType: 'command', }); await this.pushTVChanges(bodyChange); } @@ -339,9 +345,9 @@ export class TV { this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushVolumeUpChanges disablePushDetail: ${this.disablePushDetail}`); if (!this.disablePushDetail) { const bodyChange = JSON.stringify({ - 'command': 'volumeAdd', - 'parameter': 'default', - 'commandType': 'command', + command: 'volumeAdd', + parameter: 'default', + commandType: 'command', }); await this.pushTVChanges(bodyChange); } @@ -351,9 +357,9 @@ export class TV { this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushVolumeDownChanges disablePushDetail: ${this.disablePushDetail}`); if (!this.disablePushDetail) { const bodyChange = JSON.stringify({ - 'command': 'volumeSub', - 'parameter': 'default', - 'commandType': 'command', + command: 'volumeSub', + parameter: 'default', + commandType: 'command', }); await this.pushTVChanges(bodyChange); } @@ -362,27 +368,30 @@ export class TV { async pushTVChanges(bodyChange: any): Promise { this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushTVChanges`); if (this.device.connectionType === 'OpenAPI') { - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${bodyChange},`); + this.infoLog(`${this.device.remoteType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${bodyChange},`); try { const { body, statusCode, headers } = await request(`${Devices}/${this.device.deviceId}/commands`, { body: bodyChange, method: 'POST', headers: this.platform.generateHeaders(), }); - const deviceStatus = await body.json(); + const deviceStatus: any = await body.json(); this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`); this.statusCode(statusCode); this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`); this.updateHomeKitCharacteristics(); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} failed pushTVChanges with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + this.errorLog( + `${this.device.remoteType}: ${this.accessory.displayName} failed pushTVChanges with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, ); } } else { - this.warnLog(`${this.device.remoteType}: ${this.accessory.displayName}` - + ` Connection Type: ${this.device.connectionType}, commands will not be sent to OpenAPI`); + this.warnLog( + `${this.device.remoteType}: ${this.accessory.displayName}` + + ` Connection Type: ${this.device.connectionType}, commands will not be sent to OpenAPI`, + ); } } @@ -403,7 +412,7 @@ export class TV { } } - async disablePushOnChanges({ device }: { device: irdevice & irDevicesConfig; }): Promise { + async disablePushOnChanges({ device }: { device: irdevice & irDevicesConfig }): Promise { if (device.disablePushOn === undefined) { this.disablePushOn = false; } else { @@ -411,7 +420,7 @@ export class TV { } } - async disablePushOffChanges({ device }: { device: irdevice & irDevicesConfig; }): Promise { + async disablePushOffChanges({ device }: { device: irdevice & irDevicesConfig }): Promise { if (device.disablePushOff === undefined) { this.disablePushOff = false; } else { @@ -419,7 +428,7 @@ export class TV { } } - async disablePushDetailChanges({ device }: { device: irdevice & irDevicesConfig; }): Promise { + async disablePushDetailChanges({ device }: { device: irdevice & irDevicesConfig }): Promise { if (device.disablePushDetail === undefined) { this.disablePushDetail = false; } else { @@ -472,8 +481,10 @@ export class TV { this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Device is offline, statusCode: ${statusCode}`); break; case 171: - this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` - + `Hub: ${this.device.hubDeviceId}`); + this.errorLog( + `${this.device.remoteType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` + + `Hub: ${this.device.hubDeviceId}`, + ); break; case 190: this.errorLog( @@ -488,8 +499,10 @@ export class TV { this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Request successful, statusCode: ${statusCode}`); break; default: - this.infoLog(`${this.device.remoteType}: ${this.accessory.displayName} Unknown statusCode: ` - + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`); + this.infoLog( + `${this.device.remoteType}: ${this.accessory.displayName} Unknown statusCode: ` + + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`, + ); } } @@ -500,8 +513,9 @@ export class TV { FirmwareRevision(accessory: PlatformAccessory, device: irdevice & irDevicesConfig): string { let FirmwareRevision: string; - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName}` - + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`); + this.debugLog( + `${this.device.remoteType}: ${this.accessory.displayName}` + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`, + ); this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} device.firmware: ${device.firmware}`); this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`); if (accessory.context.FirmwareRevision) { @@ -560,7 +574,7 @@ export class TV { config['disablePushDetail'] = device.disablePushDetail; } if (Object.entries(config).length !== 0) { - this.infoLog(`${this.device.remoteType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); + this.debugWarnLog(`${this.device.remoteType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); } } diff --git a/src/irdevice/vacuumcleaner.ts b/src/irdevice/vacuumcleaner.ts index dc2c6940..15380515 100644 --- a/src/irdevice/vacuumcleaner.ts +++ b/src/irdevice/vacuumcleaner.ts @@ -1,7 +1,7 @@ +import { CharacteristicValue, PlatformAccessory, Service } from 'homebridge'; import { request } from 'undici'; import { SwitchBotPlatform } from '../platform'; -import { irDevicesConfig, irdevice, Devices } from '../settings'; -import { CharacteristicValue, PlatformAccessory, Service } from 'homebridge'; +import { Devices, irDevicesConfig, irdevice } from '../settings'; /** * Platform Accessory @@ -20,13 +20,17 @@ export class VacuumCleaner { disablePushOff?: boolean; deviceLogging!: string; - constructor(private readonly platform: SwitchBotPlatform, private accessory: PlatformAccessory, public device: irdevice & irDevicesConfig) { + constructor( + private readonly platform: SwitchBotPlatform, + private accessory: PlatformAccessory, + public device: irdevice & irDevicesConfig, + ) { // default placeholders this.logs(device); - this.config(device); this.context(); this.disablePushOnChanges({ device }); this.disablePushOffChanges({ device }); + this.config(device); // set accessory information accessory @@ -76,30 +80,30 @@ export class VacuumCleaner { * Vacuum Cleaner "command" "turnOn" "default" set to ON state */ async pushOnChanges(): Promise { - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushOnChanges On: ${this.On},` - + ` disablePushOn: ${this.disablePushOn}`); + this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushOnChanges On: ${this.On},` + ` disablePushOn: ${this.disablePushOn}`); if (this.On && !this.disablePushOn) { const commandType: string = await this.commandType(); const command: string = await this.commandOn(); const bodyChange = JSON.stringify({ - 'command': command, - 'parameter': 'default', - 'commandType': commandType, + command: command, + parameter: 'default', + commandType: commandType, }); await this.pushChanges(bodyChange); } } async pushOffChanges(): Promise { - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushOffChanges On: ${this.On},` - + ` disablePushOff: ${this.disablePushOff}`); + this.debugLog( + `${this.device.remoteType}: ${this.accessory.displayName} pushOffChanges On: ${this.On},` + ` disablePushOff: ${this.disablePushOff}`, + ); if (!this.On && !this.disablePushOff) { const commandType: string = await this.commandType(); const command: string = await this.commandOff(); const bodyChange = JSON.stringify({ - 'command': command, - 'parameter': 'default', - 'commandType': commandType, + command: command, + parameter: 'default', + commandType: commandType, }); await this.pushChanges(bodyChange); } @@ -108,27 +112,30 @@ export class VacuumCleaner { async pushChanges(bodyChange: any): Promise { this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushChanges`); if (this.device.connectionType === 'OpenAPI') { - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${bodyChange},`); + this.infoLog(`${this.device.remoteType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${bodyChange},`); try { const { body, statusCode, headers } = await request(`${Devices}/${this.device.deviceId}/commands`, { body: bodyChange, method: 'POST', headers: this.platform.generateHeaders(), }); - const deviceStatus = await body.json(); + const deviceStatus: any = await body.json(); this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`); this.statusCode(statusCode); this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`); this.updateHomeKitCharacteristics(); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + this.errorLog( + `${this.device.remoteType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, ); } } else { - this.warnLog(`${this.device.remoteType}: ${this.accessory.displayName}` - + ` Connection Type: ${this.device.connectionType}, commands will not be sent to OpenAPI`); + this.warnLog( + `${this.device.remoteType}: ${this.accessory.displayName}` + + ` Connection Type: ${this.device.connectionType}, commands will not be sent to OpenAPI`, + ); } } @@ -142,7 +149,7 @@ export class VacuumCleaner { } } - async disablePushOnChanges({ device }: { device: irdevice & irDevicesConfig; }): Promise { + async disablePushOnChanges({ device }: { device: irdevice & irDevicesConfig }): Promise { if (device.disablePushOn === undefined) { this.disablePushOn = false; } else { @@ -150,7 +157,7 @@ export class VacuumCleaner { } } - async disablePushOffChanges({ device }: { device: irdevice & irDevicesConfig; }): Promise { + async disablePushOffChanges({ device }: { device: irdevice & irDevicesConfig }): Promise { if (device.disablePushOff === undefined) { this.disablePushOff = false; } else { @@ -203,8 +210,10 @@ export class VacuumCleaner { this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Device is offline, statusCode: ${statusCode}`); break; case 171: - this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` - + `Hub: ${this.device.hubDeviceId}`); + this.errorLog( + `${this.device.remoteType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` + + `Hub: ${this.device.hubDeviceId}`, + ); break; case 190: this.errorLog( @@ -219,8 +228,10 @@ export class VacuumCleaner { this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Request successful, statusCode: ${statusCode}`); break; default: - this.infoLog(`${this.device.remoteType}: ${this.accessory.displayName} Unknown statusCode: ` - + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`); + this.infoLog( + `${this.device.remoteType}: ${this.accessory.displayName} Unknown statusCode: ` + + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`, + ); } } @@ -230,8 +241,9 @@ export class VacuumCleaner { FirmwareRevision(accessory: PlatformAccessory, device: irdevice & irDevicesConfig): string { let FirmwareRevision: string; - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName}` - + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`); + this.debugLog( + `${this.device.remoteType}: ${this.accessory.displayName}` + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`, + ); this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} device.firmware: ${device.firmware}`); this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`); if (accessory.context.FirmwareRevision) { @@ -282,7 +294,7 @@ export class VacuumCleaner { config['disablePushOff'] = device.disablePushOff; } if (Object.entries(config).length !== 0) { - this.infoLog(`${this.device.remoteType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); + this.debugWarnLog(`${this.device.remoteType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); } } diff --git a/src/irdevice/waterheater.ts b/src/irdevice/waterheater.ts index 99d8bee1..2698b0f8 100644 --- a/src/irdevice/waterheater.ts +++ b/src/irdevice/waterheater.ts @@ -1,7 +1,7 @@ +import { CharacteristicValue, PlatformAccessory, Service } from 'homebridge'; import { request } from 'undici'; import { SwitchBotPlatform } from '../platform'; -import { irDevicesConfig, irdevice, Devices } from '../settings'; -import { CharacteristicValue, PlatformAccessory, Service } from 'homebridge'; +import { Devices, irDevicesConfig, irdevice } from '../settings'; /** * Platform Accessory @@ -20,13 +20,17 @@ export class WaterHeater { disablePushOff?: boolean; deviceLogging!: string; - constructor(private readonly platform: SwitchBotPlatform, private accessory: PlatformAccessory, public device: irdevice & irDevicesConfig) { + constructor( + private readonly platform: SwitchBotPlatform, + private accessory: PlatformAccessory, + public device: irdevice & irDevicesConfig, + ) { // default placeholders this.logs({ device }); - this.config({ device }); this.context(); this.disablePushOnChanges({ device }); this.disablePushOffChanges({ device }); + this.config({ device }); // set accessory information accessory @@ -81,30 +85,34 @@ export class WaterHeater { * WaterHeater "command" "turnOn" "default" set to ON state */ async pushWaterHeaterOnChanges(): Promise { - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushWaterHeaterOnChanges Active: ${this.Active},` - + ` disablePushOn: ${this.disablePushOn}`); + this.debugLog( + `${this.device.remoteType}: ${this.accessory.displayName} pushWaterHeaterOnChanges Active: ${this.Active},` + + ` disablePushOn: ${this.disablePushOn}`, + ); if (this.Active === this.platform.Characteristic.Active.ACTIVE && !this.disablePushOn) { const commandType: string = await this.commandType(); const command: string = await this.commandOn(); const bodyChange = JSON.stringify({ - 'command': command, - 'parameter': 'default', - 'commandType': commandType, + command: command, + parameter: 'default', + commandType: commandType, }); await this.pushChanges(bodyChange); } } async pushWaterHeaterOffChanges(): Promise { - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushWaterHeaterOffChanges Active: ${this.Active},` - + ` disablePushOff: ${this.disablePushOff}`); + this.debugLog( + `${this.device.remoteType}: ${this.accessory.displayName} pushWaterHeaterOffChanges Active: ${this.Active},` + + ` disablePushOff: ${this.disablePushOff}`, + ); if (this.Active === this.platform.Characteristic.Active.INACTIVE && !this.disablePushOff) { const commandType: string = await this.commandType(); const command: string = await this.commandOff(); const bodyChange = JSON.stringify({ - 'command': command, - 'parameter': 'default', - 'commandType': commandType, + command: command, + parameter: 'default', + commandType: commandType, }); await this.pushChanges(bodyChange); } @@ -113,27 +121,30 @@ export class WaterHeater { async pushChanges(bodyChange: any): Promise { this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushChanges`); if (this.device.connectionType === 'OpenAPI') { - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${bodyChange},`); + this.infoLog(`${this.device.remoteType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${bodyChange},`); try { const { body, statusCode, headers } = await request(`${Devices}/${this.device.deviceId}/commands`, { body: bodyChange, method: 'POST', headers: this.platform.generateHeaders(), }); - const deviceStatus = await body.json(); + const deviceStatus: any = await body.json(); this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`); this.statusCode(statusCode); this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`); this.updateHomeKitCharacteristics(); } catch (e: any) { this.apiError(e); - this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType}` - + ` Connection, Error Message: ${JSON.stringify(e.message)}`, + this.errorLog( + `${this.device.remoteType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType}` + + ` Connection, Error Message: ${JSON.stringify(e.message)}`, ); } } else { - this.warnLog(`${this.device.remoteType}: ${this.accessory.displayName}` - + ` Connection Type: ${this.device.connectionType}, commands will not be sent to OpenAPI`); + this.warnLog( + `${this.device.remoteType}: ${this.accessory.displayName}` + + ` Connection Type: ${this.device.connectionType}, commands will not be sent to OpenAPI`, + ); } } @@ -147,7 +158,7 @@ export class WaterHeater { } } - async disablePushOnChanges({ device }: { device: irdevice & irDevicesConfig; }): Promise { + async disablePushOnChanges({ device }: { device: irdevice & irDevicesConfig }): Promise { if (device.disablePushOn === undefined) { this.disablePushOn = false; } else { @@ -155,7 +166,7 @@ export class WaterHeater { } } - async disablePushOffChanges({ device }: { device: irdevice & irDevicesConfig; }): Promise { + async disablePushOffChanges({ device }: { device: irdevice & irDevicesConfig }): Promise { if (device.disablePushOff === undefined) { this.disablePushOff = false; } else { @@ -208,8 +219,10 @@ export class WaterHeater { this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Device is offline, statusCode: ${statusCode}`); break; case 171: - this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` - + `Hub: ${this.device.hubDeviceId}`); + this.errorLog( + `${this.device.remoteType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` + + `Hub: ${this.device.hubDeviceId}`, + ); break; case 190: this.errorLog( @@ -224,19 +237,22 @@ export class WaterHeater { this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Request successful, statusCode: ${statusCode}`); break; default: - this.infoLog(`${this.device.remoteType}: ${this.accessory.displayName} Unknown statusCode: ` - + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`); + this.infoLog( + `${this.device.remoteType}: ${this.accessory.displayName} Unknown statusCode: ` + + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`, + ); } } - async apiError({ e }: { e: any; }): Promise { + async apiError({ e }: { e: any }): Promise { this.valveService.updateCharacteristic(this.platform.Characteristic.Active, e); } - FirmwareRevision({ accessory, device }: { accessory: PlatformAccessory; device: irdevice & irDevicesConfig; }): string { + FirmwareRevision({ accessory, device }: { accessory: PlatformAccessory; device: irdevice & irDevicesConfig }): string { let FirmwareRevision: string; - this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName}` - + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`); + this.debugLog( + `${this.device.remoteType}: ${this.accessory.displayName}` + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`, + ); this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} device.firmware: ${device.firmware}`); this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`); if (accessory.context.FirmwareRevision) { @@ -257,7 +273,7 @@ export class WaterHeater { } } - async config({ device }: { device: irdevice & irDevicesConfig; }): Promise { + async config({ device }: { device: irdevice & irDevicesConfig }): Promise { let config = {}; if (device.irwh) { config = device.irwh; @@ -287,11 +303,11 @@ export class WaterHeater { config['disablePushOff'] = device.disablePushOff; } if (Object.entries(config).length !== 0) { - this.infoLog({ log: [`${this.device.remoteType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`] }); + this.debugWarnLog({ log: [`${this.device.remoteType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`] }); } } - async logs({ device }: { device: irdevice & irDevicesConfig; }): Promise { + async logs({ device }: { device: irdevice & irDevicesConfig }): Promise { if (this.platform.debugMode) { this.deviceLogging = this.accessory.context.logging = 'debugMode'; this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Using Debug Mode Logging: ${this.deviceLogging}`); diff --git a/src/platform.ts b/src/platform.ts index b1ba13f5..bbbdacf3 100644 --- a/src/platform.ts +++ b/src/platform.ts @@ -32,8 +32,7 @@ import { EveHomeKitTypes } from 'homebridge-lib'; import { readFileSync, writeFileSync } from 'fs'; import { API, DynamicPlatformPlugin, Logger, PlatformAccessory, Service, Characteristic } from 'homebridge'; -import { - PLATFORM_NAME, PLUGIN_NAME, irdevice, device, SwitchBotPlatformConfig, devicesConfig, irDevicesConfig, Devices } from './settings'; +import { PLATFORM_NAME, PLUGIN_NAME, irdevice, device, SwitchBotPlatformConfig, devicesConfig, irDevicesConfig, Devices } from './settings'; /** * HomebridgePlatform @@ -54,7 +53,11 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin { public readonly fakegatoAPI: any; public readonly eve: any; - constructor(public readonly log: Logger, public readonly config: SwitchBotPlatformConfig, public readonly api: API) { + constructor( + public readonly log: Logger, + public readonly config: SwitchBotPlatformConfig, + public readonly api: API, + ) { this.logs(); this.debugLog('Finished initializing platform:', this.config.name); // only load if configured @@ -64,8 +67,10 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin { // HOOBS notice if (__dirname.includes('hoobs')) { - this.warnLog('This plugin has not been tested under HOOBS, it is highly recommended that you switch to Homebridge: ' - + 'https://tinyurl.com/HOOBS2Homebridge'); + this.warnLog( + 'This plugin has not been tested under HOOBS, it is highly recommended that you switch to Homebridge: ' + + 'https://tinyurl.com/HOOBS2Homebridge', + ); } // verify the config @@ -94,7 +99,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin { await this.updateToken(); } else if (this.config.credentials?.token && !this.config.credentials?.secret) { // eslint-disable-next-line no-useless-escape - this.errorLog('\"secret\" config is not populated, you must populate then please restart Homebridge.'); + this.errorLog('"secret" config is not populated, you must populate then please restart Homebridge.'); } else { this.discoverDevices(); } @@ -133,7 +138,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin { platformConfig['pushRate'] = this.config.options.pushRate; } if (Object.entries(platformConfig).length !== 0) { - this.infoLog(`Platform Config: ${JSON.stringify(platformConfig)}`); + this.debugWarnLog(`Platform Config: ${JSON.stringify(platformConfig)}`); } if (this.config.options) { @@ -177,9 +182,9 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin { } if (!this.config.options.pushRate) { - // default 100 milliseconds - this.config.options!.pushRate! = 0.1; - this.debugWarnLog('Using Default Push Rate.'); + // default 100 milliseconds + this.config.options!.pushRate! = 0.1; + this.debugWarnLog('Using Default Push Rate.'); } if (!this.config.credentials && !this.config.options) { @@ -230,14 +235,19 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin { throw new Error('pluginConfig.credentials is not an object'); } // Move openToken to token - if (!this.config.credentials.secret){ + if (!this.config.credentials.secret) { // eslint-disable-next-line no-useless-escape, max-len - this.warnLog('This plugin has been updated to use OpenAPI v1.1, config is set with openToken, \"openToken\" cconfig has been moved to the \"token\" config' ); + this.warnLog( + 'This plugin has been updated to use OpenAPI v1.1, config is set with openToken, "openToken" cconfig has been moved to the "token" config', + ); // eslint-disable-next-line no-useless-escape - this.errorLog('\"secret\" config is not populated, you must populate then please restart Homebridge.'); + this.errorLog('"secret" config is not populated, you must populate then please restart Homebridge.'); } else { // eslint-disable-next-line no-useless-escape, max-len - this.warnLog('This plugin has been updated to use OpenAPI v1.1, config is set with openToken, \"openToken\" config has been moved to the \"token\" config, please restart Homebridge.'); + this.warnLog( + 'This plugin has been updated to use OpenAPI v1.1, config is set with openToken, ' + + '"openToken" config has been moved to the "token" config, please restart Homebridge.', + ); } // set the refresh token @@ -260,14 +270,17 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin { const t = `${Date.now()}`; const nonce = randomUUID(); const data = this.config.credentials?.token + t + nonce; - const signTerm = crypto.createHmac('sha256', this.config.credentials?.secret).update(Buffer.from(data, 'utf-8')).digest(); + const signTerm = crypto + .createHmac('sha256', this.config.credentials?.secret) + .update(Buffer.from(data, 'utf-8')) + .digest(); const sign = signTerm.toString('base64'); return { - 'Authorization': this.config.credentials?.token, - 'sign': sign, - 'nonce': nonce, - 't': t, + Authorization: this.config.credentials?.token, + sign: sign, + nonce: nonce, + t: t, 'Content-Type': 'application/json', }; }; @@ -287,18 +300,42 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin { const { body, statusCode, headers } = await request(Devices, { headers: this.generateHeaders(), }); - const devicesAPI = await body.json(); - this.debugLog(`Devices: ${JSON.stringify(devicesAPI.body)}`); - this.statusCode(statusCode); - this.debugLog(`Headers: ${JSON.stringify(headers)}`); - // SwitchBot Devices - const deviceLists = devicesAPI.body.deviceList; - if (!this.config.options?.devices) { - this.debugLog(`SwitchBot Device Config Not Set: ${JSON.stringify(this.config.options?.devices)}`); - if (devicesAPI.body.length === 0) { - this.debugLog(`SwitchBot API Currently Doesn't Have Any Devices With Cloud Services Enabled: ${JSON.stringify(devicesAPI.body)}`); - } else { - const devices = deviceLists.map((v: any) => v); + if (statusCode === 200) { + const devicesAPI: any = await body.json(); + this.debugLog(`Devices: ${JSON.stringify(devicesAPI.body)}`); + this.debugLog(`Headers: ${JSON.stringify(headers)}`); + // SwitchBot Devices + const deviceLists = devicesAPI.body.deviceList; + if (!this.config.options?.devices) { + this.debugLog(`SwitchBot Device Config Not Set: ${JSON.stringify(this.config.options?.devices)}`); + if (deviceLists.length === 0) { + this.debugLog(`SwitchBot API Currently Doesn't Have Any Devices With Cloud Services Enabled: ${JSON.stringify(devicesAPI.body)}`); + } else { + const devices = deviceLists.map((v: any) => v); + for (const device of devices) { + if (device.deviceType) { + if (device.configDeviceName) { + device.deviceName = device.configDeviceName; + } + this.createDevice(device); + } + } + } + } else if (this.config.credentials?.token && this.config.options.devices) { + this.debugLog(`SwitchBot Device Config Set: ${JSON.stringify(this.config.options?.devices)}`); + const deviceConfigs = this.config.options?.devices; + + const mergeBydeviceId = (a1: { deviceId: string }[], a2: any[]) => + a1.map((itm: { deviceId: string }) => ({ + ...a2.find( + (item: { deviceId: string }) => + item.deviceId.toUpperCase().replace(/[^A-Z0-9]+/g, '') === itm.deviceId.toUpperCase().replace(/[^A-Z0-9]+/g, '') && item, + ), + ...itm, + })); + + const devices = mergeBydeviceId(deviceLists, deviceConfigs); + this.debugLog(`SwitchBot Devices: ${JSON.stringify(devices)}`); for (const device of devices) { if (device.deviceType) { if (device.configDeviceName) { @@ -307,77 +344,56 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin { this.createDevice(device); } } + } else { + this.errorLog('SwitchBot Token Supplied, Issue with Auth.'); } - } else if (this.config.credentials?.token && this.config.options.devices) { - this.debugLog(`SwitchBot Device Config Set: ${JSON.stringify(this.config.options?.devices)}`); - const deviceConfigs = this.config.options?.devices; - - const mergeBydeviceId = (a1: { deviceId: string }[], a2: any[]) => - a1.map((itm: { deviceId: string }) => ({ - ...a2.find( - (item: { deviceId: string }) => - item.deviceId.toUpperCase().replace(/[^A-Z0-9]+/g, '') === itm.deviceId.toUpperCase().replace(/[^A-Z0-9]+/g, '') && item, - ), - ...itm, - })); - - const devices = mergeBydeviceId(deviceLists, deviceConfigs); - this.debugLog(`SwitchBot Devices: ${JSON.stringify(devices)}`); - for (const device of devices) { - if (device.deviceType) { - if (device.configDeviceName) { - device.deviceName = device.configDeviceName; - } - this.createDevice(device); - } + if (devicesAPI.body.deviceList.length !== 0) { + this.infoLog(`Total SwitchBot Devices Found: ${devicesAPI.body.deviceList.length}`); + } else { + this.debugLog(`Total SwitchBot Devices Found: ${devicesAPI.body.deviceList.length}`); } - } else { - this.errorLog('SwitchBot Token Supplied, Issue with Auth.'); - } - if (devicesAPI.body.deviceList.length !== 0) { - this.infoLog(`Total SwitchBot Devices Found: ${devicesAPI.body.deviceList.length}`); - } else { - this.debugLog(`Total SwitchBot Devices Found: ${devicesAPI.body.deviceList.length}`); - } - // IR Devices - const irDeviceLists = devicesAPI.body.infraredRemoteList; - if (!this.config.options?.irdevices) { - this.debugLog(`IR Device Config Not Set: ${JSON.stringify(this.config.options?.irdevices)}`); - const devices = irDeviceLists.map((v: any) => v); - for (const device of devices) { - if (device.remoteType) { + // IR Devices + const irDeviceLists = devicesAPI.body.infraredRemoteList; + if (!this.config.options?.irdevices) { + this.debugLog(`IR Device Config Not Set: ${JSON.stringify(this.config.options?.irdevices)}`); + const devices = irDeviceLists.map((v: any) => v); + for (const device of devices) { + if (device.remoteType) { + this.createIRDevice(device); + } + } + } else { + this.debugLog(`IR Device Config Set: ${JSON.stringify(this.config.options?.irdevices)}`); + const irDeviceConfig = this.config.options?.irdevices; + + const mergeIRBydeviceId = (a1: { deviceId: string }[], a2: any[]) => + a1.map((itm: { deviceId: string }) => ({ + ...a2.find( + (item: { deviceId: string }) => + item.deviceId.toUpperCase().replace(/[^A-Z0-9]+/g, '') === itm.deviceId.toUpperCase().replace(/[^A-Z0-9]+/g, '') && item, + ), + ...itm, + })); + + const devices = mergeIRBydeviceId(irDeviceLists, irDeviceConfig); + this.debugLog(`IR Devices: ${JSON.stringify(devices)}`); + for (const device of devices) { this.createIRDevice(device); } } - } else { - this.debugLog(`IR Device Config Set: ${JSON.stringify(this.config.options?.irdevices)}`); - const irDeviceConfig = this.config.options?.irdevices; - - const mergeIRBydeviceId = (a1: { deviceId: string }[], a2: any[]) => - a1.map((itm: { deviceId: string }) => ({ - ...a2.find( - (item: { deviceId: string }) => - item.deviceId.toUpperCase().replace(/[^A-Z0-9]+/g, '') === itm.deviceId.toUpperCase().replace(/[^A-Z0-9]+/g, '') && item, - ), - ...itm, - })); - - const devices = mergeIRBydeviceId(irDeviceLists, irDeviceConfig); - this.debugLog(`IR Devices: ${JSON.stringify(devices)}`); - for (const device of devices) { - this.createIRDevice(device); + if (devicesAPI.body.infraredRemoteList.length !== 0) { + this.infoLog(`Total IR Devices Found: ${devicesAPI.body.infraredRemoteList.length}`); + } else { + this.debugLog(`Total IR Devices Found: ${devicesAPI.body.infraredRemoteList.length}`); } - } - if (devicesAPI.body.infraredRemoteList.length !== 0) { - this.infoLog(`Total IR Devices Found: ${devicesAPI.body.infraredRemoteList.length}`); } else { - this.debugLog(`Total IR Devices Found: ${devicesAPI.body.infraredRemoteList.length}`); + this.statusCode(statusCode); } - } catch (e: any) { - this.debugErrorLog(`Failed to Discover Devices, Error Message: ${JSON.stringify(e.message)}, Submit Bugs Here: ` - + 'https://tinyurl.com/SwitchBotBug'); + this.debugErrorLog( + `Failed to Discover Devices, Error Message: ${JSON.stringify(e.message)}, Submit Bugs Here: ` + 'https://tinyurl.com/SwitchBotBug', + ); this.debugErrorLog(`Failed to Discover Devices, Error: ${e}`); } } else if (!this.config.credentials?.token && this.config.options?.devices) { @@ -624,7 +640,6 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin { if (existingAccessory) { // the accessory already exists if (await this.registerDevice(device)) { - // if you need to update the accessory.context then you should run `api.updatePlatformAccessories`. eg.: existingAccessory.context.model = device.deviceType; existingAccessory.context.deviceID = device.deviceId; @@ -1043,8 +1058,10 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin { } if (device.group && !device.curtain?.disable_group) { - this.debugLog('Your Curtains are grouped, ' - + `, Secondary curtain automatically hidden. Main Curtain: ${device.deviceName}, DeviceID: ${device.deviceId}`); + this.debugLog( + 'Your Curtains are grouped, ' + + `, Secondary curtain automatically hidden. Main Curtain: ${device.deviceName}, DeviceID: ${device.deviceId}`, + ); } else { if (device.master) { this.warnLog(`Main Curtain: ${device.deviceName}, DeviceID: ${device.deviceId}`); @@ -1110,8 +1127,10 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin { } if (device.group && !device.curtain?.disable_group) { - this.debugLog('Your Curtains are grouped, ' - + `, Secondary curtain automatically hidden. Main Curtain: ${device.deviceName}, DeviceID: ${device.deviceId}`); + this.debugLog( + 'Your Curtains are grouped, ' + + `, Secondary curtain automatically hidden. Main Curtain: ${device.deviceName}, DeviceID: ${device.deviceId}`, + ); } else { if (device.master) { this.warnLog(`Main Curtain: ${device.deviceName}, DeviceID: ${device.deviceId}`); @@ -1649,9 +1668,6 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin { // the cached devices we stored in the `configureAccessory` method above const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid); - if (device.irair?.meterType && device.irair?.meterId) { - device.irair.meterUuid = this.api.hap.uuid.generate(`${device.irair.meterId}-${device.irair.meterType}`); - } if (existingAccessory) { // the accessory already exists if (!device.hide_device && device.hubDeviceId) { @@ -1983,42 +1999,56 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin { async registerCurtains(device: device & devicesConfig) { if (device.deviceType === 'Curtain') { - this.debugWarnLog(`deviceName: ${device.deviceName} deviceId: ${device.deviceId}, curtainDevicesIds: ${device.curtainDevicesIds}, master: ` - + `${device.master}, group: ${device.group}, disable_group: ${device.curtain?.disable_group}, connectionType: ${device.connectionType}`); + this.debugWarnLog( + `deviceName: ${device.deviceName} deviceId: ${device.deviceId}, curtainDevicesIds: ${device.curtainDevicesIds}, master: ` + + `${device.master}, group: ${device.group}, disable_group: ${device.curtain?.disable_group}, connectionType: ${device.connectionType}`, + ); } else { - this.debugWarnLog(`deviceName: ${device.deviceName} deviceId: ${device.deviceId}, blindTiltDevicesIds: ${device.blindTiltDevicesIds}, master: ` - + `${device.master}, group: ${device.group}, disable_group: ${device.curtain?.disable_group}, connectionType: ${device.connectionType}`); + this.debugWarnLog( + `deviceName: ${device.deviceName} deviceId: ${device.deviceId}, blindTiltDevicesIds: ${device.blindTiltDevicesIds}, master: ` + + `${device.master}, group: ${device.group}, disable_group: ${device.curtain?.disable_group}, connectionType: ${device.connectionType}`, + ); } let registerCurtain: boolean; if (device.master && device.group) { // OpenAPI: Master Curtains/Blind Tilt in Group registerCurtain = true; - this.debugLog(`deviceName: ${device.deviceName} [${device.deviceType} Config] device.master: ${device.master}, device.group: ${device.group}` - + ` connectionType; ${device.connectionType}`); + this.debugLog( + `deviceName: ${device.deviceName} [${device.deviceType} Config] device.master: ${device.master}, device.group: ${device.group}` + + ` connectionType; ${device.connectionType}`, + ); this.debugWarnLog(`Device: ${device.deviceName} registerCurtains: ${registerCurtain}`); - } else if (!device.master && device.curtain?.disable_group) { //!device.group && device.connectionType === 'BLE' + } else if (!device.master && device.curtain?.disable_group) { + //!device.group && device.connectionType === 'BLE' // OpenAPI: Non-Master Curtains/Blind Tilts that has Disable Grouping Checked registerCurtain = true; - this.debugLog(`deviceName: ${device.deviceName} [${device.deviceType} Config] device.master: ${device.master}, disable_group: ` - + `${device.curtain?.disable_group}, connectionType; ${device.connectionType}`); + this.debugLog( + `deviceName: ${device.deviceName} [${device.deviceType} Config] device.master: ${device.master}, disable_group: ` + + `${device.curtain?.disable_group}, connectionType; ${device.connectionType}`, + ); this.debugWarnLog(`Device: ${device.deviceName} registerCurtains: ${registerCurtain}`); } else if (device.master && !device.group) { // OpenAPI: Master Curtains/Blind Tilts not in Group registerCurtain = true; - this.debugLog(`deviceName: ${device.deviceName} [${device.deviceType} Config] device.master: ${device.master}, device.group: ${device.group}` - + ` connectionType; ${device.connectionType}`); + this.debugLog( + `deviceName: ${device.deviceName} [${device.deviceType} Config] device.master: ${device.master}, device.group: ${device.group}` + + ` connectionType; ${device.connectionType}`, + ); this.debugWarnLog(`Device: ${device.deviceName} registerCurtains: ${registerCurtain}`); } else if (device.connectionType === 'BLE') { // BLE: Curtains/Blind Tilt registerCurtain = true; - this.debugLog(`deviceName: ${device.deviceName} [${device.deviceType} Config] connectionType: ${device.connectionType}, ` - + ` group: ${device.group}`); + this.debugLog( + `deviceName: ${device.deviceName} [${device.deviceType} Config] connectionType: ${device.connectionType}, ` + ` group: ${device.group}`, + ); this.debugWarnLog(`Device: ${device.deviceName} registerCurtains: ${registerCurtain}`); } else { registerCurtain = false; - this.debugErrorLog(`deviceName: ${device.deviceName} [${device.deviceType} Config] disable_group: ${device.curtain?.disable_group},` - + ` device.master: ${device.master}, device.group: ${device.group}`); + this.debugErrorLog( + `deviceName: ${device.deviceName} [${device.deviceType} Config] disable_group: ${device.curtain?.disable_group},` + + ` device.master: ${device.master}, device.group: ${device.group}`, + ); this.debugWarnLog(`Device: ${device.deviceName} registerCurtains: ${registerCurtain}, device.connectionType: ${device.connectionType}`); } return registerCurtain; @@ -2046,8 +2076,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin { this.debugWarnLog(`Device: ${device.deviceName} registerDevice: ${registerDevice}`); } this.debugWarnLog(`Device: ${device.deviceName} connectionType: ${device.connectionType}, will display in HomeKit`); - } else if (!device.hide_device && device.deviceId && device.configDeviceType && device.configDeviceName - && device.connectionType === 'BLE') { + } else if (!device.hide_device && device.deviceId && device.configDeviceType && device.configDeviceName && device.connectionType === 'BLE') { if (device.deviceType === 'Curtain' || device.deviceType === 'Blind Tilt') { registerDevice = await this.registerCurtains(device); this.debugWarnLog(`Device: ${device.deviceName} ${device.deviceType} registerDevice: ${registerDevice}`); @@ -2077,23 +2106,25 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin { } else if (!device.connectionType && !device.hide_device) { registerDevice = false; this.debugErrorLog(`Device: ${device.deviceName} connectionType: ${device.connectionType}, will not display in HomeKit`); - } else if (device.hide_device){ + } else if (device.hide_device) { registerDevice = false; this.debugErrorLog(`Device: ${device.deviceName} hide_device: ${device.hide_device}, will not display in HomeKit`); } else { registerDevice = false; - this.debugErrorLog(`Device: ${device.deviceName} connectionType: ${device.connectionType}, hide_device: ` - + `${device.hide_device}, will not display in HomeKit`); + this.debugErrorLog( + `Device: ${device.deviceName} connectionType: ${device.connectionType}, hide_device: ` + + `${device.hide_device}, will not display in HomeKit`, + ); } return registerDevice; } public async externalOrPlatformIR(device: device & irDevicesConfig, accessory: PlatformAccessory) { /** - * Publish as external accessory - * Only one TV can exist per bridge, to bypass this limitation, you should - * publish your TV as an external accessory. - */ + * Publish as external accessory + * Only one TV can exist per bridge, to bypass this limitation, you should + * publish your TV as an external accessory. + */ if (device.external) { this.debugWarnLog(`${accessory.displayName} External Accessory Mode`); this.externalAccessory(accessory); @@ -2126,8 +2157,10 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin { async statusCode(statusCode: number): Promise { switch (statusCode) { case 151: - this.errorLog(`Command not supported by this device type, statusCode: ${statusCode}, Submit Feature Request Here: ` - + 'https://tinyurl.com/SwitchBotFeatureRequest'); + this.errorLog( + `Command not supported by this device type, statusCode: ${statusCode}, Submit Feature Request Here: ` + + 'https://tinyurl.com/SwitchBotFeatureRequest', + ); break; case 152: this.errorLog(`Device not found, statusCode: ${statusCode}`); @@ -2161,9 +2194,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin { let switchbot: any; try { Switchbot = require('node-switchbot'); - queueScheduler.schedule(() => - switchbot = new Switchbot(), - ); + queueScheduler.schedule(() => (switchbot = new Switchbot())); } catch (e: any) { switchbot = false; this.errorLog(`Was 'node-switchbot' found: ${switchbot}`); diff --git a/src/settings.ts b/src/settings.ts index 468ad93e..f21596b9 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -151,6 +151,7 @@ export type lock = { export type hub = { hide_temperature?: boolean; hide_humidity?: boolean; + hide_lightsensor?: boolean; }; export interface irDevicesConfig extends irdevice { @@ -201,7 +202,7 @@ export type body = { command: string; parameter: string; commandType: string; -} +}; //a list of physical devices. export type deviceList = { @@ -254,45 +255,45 @@ export type irdevice = { }; export type deviceStatus = { -//v1.1 of API -deviceId: string; //device ID. (Used by the following deviceTypes: Bot, Curtain, Meter, Meter Plus, Lock, Keypad, Keypad Touch, Motion Sensor, Contact Sensor, Ceiling Light, Ceiling Light Pro, Plug Mini (US), Plug Mini (JP), Strip Light, Color Bulb, Robot Vacuum Cleaner S1, Robot Vacuum Cleaner S1 Plus, Humidifier, Blind Tilt) -deviceType: string; //device type. (Used by the following deviceTypes: Bot, Curtain, Meter, Meter Plus, Lock, Keypad, Keypad Touch, Motion Sensor, Contact Sensor, Ceiling Light, Ceiling Light Pro, Plug Mini (US), Plug Mini (JP), Strip Light, Color Bulb, Robot Vacuum Cleaner S1, Robot Vacuum Cleaner S1 Plus, Humidifier, Blind Tilt) -hubDeviceId: string; //device's parent Hub ID. 000000000000 when the device itself is a Hub or it is connected through Wi-Fi. (Used by the following deviceTypes: Bot, Curtain, Meter, Meter Plus, Lock, Keypad, Keypad Touch, Motion Sensor, Contact Sensor, Ceiling Light, Ceiling Light Pro, Plug Mini (JP), Strip Light, Color Bulb, Robot Vacuum Cleaner S1, Robot Vacuum Cleaner S1 Plus, Humidifier, Blind Tilt) -power?: string; //ON/OFF state. (Used by the following deviceTypes: Bot, Ceiling Light, Ceiling Light Pro, PLug, Plug Mini (US), Plug Mini (JP), Strip Light, Color Bulb, Humidifier) -calibrate?: boolean; //determines if device has been calibrated or not. (Used by the following deviceTypes: Curtain, Lock, Blind Tilt) -group?: boolean; //determines if a device is paired with or grouped with another device or not. (Used by the following deviceTypes: Curtain, Blind Tilt) -moving?: boolean; //determines if a device is moving or not. (Used by the following deviceTypes: Curtain, Blind Tilt) -slidePosition?: number;//the current position (0-100) the percentage of the distance between the calibrated open position and closed position. (Used by the following deviceTypes: Curtain, Blind Tilt) -temperature?: number; //temperature in celsius (Used by the following deviceTypes: Meter, Meter Plus, Humidifier, IOSensor) -humidity?: number; //humidity percentage. (Used by the following deviceTypes: Meter, Meter Plus, Humidifier, IOSensor) -lockState?: string; //determines if locked or not. (Used by the following deviceTypes: Lock) -doorState?: string; //determines if the door is closed or not. (Used by the following deviceTypes: Lock) -moveDetected?: boolean; //determines if motion is detected. (Used by the following deviceTypes: Motion Sensor, Contact Sensor) -brightness?: string | number; //the ambient brightness picked up by the sensor. bright or dim. (Used by the following deviceTypes: Motion Sensor, Contact Sensor) | the brightness value, range from 1 to 100. (Used by the following deviceTypes: Ceiling Light, Ceiling Light Pro, Strip Light, Color Bulb) -openState?: string; //the open state of the sensor. open, close, or timeOutNotClose. (Used by the following deviceTypes: Contact Sensor) -colorTemperature?: number; //the color temperature value, range from 2700 to 6500. (Used by the following deviceTypes: Ceiling Light, Ceiling Light Pro, Color Bulb) -voltage?: number; //the voltage of the device, measured in Volt. (Used by the following deviceTypes: Plug Mini (US), Plug Mini (JP)) -weight?: number; //the power consumed in a day, measured in Watts. (Used by the following deviceTypes: Plug Mini (US), Plug Mini (JP)) -electricityOfDay?: number; //the duration that the device has been used during a day, measured in minutes. (Used by the following deviceTypes: Plug Mini (US), Plug Mini (JP)) -electricCurrent?: number; //the current of the device at the moment, measured in Amp. (Used by the following deviceTypes: Plug Mini (US), Plug Mini (JP)) -color?: string; //the color value, RGB "255:255:255". (Used by the following deviceTypes: Strip Light, Color Bulb) -workingStatus?: string; //the working status of the device. StandBy, Clearing, Paused, GotoChargeBase, Charging, ChargeDone, Dormant, InTrouble, InRemoteControl, or InDustCollecting. (Used by the following deviceTypes: Robot Vacuum Cleaner S1, Robot Vacuum Cleaner S1 Plus) -onlineStatus?: string; //the connection status of the device. online or offline. (Used by the following deviceTypes: Robot Vacuum Cleaner S1, Robot Vacuum Cleaner S1 Plus) -battery?: number; //the current battery level. (Used by the following deviceTypes: Robot Vacuum Cleaner S1, Robot Vacuum Cleaner S1 Plus, Blind Tilt, IOSensor) -deviceName?: string; //device name. (Used by the following deviceTypes: Robot Vacuum Cleaner S1 Plus) -nebulizationEfficiency?: number; //atomization efficiency percentage. (Used by the following deviceTypes: Humidifier) -auto?: boolean; //determines if a Humidifier is in Auto Mode or not. (Used by the following deviceTypes: Humidifier) -childLock?: boolean; //determines if a Humidifier's safety lock is on or not. (Used by the following deviceTypes: Humidifier) -sound?: boolean;//determines if a Humidifier is muted or not. (Used by the following deviceTypes: Humidifier) -lackWater?: boolean;//determines if the water tank is empty or not. (Used by the following deviceTypes: Humidifier) -version?: number;//the version of the device. (Used by the following deviceTypes: Blind Tilt) -direction?: string;//the opening direction of a Blind Tilt device. (Used by the following deviceTypes: Blind Tilt) -runStatus?: string;//'static' when not moving. (Used by the following deviceTypes: Blind Tilt) -mode?: number; //available for devices. the fan mode. (Used by the following deviceTypes: Smart Fan) -speed?: number;//the fan speed. (Used by the following deviceTypes: Smart Fan) -shaking?: boolean;//determines if the fan is swinging or not. (Used by the following deviceTypes: Smart Fan) -shakeCenter?: string;//the fan's swing direciton. (Used by the following deviceTypes: Smart Fan) -shakeRange?: string;//the fan's swing range, 0~120°. (Used by the following deviceTypes: Smart Fan) + //v1.1 of API + deviceId: string; //device ID. (Used by the following deviceTypes: Bot, Curtain, Meter, Meter Plus, Lock, Keypad, Keypad Touch, Motion Sensor, Contact Sensor, Ceiling Light, Ceiling Light Pro, Plug Mini (US), Plug Mini (JP), Strip Light, Color Bulb, Robot Vacuum Cleaner S1, Robot Vacuum Cleaner S1 Plus, Humidifier, Blind Tilt) + deviceType: string; //device type. (Used by the following deviceTypes: Bot, Curtain, Meter, Meter Plus, Lock, Keypad, Keypad Touch, Motion Sensor, Contact Sensor, Ceiling Light, Ceiling Light Pro, Plug Mini (US), Plug Mini (JP), Strip Light, Color Bulb, Robot Vacuum Cleaner S1, Robot Vacuum Cleaner S1 Plus, Humidifier, Blind Tilt) + hubDeviceId: string; //device's parent Hub ID. 000000000000 when the device itself is a Hub or it is connected through Wi-Fi. (Used by the following deviceTypes: Bot, Curtain, Meter, Meter Plus, Lock, Keypad, Keypad Touch, Motion Sensor, Contact Sensor, Ceiling Light, Ceiling Light Pro, Plug Mini (JP), Strip Light, Color Bulb, Robot Vacuum Cleaner S1, Robot Vacuum Cleaner S1 Plus, Humidifier, Blind Tilt) + power?: string; //ON/OFF state. (Used by the following deviceTypes: Bot, Ceiling Light, Ceiling Light Pro, PLug, Plug Mini (US), Plug Mini (JP), Strip Light, Color Bulb, Humidifier) + calibrate?: boolean; //determines if device has been calibrated or not. (Used by the following deviceTypes: Curtain, Lock, Blind Tilt) + group?: boolean; //determines if a device is paired with or grouped with another device or not. (Used by the following deviceTypes: Curtain, Blind Tilt) + moving?: boolean; //determines if a device is moving or not. (Used by the following deviceTypes: Curtain, Blind Tilt) + slidePosition?: number; //the current position (0-100) the percentage of the distance between the calibrated open position and closed position. (Used by the following deviceTypes: Curtain, Blind Tilt) + temperature?: number; //temperature in celsius (Used by the following deviceTypes: Meter, Meter Plus, Humidifier, IOSensor) + humidity?: number; //humidity percentage. (Used by the following deviceTypes: Meter, Meter Plus, Humidifier, IOSensor) + lockState?: string; //determines if locked or not. (Used by the following deviceTypes: Lock) + doorState?: string; //determines if the door is closed or not. (Used by the following deviceTypes: Lock) + moveDetected?: boolean; //determines if motion is detected. (Used by the following deviceTypes: Motion Sensor, Contact Sensor) + brightness?: string | number; //the ambient brightness picked up by the sensor. bright or dim. (Used by the following deviceTypes: Motion Sensor, Contact Sensor) | the brightness value, range from 1 to 100. (Used by the following deviceTypes: Ceiling Light, Ceiling Light Pro, Strip Light, Color Bulb) + openState?: string; //the open state of the sensor. open, close, or timeOutNotClose. (Used by the following deviceTypes: Contact Sensor) + colorTemperature?: number; //the color temperature value, range from 2700 to 6500. (Used by the following deviceTypes: Ceiling Light, Ceiling Light Pro, Color Bulb) + voltage?: number; //the voltage of the device, measured in Volt. (Used by the following deviceTypes: Plug Mini (US), Plug Mini (JP)) + weight?: number; //the power consumed in a day, measured in Watts. (Used by the following deviceTypes: Plug Mini (US), Plug Mini (JP)) + electricityOfDay?: number; //the duration that the device has been used during a day, measured in minutes. (Used by the following deviceTypes: Plug Mini (US), Plug Mini (JP)) + electricCurrent?: number; //the current of the device at the moment, measured in Amp. (Used by the following deviceTypes: Plug Mini (US), Plug Mini (JP)) + color?: string; //the color value, RGB "255:255:255". (Used by the following deviceTypes: Strip Light, Color Bulb) + workingStatus?: string; //the working status of the device. StandBy, Clearing, Paused, GotoChargeBase, Charging, ChargeDone, Dormant, InTrouble, InRemoteControl, or InDustCollecting. (Used by the following deviceTypes: Robot Vacuum Cleaner S1, Robot Vacuum Cleaner S1 Plus) + onlineStatus?: string; //the connection status of the device. online or offline. (Used by the following deviceTypes: Robot Vacuum Cleaner S1, Robot Vacuum Cleaner S1 Plus) + battery?: number; //the current battery level. (Used by the following deviceTypes: Robot Vacuum Cleaner S1, Robot Vacuum Cleaner S1 Plus, Blind Tilt, IOSensor) + deviceName?: string; //device name. (Used by the following deviceTypes: Robot Vacuum Cleaner S1 Plus) + nebulizationEfficiency?: number; //atomization efficiency percentage. (Used by the following deviceTypes: Humidifier) + auto?: boolean; //determines if a Humidifier is in Auto Mode or not. (Used by the following deviceTypes: Humidifier) + childLock?: boolean; //determines if a Humidifier's safety lock is on or not. (Used by the following deviceTypes: Humidifier) + sound?: boolean; //determines if a Humidifier is muted or not. (Used by the following deviceTypes: Humidifier) + lackWater?: boolean; //determines if the water tank is empty or not. (Used by the following deviceTypes: Humidifier) + version?: number; //the version of the device. (Used by the following deviceTypes: Blind Tilt, Meter, MeterPlus, IOSensor) + direction?: string; //the opening direction of a Blind Tilt device. (Used by the following deviceTypes: Blind Tilt) + runStatus?: string; //'static' when not moving. (Used by the following deviceTypes: Blind Tilt) + mode?: number; //available for devices. the fan mode. (Used by the following deviceTypes: Smart Fan) + speed?: number; //the fan speed. (Used by the following deviceTypes: Smart Fan) + shaking?: boolean; //determines if the fan is swinging or not. (Used by the following deviceTypes: Smart Fan) + shakeCenter?: string; //the fan's swing direciton. (Used by the following deviceTypes: Smart Fan) + shakeRange?: string; //the fan's swing range, 0~120°. (Used by the following deviceTypes: Smart Fan) }; export type ad = { diff --git a/src/utils.ts b/src/utils.ts index 5785ba78..421bda08 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,3 +1,3 @@ export function sleep(ms: number): Promise { - return new Promise(resolve => setTimeout(resolve, ms)); + return new Promise((resolve) => setTimeout(resolve, ms)); }