From 4be18e833bdd2953bf1795f50c6d43ab6d847180 Mon Sep 17 00:00:00 2001 From: Donavan Becker Date: Thu, 31 Mar 2022 18:28:24 -0500 Subject: [PATCH] v1.7.0 (#208) ## [Version 1.7.0](https://github.com/donavanbecker/homebridge-rainbird/releases/tag/v1.7.0) (2022-03-31) ### What's Changed - Added option to show zones as separate valve accessories. - Refactored device classes to use a common base class. - Housekeeping and updated dependencies. **Full Changelog**: https://github.com/donavanbecker/homebridge-rainbird/compare/v1.6.4...v1.7.0 --- .github/ISSUE_TEMPLATE/bug-report.yml | 4 +- .github/ISSUE_TEMPLATE/feature-request.yml | 4 +- .github/ISSUE_TEMPLATE/support-request.yml | 4 +- .github/PULL_REQUEST_TEMPLATE/pull_request.md | 4 +- CHANGELOG.md | 40 +- README.md | 7 +- config.schema.json | 7 + package-lock.json | 580 +++++++++--------- package.json | 16 +- src/RainBird/RainBirdService.ts | 1 + src/devices/ContactSensor.ts | 96 +-- src/devices/DeviceBase.ts | 92 +++ src/devices/IrrigationSystem.ts | 175 ++---- src/devices/LeakSensor.ts | 93 +-- src/devices/ProgramSwitch.ts | 96 +-- src/devices/StopIrrigationSwitch.ts | 96 +-- src/devices/ZoneValve.ts | 208 +++++++ src/platform.ts | 92 ++- src/settings.ts | 1 + 19 files changed, 831 insertions(+), 785 deletions(-) create mode 100644 src/devices/DeviceBase.ts create mode 100644 src/devices/ZoneValve.ts diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml index d83be9e..3123030 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -2,7 +2,9 @@ name: Bug-Report description: Report a Bug to help us improve title: "Bug: " labels: [bug] -assignees: 'donavanbecker' +assignees: + - donavanbecker + - mantorok1 body: - type: markdown attributes: diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml index b82f4ff..570cb65 100644 --- a/.github/ISSUE_TEMPLATE/feature-request.yml +++ b/.github/ISSUE_TEMPLATE/feature-request.yml @@ -2,7 +2,9 @@ name: Feature Request description: Suggest an idea for this project title: "Feature Request: " labels: [enhancement] -assignees: 'donavanbecker' +assignees: + - donavanbecker + - mantorok1 body: - type: markdown attributes: diff --git a/.github/ISSUE_TEMPLATE/support-request.yml b/.github/ISSUE_TEMPLATE/support-request.yml index 6d2b260..9cd31c1 100644 --- a/.github/ISSUE_TEMPLATE/support-request.yml +++ b/.github/ISSUE_TEMPLATE/support-request.yml @@ -2,7 +2,9 @@ name: Support Request description: Need help? title: "Support Request: " labels: [question] -assignees: 'donavanbecker' +assignees: + - donavanbecker + - mantorok1 body: - type: markdown attributes: diff --git a/.github/PULL_REQUEST_TEMPLATE/pull_request.md b/.github/PULL_REQUEST_TEMPLATE/pull_request.md index 1f94731..59e0c79 100644 --- a/.github/PULL_REQUEST_TEMPLATE/pull_request.md +++ b/.github/PULL_REQUEST_TEMPLATE/pull_request.md @@ -3,7 +3,9 @@ name: Enhancement about: Contribute to Plugin through Pull Request title: '' labels: 'enhancement' -assignees: 'donavanbecker' +assignees: + - donavanbecker + - mantorok1 --- **Is your enhancement related to a problem? Please describe.** diff --git a/CHANGELOG.md b/CHANGELOG.md index d1fef6c..403b15e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,19 @@ All notable changes to this project will be documented in this file. This project uses [Semantic Versioning](https://semver.org/) +## [Version 1.7.0](https://github.com/donavanbecker/homebridge-rainbird/releases/tag/v1.7.0) (2022-03-31) + +### What's Changed + +- Added option to show zones as separate valve accessories. +- Refactored device classes to use a common base class. +- Housekeeping and updated dependencies. + +**Full Changelog**: https://github.com/donavanbecker/homebridge-rainbird/compare/v1.6.4...v1.7.0 + ## [Version 1.6.4](https://github.com/donavanbecker/homebridge-rainbird/releases/tag/v1.6.4) (2022-03-19) -### What's Changes +### What's Changed - Housekeeping and updated dependencies. @@ -12,7 +22,7 @@ All notable changes to this project will be documented in this file. This projec ## [Version 1.6.3](https://github.com/donavanbecker/homebridge-rainbird/releases/tag/v1.6.3) (2022-02-15) -### What's Changes +### What's Changed - Housekeeping and updated dependencies. @@ -20,7 +30,7 @@ All notable changes to this project will be documented in this file. This projec ## [Version 1.6.2](https://github.com/donavanbecker/homebridge-rainbird/releases/tag/v1.6.2) (2022-02-12) -### What's Changes +### What's Changed - Housekeeping and updated dependencies. @@ -28,7 +38,7 @@ All notable changes to this project will be documented in this file. This projec ## [Version 1.6.1](https://github.com/donavanbecker/homebridge-rainbird/releases/tag/v1.6.1) (2022-01-29) -### What's Changes +### What's Changed - Restore Request/Response logging. - prevent Program Switch showing as running when rain set point reached. @@ -38,7 +48,7 @@ All notable changes to this project will be documented in this file. This projec ## [Version 1.6.0](https://github.com/donavanbecker/homebridge-rainbird/releases/tag/v1.6.0) (2022-01-27) -### What's Changes +### What's Changed ### Major Change To `Logging`: @@ -63,7 +73,7 @@ All notable changes to this project will be documented in this file. This projec ## [Version 1.5.2](https://github.com/donavanbecker/homebridge-rainbird/releases/tag/v1.5.2) (2021-12-15) -### What's Changes +### What's Changed - Housekeeping and updated dependencies. @@ -71,7 +81,7 @@ All notable changes to this project will be documented in this file. This projec ## [Version 1.5.1](https://github.com/donavanbecker/homebridge-rainbird/compare/v1.5.0...v1.5.1) (2021-11-12) -### What's Changes +### What's Changed - Housekeeping and updated dependencies. @@ -79,7 +89,7 @@ All notable changes to this project will be documented in this file. This projec ## [Version 1.5.0](https://github.com/donavanbecker/homebridge-rainbird/compare/v1.4.0...v1.5.0) (2021-11-06) -### What's Changes +### What's Changed - Added enableZone to find Enabled Zones - Added Command Logging for plugin @@ -89,7 +99,7 @@ All notable changes to this project will be documented in this file. This projec ## [Version 1.4.0](https://github.com/donavanbecker/homebridge-rainbird/compare/v1.3.0...v1.4.0) (2021-10-28) -### What's Changes +### What's Changed - Added support to show vavles as contact sensors - Allows you to get notified in the Home App when a Zone has started. @@ -103,7 +113,7 @@ All notable changes to this project will be documented in this file. This projec ## [Version 1.3.0](https://github.com/donavanbecker/homebridge-rainbird/compare/v1.2.0...v1.3.0) (2021-10-09) -### What's Changes +### What's Changed - Support for rain sensor using the HomeKit leak sensor - Suppress a zone's active status when scheduled program has been suspended (due to rain) @@ -114,7 +124,7 @@ All notable changes to this project will be documented in this file. This projec ## [Version 1.2.0](https://github.com/donavanbecker/homebridge-rainbird/compare/v1.1.0...v1.2.0) (2021-09-29) -### What's Changes +### What's Changed - Added CurrentZoneTimeRemainingRequest & CurrentZoneTimeRemainingResponse function. - Fixed issue where some RainBird controllers (such as ESP-RZXe & ESP-Me) couldn't show the time remaining for a zone that was not started via the plugin (such as a scheduled program). @@ -123,7 +133,7 @@ All notable changes to this project will be documented in this file. This projec ## [Version 1.1.0](https://github.com/donavanbecker/homebridge-rainbird/compare/v1.0.0...v1.1.0) (2021-09-27) -### What's Changes +### What's Changed - Add Support for More Models and Added Compatiable Models to Readme. - Fixed `Failed to Discover Devices, "Cannot read property 'getTime' of undefined"` [#39](https://github.com/donavanbecker/homebridge-rainbird/issues/39). @@ -132,7 +142,7 @@ All notable changes to this project will be documented in this file. This projec ## [Version 1.0.0](https://github.com/donavanbecker/homebridge-rainbird/compare/v0.1.0...v1.0.0) (2021-09-19) -### What's Changes +### What's Changed - Official Release of Homebridge RainBird Plugin. @@ -140,7 +150,7 @@ All notable changes to this project will be documented in this file. This projec ## [Version 0.2.0](https://github.com/donavanbecker/homebridge-rainbird/tag/v0.0.1) (2021-09-17) -### What's Changes +### What's Changed - Add Plugin Debug Config Option @@ -148,6 +158,6 @@ All notable changes to this project will be documented in this file. This projec ## [Version 0.1.0](https://github.com/donavanbecker/homebridge-rainbird/tag/v0.0.1) (2021-08-29) -### What's Changes +### What's Changed - Initial Release diff --git a/README.md b/README.md index 144fa7f..611bd0e 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,7 @@ Any controller that supports the [RainBird LNK WiFi Module](https://www.rainbird - ESP-ME3 (see "Known Limitations") ## Known Limitations -- Using the RainBird app while the plugin is running can cause connectivity issues -- The RainBird LNK WiFi Module doesn't seem to support "Band Steering" and WiFi Channel 13. Please ensure your router is not configured to use these. -- ESP-ME3: It is not currently possible to show the time remaining for a zone that was not started via the plugin (such as a scheduled program). The time remaining will show as `00:00` in these cases. Also a zone will show as active even though a scheduled program has been suspended (due to rain) \ No newline at end of file +- Using the RainBird app while the plugin is running can cause connectivity issues. +- The RainBird LNK WiFi Module may not support "Band Steering" and WiFi Channel 13. Try not using these on your router if you are having connectivity issues. +- ESP-ME3: It is not currently possible to show the time remaining for a zone that was not started via the plugin (such as a scheduled program). The time remaining will show as `00:00` in these cases. Also a zone will show as active even though a scheduled program has been suspended (due to rain). +- iOS 15.4/macOS 12.3 introduced a bug that prevents the valves (zones) from showing within the Irrigation System accessory in the Home app. Try using the "Show Zones as Valve Accessories" option as a workaround. \ No newline at end of file diff --git a/config.schema.json b/config.schema.json index 3c7f65c..9b35d70 100644 --- a/config.schema.json +++ b/config.schema.json @@ -67,6 +67,12 @@ "type": "boolean", "requried": false }, + "showZoneValve": { + "title": "Show Zones as Valve Accessories", + "type": "boolean", + "required": false, + "description": "Show zones as seperate valve accessories (useful to workaround the bug introduced in iOS 15.4/macOS 12.3 that prevents the valves from showing within the Irrigation System accessory)." + }, "showRequestResponse": { "title": "Show RainBird requests and responses in the log", "type": "boolean", @@ -182,6 +188,7 @@ "devices[].showProgramBSwitch", "devices[].showProgramCSwitch", "devices[].showStopIrrigationSwitch", + "devices[].showZoneValve", "devices[].showRequestResponse", "devices[].refreshRate", "devices[].logging" diff --git a/package-lock.json b/package-lock.json index aaaf0ab..a1b476d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "homebridge-rainbird", - "version": "1.6.4", + "version": "1.7.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "homebridge-rainbird", - "version": "1.6.4", + "version": "1.7.0", "funding": [ { "type": "Paypal - donavanbecker", @@ -34,25 +34,25 @@ "devDependencies": { "@types/aes-js": "^3.1.1", "@types/better-queue": "^3.8.3", - "@types/node": "^17.0.21", + "@types/node": "^17.0.23", "@types/node-fetch": "^3.0.3", - "@typescript-eslint/eslint-plugin": "^5.15.0", - "@typescript-eslint/parser": "^5.15.0", - "eslint": "^8.11.0", + "@typescript-eslint/eslint-plugin": "^5.17.0", + "@typescript-eslint/parser": "^5.17.0", + "eslint": "^8.12.0", "eslint-config-prettier": "8.5.0", "eslint-plugin-prettier": "4.0.0", "homebridge": "^1.4.0", "nodemon": "^2.0.15", "npm-check-updates": "^12.5.4", - "prettier": "2.6.0", + "prettier": "2.6.1", "rimraf": "^3.0.2", "ts-node": "^10.7.0", - "typescript": "^4.6.2", + "typescript": "^4.6.3", "typescript-axios-wb": "^1.0.3" }, "engines": { "homebridge": "^1.4.0", - "node": "^14.19.0 || ^16.14.0" + "node": "^14.19.1 || ^16.14.2" } }, "node_modules/@cspotcode/source-map-consumer": { @@ -208,13 +208,16 @@ } }, "node_modules/@npmcli/fs": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", - "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.0.tgz", + "integrity": "sha512-DmfBvNXGaetMxj9LTp8NAN9vEidXURrf5ZTslQzEAi/6GbW+4yjaLFQc6Tue5cpZ9Frlk4OBo/Snf1Bh/S7qTQ==", "dev": true, "dependencies": { - "@gar/promisify": "^1.0.1", + "@gar/promisify": "^1.1.3", "semver": "^7.3.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, "node_modules/@npmcli/git": { @@ -238,9 +241,9 @@ } }, "node_modules/@npmcli/git/node_modules/lru-cache": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.7.1.tgz", - "integrity": "sha512-cRffBiTW8s73eH4aTXqBcTLU0xQnwGV3/imttRHGWCrbergmnK4D6JXQd8qin5z43HnDwRI+o7mVW0LEB+tpAw==", + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.7.3.tgz", + "integrity": "sha512-WY9wjJNQt9+PZilnLbuFKM+SwDull9+6IAguOrarOMoOHTcJ9GnXSO11+Gw6c7xtDkBkthR57OZMtZKYr+1CEw==", "dev": true, "engines": { "node": ">=12" @@ -399,15 +402,15 @@ } }, "node_modules/@types/json-schema": { - "version": "7.0.10", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.10.tgz", - "integrity": "sha512-BLO9bBq59vW3fxCpD4o0N4U+DXsvwvIcl+jofw0frQo/GrBFC+/jRZj1E7kgp6dvTyNmA4y6JCV5Id/r3mNP5A==", + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", "dev": true }, "node_modules/@types/node": { - "version": "17.0.21", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.21.tgz", - "integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==", + "version": "17.0.23", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.23.tgz", + "integrity": "sha512-UxDxWn7dl97rKVeVS61vErvw086aCYhDLyvRQZ5Rk65rZKepaFdm53GeqXaKBuOhED4e9uWq34IC3TdSdJJ2Gw==", "dev": true }, "node_modules/@types/node-fetch": { @@ -421,14 +424,14 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.15.0.tgz", - "integrity": "sha512-u6Db5JfF0Esn3tiAKELvoU5TpXVSkOpZ78cEGn/wXtT2RVqs2vkt4ge6N8cRCyw7YVKhmmLDbwI2pg92mlv7cA==", + "version": "5.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.17.0.tgz", + "integrity": "sha512-qVstvQilEd89HJk3qcbKt/zZrfBZ+9h2ynpAGlWjWiizA7m/MtLT9RoX6gjtpE500vfIg8jogAkDzdCxbsFASQ==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.15.0", - "@typescript-eslint/type-utils": "5.15.0", - "@typescript-eslint/utils": "5.15.0", + "@typescript-eslint/scope-manager": "5.17.0", + "@typescript-eslint/type-utils": "5.17.0", + "@typescript-eslint/utils": "5.17.0", "debug": "^4.3.2", "functional-red-black-tree": "^1.0.1", "ignore": "^5.1.8", @@ -454,14 +457,14 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.15.0.tgz", - "integrity": "sha512-NGAYP/+RDM2sVfmKiKOCgJYPstAO40vPAgACoWPO/+yoYKSgAXIFaBKsV8P0Cc7fwKgvj27SjRNX4L7f4/jCKQ==", + "version": "5.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.17.0.tgz", + "integrity": "sha512-aRzW9Jg5Rlj2t2/crzhA2f23SIYFlF9mchGudyP0uiD6SenIxzKoLjwzHbafgHn39dNV/TV7xwQkLfFTZlJ4ig==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.15.0", - "@typescript-eslint/types": "5.15.0", - "@typescript-eslint/typescript-estree": "5.15.0", + "@typescript-eslint/scope-manager": "5.17.0", + "@typescript-eslint/types": "5.17.0", + "@typescript-eslint/typescript-estree": "5.17.0", "debug": "^4.3.2" }, "engines": { @@ -481,13 +484,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.15.0.tgz", - "integrity": "sha512-EFiZcSKrHh4kWk0pZaa+YNJosvKE50EnmN4IfgjkA3bTHElPtYcd2U37QQkNTqwMCS7LXeDeZzEqnsOH8chjSg==", + "version": "5.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.17.0.tgz", + "integrity": "sha512-062iCYQF/doQ9T2WWfJohQKKN1zmmXVfAcS3xaiialiw8ZUGy05Em6QVNYJGO34/sU1a7a+90U3dUNfqUDHr3w==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.15.0", - "@typescript-eslint/visitor-keys": "5.15.0" + "@typescript-eslint/types": "5.17.0", + "@typescript-eslint/visitor-keys": "5.17.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -498,12 +501,12 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.15.0.tgz", - "integrity": "sha512-KGeDoEQ7gHieLydujGEFLyLofipe9PIzfvA/41urz4hv+xVxPEbmMQonKSynZ0Ks2xDhJQ4VYjB3DnRiywvKDA==", + "version": "5.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.17.0.tgz", + "integrity": "sha512-3hU0RynUIlEuqMJA7dragb0/75gZmwNwFf/QJokWzPehTZousP/MNifVSgjxNcDCkM5HI2K22TjQWUmmHUINSg==", "dev": true, "dependencies": { - "@typescript-eslint/utils": "5.15.0", + "@typescript-eslint/utils": "5.17.0", "debug": "^4.3.2", "tsutils": "^3.21.0" }, @@ -524,9 +527,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.15.0.tgz", - "integrity": "sha512-yEiTN4MDy23vvsIksrShjNwQl2vl6kJeG9YkVJXjXZnkJElzVK8nfPsWKYxcsGWG8GhurYXP4/KGj3aZAxbeOA==", + "version": "5.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.17.0.tgz", + "integrity": "sha512-AgQ4rWzmCxOZLioFEjlzOI3Ch8giDWx8aUDxyNw9iOeCvD3GEYAB7dxWGQy4T/rPVe8iPmu73jPHuaSqcjKvxw==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -537,13 +540,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.15.0.tgz", - "integrity": "sha512-Hb0e3dGc35b75xLzixM3cSbG1sSbrTBQDfIScqdyvrfJZVEi4XWAT+UL/HMxEdrJNB8Yk28SKxPLtAhfCbBInA==", + "version": "5.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.17.0.tgz", + "integrity": "sha512-X1gtjEcmM7Je+qJRhq7ZAAaNXYhTgqMkR10euC4Si6PIjb+kwEQHSxGazXUQXFyqfEXdkGf6JijUu5R0uceQzg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.15.0", - "@typescript-eslint/visitor-keys": "5.15.0", + "@typescript-eslint/types": "5.17.0", + "@typescript-eslint/visitor-keys": "5.17.0", "debug": "^4.3.2", "globby": "^11.0.4", "is-glob": "^4.0.3", @@ -564,15 +567,15 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.15.0.tgz", - "integrity": "sha512-081rWu2IPKOgTOhHUk/QfxuFog8m4wxW43sXNOMSCdh578tGJ1PAaWPsj42LOa7pguh173tNlMigsbrHvh/mtA==", + "version": "5.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.17.0.tgz", + "integrity": "sha512-DVvndq1QoxQH+hFv+MUQHrrWZ7gQ5KcJzyjhzcqB1Y2Xes1UQQkTRPUfRpqhS8mhTWsSb2+iyvDW1Lef5DD7vA==", "dev": true, "dependencies": { "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.15.0", - "@typescript-eslint/types": "5.15.0", - "@typescript-eslint/typescript-estree": "5.15.0", + "@typescript-eslint/scope-manager": "5.17.0", + "@typescript-eslint/types": "5.17.0", + "@typescript-eslint/typescript-estree": "5.17.0", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0" }, @@ -588,12 +591,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.15.0.tgz", - "integrity": "sha512-+vX5FKtgvyHbmIJdxMJ2jKm9z2BIlXJiuewI8dsDYMp5LzPUcuTT78Ya5iwvQg3VqSVdmxyM8Anj1Jeq7733ZQ==", + "version": "5.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.17.0.tgz", + "integrity": "sha512-6K/zlc4OfCagUu7Am/BD5k8PSWQOgh34Nrv9Rxe2tBzlJ7uOeJ/h7ugCGDCeEZHT6k2CJBhbk9IsbkPI0uvUkA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.15.0", + "@typescript-eslint/types": "5.17.0", "eslint-visitor-keys": "^3.0.0" }, "engines": { @@ -899,24 +902,27 @@ "dev": true }, "node_modules/builtins": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", - "integrity": "sha1-y5T662HIaWRR2zZTThQi+U8K7og=", - "dev": true + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.0.tgz", + "integrity": "sha512-aizhtbxgT1Udg0Fj6GssXshAVK+nxbtCV+1OtTrMNy67jffDFBY6CUBAkhO4owbleAx6fdbnWdpsmmcXydbzNw==", + "dev": true, + "dependencies": { + "semver": "^7.0.0" + } }, "node_modules/cacache": { - "version": "16.0.2", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.0.2.tgz", - "integrity": "sha512-Q17j7s8X81i/QYVrKVQ/qwWGT+pYLfpTcZ+X+p/Qw9FULy9JEfb2FECYTTt6mPV6A/vk92nRZ80ncpKxiGTrIA==", + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.0.3.tgz", + "integrity": "sha512-eC7wYodNCVb97kuHGk5P+xZsvUJHkhSEOyNwkenqQPAsOtrTjvWOE5vSPNBpz9d8X3acIf6w2Ub5s4rvOCTs4g==", "dev": true, "dependencies": { - "@npmcli/fs": "^1.0.0", + "@npmcli/fs": "^2.1.0", "@npmcli/move-file": "^1.1.2", "chownr": "^2.0.0", "fs-minipass": "^2.1.0", "glob": "^7.2.0", "infer-owner": "^1.0.4", - "lru-cache": "^7.5.1", + "lru-cache": "^7.7.1", "minipass": "^3.1.6", "minipass-collect": "^1.0.2", "minipass-flush": "^1.0.5", @@ -930,13 +936,13 @@ "unique-filename": "^1.1.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, "node_modules/cacache/node_modules/lru-cache": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.7.1.tgz", - "integrity": "sha512-cRffBiTW8s73eH4aTXqBcTLU0xQnwGV3/imttRHGWCrbergmnK4D6JXQd8qin5z43HnDwRI+o7mVW0LEB+tpAw==", + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.7.3.tgz", + "integrity": "sha512-WY9wjJNQt9+PZilnLbuFKM+SwDull9+6IAguOrarOMoOHTcJ9GnXSO11+Gw6c7xtDkBkthR57OZMtZKYr+1CEw==", "dev": true, "engines": { "node": ">=12" @@ -1512,9 +1518,9 @@ "dev": true }, "node_modules/es-abstract": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", - "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.2.tgz", + "integrity": "sha512-gfSBJoZdlL2xRiOCy0g8gLMryhoe1TlimjzU99L/31Z8QEGIhVQI+EWwt5lT+AuU9SnorVupXFqqOGqGfsyO6w==", "dev": true, "dependencies": { "call-bind": "^1.0.2", @@ -1523,15 +1529,15 @@ "get-intrinsic": "^1.1.1", "get-symbol-description": "^1.0.0", "has": "^1.0.3", - "has-symbols": "^1.0.2", + "has-symbols": "^1.0.3", "internal-slot": "^1.0.3", "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.1", + "is-negative-zero": "^2.0.2", "is-regex": "^1.1.4", "is-shared-array-buffer": "^1.0.1", "is-string": "^1.0.7", - "is-weakref": "^1.0.1", - "object-inspect": "^1.11.0", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.0", "object-keys": "^1.1.1", "object.assign": "^4.1.2", "string.prototype.trimend": "^1.0.4", @@ -1603,9 +1609,9 @@ } }, "node_modules/eslint": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.11.0.tgz", - "integrity": "sha512-/KRpd9mIRg2raGxHRGwW9ZywYNAClZrHjdueHcrVDuO3a6bj83eoTirCCk0M0yPwOjWYKHwRVRid+xK4F/GHgA==", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.12.0.tgz", + "integrity": "sha512-it1oBL9alZg1S8UycLm5YDMAkIhtH6FtAzuZs6YvoGVldWjbS08BkAdb/ymP9LlAyq8koANu32U7Ib/w+UNh8Q==", "dev": true, "dependencies": { "@eslint/eslintrc": "^1.2.1", @@ -2149,9 +2155,9 @@ } }, "node_modules/gauge": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.3.tgz", - "integrity": "sha512-ICw1DhAwMtb22rYFwEHgJcx1JCwJGv3x6G0OQUq56Nge+H4Q8JEwr8iveS0XFlsUNSI67F5ffMGK25bK4Pmskw==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", "dev": true, "dependencies": { "aproba": "^1.0.3 || ^2.0.0", @@ -2164,7 +2170,7 @@ "wide-align": "^1.1.5" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, "node_modules/get-intrinsic": { @@ -3074,13 +3080,10 @@ "dev": true }, "node_modules/json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", "dev": true, - "dependencies": { - "minimist": "^1.2.5" - }, "bin": { "json5": "lib/cli.js" }, @@ -3309,18 +3312,18 @@ "dev": true }, "node_modules/make-fetch-happen": { - "version": "10.0.6", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.0.6.tgz", - "integrity": "sha512-4Gfh6lV3TLXmj7qz79hBFuvVqjYSMW6v2+sxtdX4LFQU0rK3V/txRjE0DoZb7X0IF3t9f8NO3CxPSWlvdckhVA==", + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.1.1.tgz", + "integrity": "sha512-3/mCljDQNjmrP7kl0vhS5WVlV+TvSKoZaFhdiYV7MOijEnrhrjaVnqbp/EY/7S+fhUB2KpH7j8c1iRsIOs+kjw==", "dev": true, "dependencies": { "agentkeepalive": "^4.2.1", - "cacache": "^16.0.0", + "cacache": "^16.0.2", "http-cache-semantics": "^4.1.0", "http-proxy-agent": "^5.0.0", "https-proxy-agent": "^5.0.0", "is-lambda": "^1.0.1", - "lru-cache": "^7.5.1", + "lru-cache": "^7.7.1", "minipass": "^3.1.6", "minipass-collect": "^1.0.2", "minipass-fetch": "^2.0.3", @@ -3332,13 +3335,13 @@ "ssri": "^8.0.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, "node_modules/make-fetch-happen/node_modules/lru-cache": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.7.1.tgz", - "integrity": "sha512-cRffBiTW8s73eH4aTXqBcTLU0xQnwGV3/imttRHGWCrbergmnK4D6JXQd8qin5z43HnDwRI+o7mVW0LEB+tpAw==", + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.7.3.tgz", + "integrity": "sha512-WY9wjJNQt9+PZilnLbuFKM+SwDull9+6IAguOrarOMoOHTcJ9GnXSO11+Gw6c7xtDkBkthR57OZMtZKYr+1CEw==", "dev": true, "engines": { "node": ">=12" @@ -3360,13 +3363,13 @@ } }, "node_modules/micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "dev": true, "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" + "braces": "^3.0.2", + "picomatch": "^2.3.1" }, "engines": { "node": ">=8.6" @@ -3394,9 +3397,9 @@ } }, "node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", "dev": true }, "node_modules/minipass": { @@ -3424,9 +3427,9 @@ } }, "node_modules/minipass-fetch": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.0.3.tgz", - "integrity": "sha512-VA+eiiUtaIvpQJXISwE3OiMvQwAWrgKb97F0aXlCS1Ahikr8fEQq8m3Hf7Kv9KT3nokuHigJKsDMB6atU04olQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.0.tgz", + "integrity": "sha512-H9U4UVBGXEyyWJnqYDCLp1PwD8XIkJ4akNHp1aGVI+2Ym7wQMlxDKi4IB4JbmyU+pl9pEs/cVrK6cOuvmbK4Sg==", "dev": true, "dependencies": { "minipass": "^3.1.6", @@ -3434,7 +3437,7 @@ "minizlib": "^2.1.2" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" }, "optionalDependencies": { "encoding": "^0.1.13" @@ -3500,12 +3503,12 @@ } }, "node_modules/mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, "dependencies": { - "minimist": "^1.2.5" + "minimist": "^1.2.6" }, "bin": { "mkdirp": "bin/cmd.js" @@ -3733,9 +3736,9 @@ } }, "node_modules/normalize-package-data/node_modules/lru-cache": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.7.1.tgz", - "integrity": "sha512-cRffBiTW8s73eH4aTXqBcTLU0xQnwGV3/imttRHGWCrbergmnK4D6JXQd8qin5z43HnDwRI+o7mVW0LEB+tpAw==", + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.7.3.tgz", + "integrity": "sha512-WY9wjJNQt9+PZilnLbuFKM+SwDull9+6IAguOrarOMoOHTcJ9GnXSO11+Gw6c7xtDkBkthR57OZMtZKYr+1CEw==", "dev": true, "engines": { "node": ">=12" @@ -3861,17 +3864,17 @@ "dev": true }, "node_modules/npm-package-arg": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-9.0.1.tgz", - "integrity": "sha512-Xs9wznfEAmZAR61qsYH3iN24V/qMYYkvAR5CRQNMvC6PjN2fHtO8y9XP/xdp5K+Icx+u1wMBMgWRPCmAEChSog==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-9.0.2.tgz", + "integrity": "sha512-v/miORuX8cndiOheW8p2moNuPJ7QhcFh9WGlTorruG8hXSA23vMTEp5hTCmDxic0nD8KHhj/NQgFuySD3GYY3g==", "dev": true, "dependencies": { "hosted-git-info": "^5.0.0", "semver": "^7.3.5", - "validate-npm-package-name": "^3.0.0" + "validate-npm-package-name": "^4.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, "node_modules/npm-package-arg/node_modules/hosted-git-info": { @@ -3887,9 +3890,9 @@ } }, "node_modules/npm-package-arg/node_modules/lru-cache": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.7.1.tgz", - "integrity": "sha512-cRffBiTW8s73eH4aTXqBcTLU0xQnwGV3/imttRHGWCrbergmnK4D6JXQd8qin5z43HnDwRI+o7mVW0LEB+tpAw==", + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.7.3.tgz", + "integrity": "sha512-WY9wjJNQt9+PZilnLbuFKM+SwDull9+6IAguOrarOMoOHTcJ9GnXSO11+Gw6c7xtDkBkthR57OZMtZKYr+1CEw==", "dev": true, "engines": { "node": ">=12" @@ -3929,21 +3932,21 @@ } }, "node_modules/npm-registry-fetch": { - "version": "13.0.1", - "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-13.0.1.tgz", - "integrity": "sha512-Ak+LXVtSrCLOdscFW/apUw67OPNph8waHsPKM9UOJosL7i59EF5XoSWQMEsXEOeifM9Bb4/2+WrQC4t/pd8DGg==", + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-13.1.0.tgz", + "integrity": "sha512-TIYL5X8CcwDhbFMXFDShNcpG6OMCYK6VzvSr6MUWP20tCU2DJ4ao2qQg3DT+3Pet8mO6/cgbZpon4LMh3duYLg==", "dev": true, "dependencies": { - "make-fetch-happen": "^10.0.3", + "make-fetch-happen": "^10.0.6", "minipass": "^3.1.6", - "minipass-fetch": "^2.0.1", + "minipass-fetch": "^2.0.3", "minipass-json-stream": "^1.0.1", "minizlib": "^2.1.2", - "npm-package-arg": "^9.0.0", + "npm-package-arg": "^9.0.1", "proc-log": "^2.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, "node_modules/npmlog": { @@ -4301,9 +4304,9 @@ } }, "node_modules/prettier": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.6.0.tgz", - "integrity": "sha512-m2FgJibYrBGGgQXNzfd0PuDGShJgRavjUoRCw1mZERIWVSXF0iLzLm+aOqTAbLnC3n6JzUhAA8uZnFVghHJ86A==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.6.1.tgz", + "integrity": "sha512-8UVbTBYGwN37Bs9LERmxCPjdvPxlEowx2urIL6urHzdb3SDq4B/Z6xLFCblrSnE4iKWcS6ziJ3aOYrc1kz/E2A==", "dev": true, "bin": { "prettier": "bin-prettier.js" @@ -4328,12 +4331,12 @@ } }, "node_modules/proc-log": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-2.0.0.tgz", - "integrity": "sha512-I/35MfCX2H8jBUhKN8JB8nmqvQo/nKdrBodBY7L3RhDSPPyvOHwLYNmPuhwuJq7a7C3vgFKWGQM+ecPStcvOHA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-2.0.1.tgz", + "integrity": "sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw==", "dev": true, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, "node_modules/progress": { @@ -5286,9 +5289,9 @@ } }, "node_modules/typescript": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.2.tgz", - "integrity": "sha512-HM/hFigTBHZhLXshn9sN37H085+hQGeJHJ/X7LpBWLID/fbc2acUMfU+lGD98X81sKP+pFa9f0DZmCwB9GnbAg==", + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.3.tgz", + "integrity": "sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -5445,12 +5448,15 @@ } }, "node_modules/validate-npm-package-name": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz", - "integrity": "sha1-X6kS2B630MdK/BQN5zF/DKffQ34=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-4.0.0.tgz", + "integrity": "sha512-mzR0L8ZDktZjpX4OB46KT+56MAhl4EIazWP/+G/HPGuvfdaqg4YsCdtOm6U9+LOFyYDoh4dpnpxZRB9MQQns5Q==", "dev": true, "dependencies": { - "builtins": "^1.0.3" + "builtins": "^5.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, "node_modules/web-streams-polyfill": { @@ -5796,12 +5802,12 @@ } }, "@npmcli/fs": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", - "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.0.tgz", + "integrity": "sha512-DmfBvNXGaetMxj9LTp8NAN9vEidXURrf5ZTslQzEAi/6GbW+4yjaLFQc6Tue5cpZ9Frlk4OBo/Snf1Bh/S7qTQ==", "dev": true, "requires": { - "@gar/promisify": "^1.0.1", + "@gar/promisify": "^1.1.3", "semver": "^7.3.5" } }, @@ -5823,9 +5829,9 @@ }, "dependencies": { "lru-cache": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.7.1.tgz", - "integrity": "sha512-cRffBiTW8s73eH4aTXqBcTLU0xQnwGV3/imttRHGWCrbergmnK4D6JXQd8qin5z43HnDwRI+o7mVW0LEB+tpAw==", + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.7.3.tgz", + "integrity": "sha512-WY9wjJNQt9+PZilnLbuFKM+SwDull9+6IAguOrarOMoOHTcJ9GnXSO11+Gw6c7xtDkBkthR57OZMtZKYr+1CEw==", "dev": true }, "mkdirp": { @@ -5952,15 +5958,15 @@ } }, "@types/json-schema": { - "version": "7.0.10", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.10.tgz", - "integrity": "sha512-BLO9bBq59vW3fxCpD4o0N4U+DXsvwvIcl+jofw0frQo/GrBFC+/jRZj1E7kgp6dvTyNmA4y6JCV5Id/r3mNP5A==", + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", "dev": true }, "@types/node": { - "version": "17.0.21", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.21.tgz", - "integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==", + "version": "17.0.23", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.23.tgz", + "integrity": "sha512-UxDxWn7dl97rKVeVS61vErvw086aCYhDLyvRQZ5Rk65rZKepaFdm53GeqXaKBuOhED4e9uWq34IC3TdSdJJ2Gw==", "dev": true }, "@types/node-fetch": { @@ -5973,14 +5979,14 @@ } }, "@typescript-eslint/eslint-plugin": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.15.0.tgz", - "integrity": "sha512-u6Db5JfF0Esn3tiAKELvoU5TpXVSkOpZ78cEGn/wXtT2RVqs2vkt4ge6N8cRCyw7YVKhmmLDbwI2pg92mlv7cA==", + "version": "5.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.17.0.tgz", + "integrity": "sha512-qVstvQilEd89HJk3qcbKt/zZrfBZ+9h2ynpAGlWjWiizA7m/MtLT9RoX6gjtpE500vfIg8jogAkDzdCxbsFASQ==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.15.0", - "@typescript-eslint/type-utils": "5.15.0", - "@typescript-eslint/utils": "5.15.0", + "@typescript-eslint/scope-manager": "5.17.0", + "@typescript-eslint/type-utils": "5.17.0", + "@typescript-eslint/utils": "5.17.0", "debug": "^4.3.2", "functional-red-black-tree": "^1.0.1", "ignore": "^5.1.8", @@ -5990,52 +5996,52 @@ } }, "@typescript-eslint/parser": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.15.0.tgz", - "integrity": "sha512-NGAYP/+RDM2sVfmKiKOCgJYPstAO40vPAgACoWPO/+yoYKSgAXIFaBKsV8P0Cc7fwKgvj27SjRNX4L7f4/jCKQ==", + "version": "5.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.17.0.tgz", + "integrity": "sha512-aRzW9Jg5Rlj2t2/crzhA2f23SIYFlF9mchGudyP0uiD6SenIxzKoLjwzHbafgHn39dNV/TV7xwQkLfFTZlJ4ig==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.15.0", - "@typescript-eslint/types": "5.15.0", - "@typescript-eslint/typescript-estree": "5.15.0", + "@typescript-eslint/scope-manager": "5.17.0", + "@typescript-eslint/types": "5.17.0", + "@typescript-eslint/typescript-estree": "5.17.0", "debug": "^4.3.2" } }, "@typescript-eslint/scope-manager": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.15.0.tgz", - "integrity": "sha512-EFiZcSKrHh4kWk0pZaa+YNJosvKE50EnmN4IfgjkA3bTHElPtYcd2U37QQkNTqwMCS7LXeDeZzEqnsOH8chjSg==", + "version": "5.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.17.0.tgz", + "integrity": "sha512-062iCYQF/doQ9T2WWfJohQKKN1zmmXVfAcS3xaiialiw8ZUGy05Em6QVNYJGO34/sU1a7a+90U3dUNfqUDHr3w==", "dev": true, "requires": { - "@typescript-eslint/types": "5.15.0", - "@typescript-eslint/visitor-keys": "5.15.0" + "@typescript-eslint/types": "5.17.0", + "@typescript-eslint/visitor-keys": "5.17.0" } }, "@typescript-eslint/type-utils": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.15.0.tgz", - "integrity": "sha512-KGeDoEQ7gHieLydujGEFLyLofipe9PIzfvA/41urz4hv+xVxPEbmMQonKSynZ0Ks2xDhJQ4VYjB3DnRiywvKDA==", + "version": "5.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.17.0.tgz", + "integrity": "sha512-3hU0RynUIlEuqMJA7dragb0/75gZmwNwFf/QJokWzPehTZousP/MNifVSgjxNcDCkM5HI2K22TjQWUmmHUINSg==", "dev": true, "requires": { - "@typescript-eslint/utils": "5.15.0", + "@typescript-eslint/utils": "5.17.0", "debug": "^4.3.2", "tsutils": "^3.21.0" } }, "@typescript-eslint/types": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.15.0.tgz", - "integrity": "sha512-yEiTN4MDy23vvsIksrShjNwQl2vl6kJeG9YkVJXjXZnkJElzVK8nfPsWKYxcsGWG8GhurYXP4/KGj3aZAxbeOA==", + "version": "5.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.17.0.tgz", + "integrity": "sha512-AgQ4rWzmCxOZLioFEjlzOI3Ch8giDWx8aUDxyNw9iOeCvD3GEYAB7dxWGQy4T/rPVe8iPmu73jPHuaSqcjKvxw==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.15.0.tgz", - "integrity": "sha512-Hb0e3dGc35b75xLzixM3cSbG1sSbrTBQDfIScqdyvrfJZVEi4XWAT+UL/HMxEdrJNB8Yk28SKxPLtAhfCbBInA==", + "version": "5.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.17.0.tgz", + "integrity": "sha512-X1gtjEcmM7Je+qJRhq7ZAAaNXYhTgqMkR10euC4Si6PIjb+kwEQHSxGazXUQXFyqfEXdkGf6JijUu5R0uceQzg==", "dev": true, "requires": { - "@typescript-eslint/types": "5.15.0", - "@typescript-eslint/visitor-keys": "5.15.0", + "@typescript-eslint/types": "5.17.0", + "@typescript-eslint/visitor-keys": "5.17.0", "debug": "^4.3.2", "globby": "^11.0.4", "is-glob": "^4.0.3", @@ -6044,26 +6050,26 @@ } }, "@typescript-eslint/utils": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.15.0.tgz", - "integrity": "sha512-081rWu2IPKOgTOhHUk/QfxuFog8m4wxW43sXNOMSCdh578tGJ1PAaWPsj42LOa7pguh173tNlMigsbrHvh/mtA==", + "version": "5.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.17.0.tgz", + "integrity": "sha512-DVvndq1QoxQH+hFv+MUQHrrWZ7gQ5KcJzyjhzcqB1Y2Xes1UQQkTRPUfRpqhS8mhTWsSb2+iyvDW1Lef5DD7vA==", "dev": true, "requires": { "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.15.0", - "@typescript-eslint/types": "5.15.0", - "@typescript-eslint/typescript-estree": "5.15.0", + "@typescript-eslint/scope-manager": "5.17.0", + "@typescript-eslint/types": "5.17.0", + "@typescript-eslint/typescript-estree": "5.17.0", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0" } }, "@typescript-eslint/visitor-keys": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.15.0.tgz", - "integrity": "sha512-+vX5FKtgvyHbmIJdxMJ2jKm9z2BIlXJiuewI8dsDYMp5LzPUcuTT78Ya5iwvQg3VqSVdmxyM8Anj1Jeq7733ZQ==", + "version": "5.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.17.0.tgz", + "integrity": "sha512-6K/zlc4OfCagUu7Am/BD5k8PSWQOgh34Nrv9Rxe2tBzlJ7uOeJ/h7ugCGDCeEZHT6k2CJBhbk9IsbkPI0uvUkA==", "dev": true, "requires": { - "@typescript-eslint/types": "5.15.0", + "@typescript-eslint/types": "5.17.0", "eslint-visitor-keys": "^3.0.0" } }, @@ -6302,24 +6308,27 @@ "dev": true }, "builtins": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", - "integrity": "sha1-y5T662HIaWRR2zZTThQi+U8K7og=", - "dev": true + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.0.tgz", + "integrity": "sha512-aizhtbxgT1Udg0Fj6GssXshAVK+nxbtCV+1OtTrMNy67jffDFBY6CUBAkhO4owbleAx6fdbnWdpsmmcXydbzNw==", + "dev": true, + "requires": { + "semver": "^7.0.0" + } }, "cacache": { - "version": "16.0.2", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.0.2.tgz", - "integrity": "sha512-Q17j7s8X81i/QYVrKVQ/qwWGT+pYLfpTcZ+X+p/Qw9FULy9JEfb2FECYTTt6mPV6A/vk92nRZ80ncpKxiGTrIA==", + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.0.3.tgz", + "integrity": "sha512-eC7wYodNCVb97kuHGk5P+xZsvUJHkhSEOyNwkenqQPAsOtrTjvWOE5vSPNBpz9d8X3acIf6w2Ub5s4rvOCTs4g==", "dev": true, "requires": { - "@npmcli/fs": "^1.0.0", + "@npmcli/fs": "^2.1.0", "@npmcli/move-file": "^1.1.2", "chownr": "^2.0.0", "fs-minipass": "^2.1.0", "glob": "^7.2.0", "infer-owner": "^1.0.4", - "lru-cache": "^7.5.1", + "lru-cache": "^7.7.1", "minipass": "^3.1.6", "minipass-collect": "^1.0.2", "minipass-flush": "^1.0.5", @@ -6334,9 +6343,9 @@ }, "dependencies": { "lru-cache": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.7.1.tgz", - "integrity": "sha512-cRffBiTW8s73eH4aTXqBcTLU0xQnwGV3/imttRHGWCrbergmnK4D6JXQd8qin5z43HnDwRI+o7mVW0LEB+tpAw==", + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.7.3.tgz", + "integrity": "sha512-WY9wjJNQt9+PZilnLbuFKM+SwDull9+6IAguOrarOMoOHTcJ9GnXSO11+Gw6c7xtDkBkthR57OZMtZKYr+1CEw==", "dev": true }, "mkdirp": { @@ -6784,9 +6793,9 @@ "dev": true }, "es-abstract": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", - "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.2.tgz", + "integrity": "sha512-gfSBJoZdlL2xRiOCy0g8gLMryhoe1TlimjzU99L/31Z8QEGIhVQI+EWwt5lT+AuU9SnorVupXFqqOGqGfsyO6w==", "dev": true, "requires": { "call-bind": "^1.0.2", @@ -6795,15 +6804,15 @@ "get-intrinsic": "^1.1.1", "get-symbol-description": "^1.0.0", "has": "^1.0.3", - "has-symbols": "^1.0.2", + "has-symbols": "^1.0.3", "internal-slot": "^1.0.3", "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.1", + "is-negative-zero": "^2.0.2", "is-regex": "^1.1.4", "is-shared-array-buffer": "^1.0.1", "is-string": "^1.0.7", - "is-weakref": "^1.0.1", - "object-inspect": "^1.11.0", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.0", "object-keys": "^1.1.1", "object.assign": "^4.1.2", "string.prototype.trimend": "^1.0.4", @@ -6851,9 +6860,9 @@ "dev": true }, "eslint": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.11.0.tgz", - "integrity": "sha512-/KRpd9mIRg2raGxHRGwW9ZywYNAClZrHjdueHcrVDuO3a6bj83eoTirCCk0M0yPwOjWYKHwRVRid+xK4F/GHgA==", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.12.0.tgz", + "integrity": "sha512-it1oBL9alZg1S8UycLm5YDMAkIhtH6FtAzuZs6YvoGVldWjbS08BkAdb/ymP9LlAyq8koANu32U7Ib/w+UNh8Q==", "dev": true, "requires": { "@eslint/eslintrc": "^1.2.1", @@ -7262,9 +7271,9 @@ "dev": true }, "gauge": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.3.tgz", - "integrity": "sha512-ICw1DhAwMtb22rYFwEHgJcx1JCwJGv3x6G0OQUq56Nge+H4Q8JEwr8iveS0XFlsUNSI67F5ffMGK25bK4Pmskw==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", "dev": true, "requires": { "aproba": "^1.0.3 || ^2.0.0", @@ -7940,13 +7949,10 @@ "dev": true }, "json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "dev": true }, "jsonfile": { "version": "6.1.0", @@ -8120,18 +8126,18 @@ "dev": true }, "make-fetch-happen": { - "version": "10.0.6", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.0.6.tgz", - "integrity": "sha512-4Gfh6lV3TLXmj7qz79hBFuvVqjYSMW6v2+sxtdX4LFQU0rK3V/txRjE0DoZb7X0IF3t9f8NO3CxPSWlvdckhVA==", + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.1.1.tgz", + "integrity": "sha512-3/mCljDQNjmrP7kl0vhS5WVlV+TvSKoZaFhdiYV7MOijEnrhrjaVnqbp/EY/7S+fhUB2KpH7j8c1iRsIOs+kjw==", "dev": true, "requires": { "agentkeepalive": "^4.2.1", - "cacache": "^16.0.0", + "cacache": "^16.0.2", "http-cache-semantics": "^4.1.0", "http-proxy-agent": "^5.0.0", "https-proxy-agent": "^5.0.0", "is-lambda": "^1.0.1", - "lru-cache": "^7.5.1", + "lru-cache": "^7.7.1", "minipass": "^3.1.6", "minipass-collect": "^1.0.2", "minipass-fetch": "^2.0.3", @@ -8144,9 +8150,9 @@ }, "dependencies": { "lru-cache": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.7.1.tgz", - "integrity": "sha512-cRffBiTW8s73eH4aTXqBcTLU0xQnwGV3/imttRHGWCrbergmnK4D6JXQd8qin5z43HnDwRI+o7mVW0LEB+tpAw==", + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.7.3.tgz", + "integrity": "sha512-WY9wjJNQt9+PZilnLbuFKM+SwDull9+6IAguOrarOMoOHTcJ9GnXSO11+Gw6c7xtDkBkthR57OZMtZKYr+1CEw==", "dev": true } } @@ -8164,13 +8170,13 @@ "dev": true }, "micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "dev": true, "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" + "braces": "^3.0.2", + "picomatch": "^2.3.1" } }, "mimic-response": { @@ -8189,9 +8195,9 @@ } }, "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", "dev": true }, "minipass": { @@ -8213,9 +8219,9 @@ } }, "minipass-fetch": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.0.3.tgz", - "integrity": "sha512-VA+eiiUtaIvpQJXISwE3OiMvQwAWrgKb97F0aXlCS1Ahikr8fEQq8m3Hf7Kv9KT3nokuHigJKsDMB6atU04olQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.0.tgz", + "integrity": "sha512-H9U4UVBGXEyyWJnqYDCLp1PwD8XIkJ4akNHp1aGVI+2Ym7wQMlxDKi4IB4JbmyU+pl9pEs/cVrK6cOuvmbK4Sg==", "dev": true, "requires": { "encoding": "^0.1.13", @@ -8272,12 +8278,12 @@ } }, "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, "requires": { - "minimist": "^1.2.5" + "minimist": "^1.2.6" } }, "ms": { @@ -8440,9 +8446,9 @@ } }, "lru-cache": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.7.1.tgz", - "integrity": "sha512-cRffBiTW8s73eH4aTXqBcTLU0xQnwGV3/imttRHGWCrbergmnK4D6JXQd8qin5z43HnDwRI+o7mVW0LEB+tpAw==", + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.7.3.tgz", + "integrity": "sha512-WY9wjJNQt9+PZilnLbuFKM+SwDull9+6IAguOrarOMoOHTcJ9GnXSO11+Gw6c7xtDkBkthR57OZMtZKYr+1CEw==", "dev": true } } @@ -8547,14 +8553,14 @@ "dev": true }, "npm-package-arg": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-9.0.1.tgz", - "integrity": "sha512-Xs9wznfEAmZAR61qsYH3iN24V/qMYYkvAR5CRQNMvC6PjN2fHtO8y9XP/xdp5K+Icx+u1wMBMgWRPCmAEChSog==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-9.0.2.tgz", + "integrity": "sha512-v/miORuX8cndiOheW8p2moNuPJ7QhcFh9WGlTorruG8hXSA23vMTEp5hTCmDxic0nD8KHhj/NQgFuySD3GYY3g==", "dev": true, "requires": { "hosted-git-info": "^5.0.0", "semver": "^7.3.5", - "validate-npm-package-name": "^3.0.0" + "validate-npm-package-name": "^4.0.0" }, "dependencies": { "hosted-git-info": { @@ -8567,9 +8573,9 @@ } }, "lru-cache": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.7.1.tgz", - "integrity": "sha512-cRffBiTW8s73eH4aTXqBcTLU0xQnwGV3/imttRHGWCrbergmnK4D6JXQd8qin5z43HnDwRI+o7mVW0LEB+tpAw==", + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.7.3.tgz", + "integrity": "sha512-WY9wjJNQt9+PZilnLbuFKM+SwDull9+6IAguOrarOMoOHTcJ9GnXSO11+Gw6c7xtDkBkthR57OZMtZKYr+1CEw==", "dev": true } } @@ -8599,17 +8605,17 @@ } }, "npm-registry-fetch": { - "version": "13.0.1", - "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-13.0.1.tgz", - "integrity": "sha512-Ak+LXVtSrCLOdscFW/apUw67OPNph8waHsPKM9UOJosL7i59EF5XoSWQMEsXEOeifM9Bb4/2+WrQC4t/pd8DGg==", + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-13.1.0.tgz", + "integrity": "sha512-TIYL5X8CcwDhbFMXFDShNcpG6OMCYK6VzvSr6MUWP20tCU2DJ4ao2qQg3DT+3Pet8mO6/cgbZpon4LMh3duYLg==", "dev": true, "requires": { - "make-fetch-happen": "^10.0.3", + "make-fetch-happen": "^10.0.6", "minipass": "^3.1.6", - "minipass-fetch": "^2.0.1", + "minipass-fetch": "^2.0.3", "minipass-json-stream": "^1.0.1", "minizlib": "^2.1.2", - "npm-package-arg": "^9.0.0", + "npm-package-arg": "^9.0.1", "proc-log": "^2.0.0" } }, @@ -8872,9 +8878,9 @@ "dev": true }, "prettier": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.6.0.tgz", - "integrity": "sha512-m2FgJibYrBGGgQXNzfd0PuDGShJgRavjUoRCw1mZERIWVSXF0iLzLm+aOqTAbLnC3n6JzUhAA8uZnFVghHJ86A==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.6.1.tgz", + "integrity": "sha512-8UVbTBYGwN37Bs9LERmxCPjdvPxlEowx2urIL6urHzdb3SDq4B/Z6xLFCblrSnE4iKWcS6ziJ3aOYrc1kz/E2A==", "dev": true }, "prettier-linter-helpers": { @@ -8887,9 +8893,9 @@ } }, "proc-log": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-2.0.0.tgz", - "integrity": "sha512-I/35MfCX2H8jBUhKN8JB8nmqvQo/nKdrBodBY7L3RhDSPPyvOHwLYNmPuhwuJq7a7C3vgFKWGQM+ecPStcvOHA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-2.0.1.tgz", + "integrity": "sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw==", "dev": true }, "progress": { @@ -9598,9 +9604,9 @@ } }, "typescript": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.2.tgz", - "integrity": "sha512-HM/hFigTBHZhLXshn9sN37H085+hQGeJHJ/X7LpBWLID/fbc2acUMfU+lGD98X81sKP+pFa9f0DZmCwB9GnbAg==", + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.3.tgz", + "integrity": "sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==", "dev": true }, "typescript-axios-wb": { @@ -9729,12 +9735,12 @@ } }, "validate-npm-package-name": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz", - "integrity": "sha1-X6kS2B630MdK/BQN5zF/DKffQ34=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-4.0.0.tgz", + "integrity": "sha512-mzR0L8ZDktZjpX4OB46KT+56MAhl4EIazWP/+G/HPGuvfdaqg4YsCdtOm6U9+LOFyYDoh4dpnpxZRB9MQQns5Q==", "dev": true, "requires": { - "builtins": "^1.0.3" + "builtins": "^5.0.0" } }, "web-streams-polyfill": { diff --git a/package.json b/package.json index 3af1b1e..b78ed2f 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "displayName": "Homebridge Rainbird", "name": "homebridge-rainbird", - "version": "1.6.4", + "version": "1.7.0", "description": "The [Homebridge](https://homebridge.io) Rainbird plugin allows you to access your [Rainbird](https://rainbird.com) device(s) from HomeKit.", "author": "donavanbecker", "license": "Apache-2.0", @@ -14,7 +14,7 @@ }, "engines": { "homebridge": "^1.4.0", - "node": "^14.19.0 || ^16.14.0" + "node": "^14.19.1 || ^16.14.2" }, "main": "dist/index.js", "scripts": { @@ -60,20 +60,20 @@ "devDependencies": { "@types/aes-js": "^3.1.1", "@types/better-queue": "^3.8.3", - "@types/node": "^17.0.21", + "@types/node": "^17.0.23", "@types/node-fetch": "^3.0.3", - "@typescript-eslint/eslint-plugin": "^5.15.0", - "@typescript-eslint/parser": "^5.15.0", - "eslint": "^8.11.0", + "@typescript-eslint/eslint-plugin": "^5.17.0", + "@typescript-eslint/parser": "^5.17.0", + "eslint": "^8.12.0", "eslint-config-prettier": "8.5.0", "eslint-plugin-prettier": "4.0.0", "homebridge": "^1.4.0", "nodemon": "^2.0.15", "rimraf": "^3.0.2", "ts-node": "^10.7.0", - "typescript": "^4.6.2", + "typescript": "^4.6.3", "typescript-axios-wb": "^1.0.3", "npm-check-updates": "^12.5.4", - "prettier": "2.6.0" + "prettier": "2.6.1" } } diff --git a/src/RainBird/RainBirdService.ts b/src/RainBird/RainBirdService.ts index 009c7ab..10bed89 100644 --- a/src/RainBird/RainBirdService.ts +++ b/src/RainBird/RainBirdService.ts @@ -63,6 +63,7 @@ export class RainBirdService extends events.EventEmitter { showRequestResponse: boolean, }) { super(); + this.setMaxListeners(50); this.log = options.log; this._client = new RainBirdClient(options.address, options.password, options.log, options.showRequestResponse); diff --git a/src/devices/ContactSensor.ts b/src/devices/ContactSensor.ts index ad012ea..c9ae20f 100644 --- a/src/devices/ContactSensor.ts +++ b/src/devices/ContactSensor.ts @@ -3,39 +3,26 @@ import { RainbirdPlatform } from '../platform'; import { RainBirdService } from '../RainBird/RainBirdService'; import { fromEvent } from 'rxjs'; import { DevicesConfig } from '../settings'; +import { DeviceBase } from './DeviceBase'; /** * Platform Accessory * An instance of this class is created for each accessory your platform registers * Each accessory may expose multiple services of different service types. */ -export class ContactSensor { +export class ContactSensor extends DeviceBase { private contactSensor!: { service: Service; state: CharacteristicValue; }; - // Config - deviceRefreshRate!: number; - deviceLogging!: string; - constructor( - private readonly platform: RainbirdPlatform, - private accessory: PlatformAccessory, - public device: DevicesConfig, - public rainbird: RainBirdService, + readonly platform: RainbirdPlatform, + accessory: PlatformAccessory, + device: DevicesConfig, + rainbird: RainBirdService, ) { - this.logs(device); - this.refreshRate(device); - // Set accessory information - accessory - .getService(this.platform.Service.AccessoryInformation)! - .setCharacteristic(this.platform.Characteristic.Manufacturer, 'RainBird') - .setCharacteristic(this.platform.Characteristic.Model, accessory.context.model ?? rainbird!.model) - .setCharacteristic(this.platform.Characteristic.SerialNumber, accessory.context.deviceID ?? rainbird!.serialNumber) - .setCharacteristic(this.platform.Characteristic.FirmwareRevision, accessory.context.FirmwareRevision ?? rainbird!.version) - .getCharacteristic(this.platform.Characteristic.FirmwareRevision) - .updateValue(accessory.context.FirmwareRevision); + super(platform, accessory, device, rainbird); // Contact Sensor Service const name = `Zone ${accessory.context.zoneId}`; @@ -76,7 +63,7 @@ export class ContactSensor { this.contactSensor.state = this.rainbird!.isInUse(this.accessory.context.zoneId) ? this.platform.Characteristic.ContactSensorState.CONTACT_NOT_DETECTED : this.platform.Characteristic.ContactSensorState.CONTACT_DETECTED; - this.debugLog(`Contact Sensor: ${this.accessory.context.zoneId}, ContactSensorState: ${this.contactSensor.state}`); + this.debugLog(`${this.constructor.name}: ${this.accessory.displayName}, ContactSensorState: ${this.contactSensor.state}`); } /** @@ -85,71 +72,12 @@ export class ContactSensor { updateHomeKitCharacteristics() { // Valves if (this.contactSensor.state === undefined) { - this.debugLog(`Contact Sensor ${this.accessory.displayName} ContactSensorState: ${this.contactSensor.state}, ${this.accessory.context.zoneId}`); + this.debugLog( + `${this.constructor.name} ${this.accessory.displayName} ContactSensorState: ${this.contactSensor.state}, ${this.accessory.context.zoneId}`); } else { this.contactSensor.service.updateCharacteristic(this.platform.Characteristic.ContactSensorState, this.contactSensor.state); - this.debugLog(`Contact Sensor ${this.accessory.displayName} ContactSensorState: ${this.contactSensor.state}, ${this.accessory.context.zoneId}`); - } - } - - refreshRate(device: DevicesConfig) { - if (device.refreshRate) { - this.deviceRefreshRate = this.accessory.context.refreshRate = device.refreshRate; - this.debugLog(`Thermostat: ${this.accessory.displayName} Using Device Config refreshRate: ${this.deviceRefreshRate}`); - } else if (this.platform.config.options!.refreshRate) { - this.deviceRefreshRate = this.accessory.context.refreshRate = this.platform.config.options!.refreshRate; - this.debugLog(`Thermostat: ${this.accessory.displayName} Using Platform Config refreshRate: ${this.deviceRefreshRate}`); - } - } - - logs(device: DevicesConfig) { - if (this.platform.debugMode) { - this.deviceLogging = this.accessory.context.logging = 'debugMode'; - this.debugLog(`Thermostat: ${this.accessory.displayName} Using Debug Mode Logging: ${this.deviceLogging}`); - } else if (device.logging) { - this.deviceLogging = this.accessory.context.logging = device.logging; - this.debugLog(`Thermostat: ${this.accessory.displayName} Using Device Config Logging: ${this.deviceLogging}`); - } else if (this.platform.config.options?.logging) { - this.deviceLogging = this.accessory.context.logging = this.platform.config.options?.logging; - this.debugLog(`Thermostat: ${this.accessory.displayName} Using Platform Config Logging: ${this.deviceLogging}`); - } else { - this.deviceLogging = this.accessory.context.logging = 'standard'; - this.debugLog(`Thermostat: ${this.accessory.displayName} Logging Not Set, Using: ${this.deviceLogging}`); - } - } - - /** - * Logging for Device - */ - infoLog(...log: any[]) { - if (this.enablingDeviceLogging()) { - this.platform.log.info(String(...log)); - } - } - - warnLog(...log: any[]) { - if (this.enablingDeviceLogging()) { - this.platform.log.warn(String(...log)); - } - } - - errorLog(...log: any[]) { - if (this.enablingDeviceLogging()) { - this.platform.log.error(String(...log)); - } - } - - debugLog(...log: any[]) { - if (this.enablingDeviceLogging()) { - if (this.deviceLogging === 'debug') { - this.platform.log.info('[DEBUG]', String(...log)); - } else { - this.platform.log.debug(String(...log)); - } + this.debugLog( + `${this.constructor.name} ${this.accessory.displayName} ContactSensorState: ${this.contactSensor.state}, ${this.accessory.context.zoneId}`); } } - - enablingDeviceLogging(): boolean { - return this.deviceLogging.includes('debug') || this.deviceLogging === 'standard'; - } } diff --git a/src/devices/DeviceBase.ts b/src/devices/DeviceBase.ts new file mode 100644 index 0000000..eeaa0e6 --- /dev/null +++ b/src/devices/DeviceBase.ts @@ -0,0 +1,92 @@ +import { PlatformAccessory } from 'homebridge'; +import { RainbirdPlatform } from '../platform'; +import { RainBirdService } from '../RainBird/RainBirdService'; +import { DevicesConfig } from '../settings'; + +export abstract class DeviceBase { + + // Config + protected deviceLogging!: string; + protected deviceRefreshRate!: number; + + constructor( + protected readonly platform: RainbirdPlatform, + protected accessory: PlatformAccessory, + protected device: DevicesConfig, + protected rainbird: RainBirdService, + ) { + this.logs(device); + this.refreshRate(device); + + // Set accessory information + accessory + .getService(this.platform.Service.AccessoryInformation)! + .setCharacteristic(this.platform.Characteristic.Manufacturer, 'RainBird') + .setCharacteristic(this.platform.Characteristic.Model, accessory.context.model ?? rainbird!.model) + .setCharacteristic(this.platform.Characteristic.SerialNumber, accessory.context.deviceID ?? rainbird!.serialNumber) + .setCharacteristic(this.platform.Characteristic.FirmwareRevision, accessory.context.FirmwareRevision ?? rainbird!.version) + .getCharacteristic(this.platform.Characteristic.FirmwareRevision) + .updateValue(accessory.context.FirmwareRevision); + } + + logs(device: DevicesConfig) { + if (this.platform.debugMode) { + this.deviceLogging = this.accessory.context.logging = 'debugMode'; + this.debugLog(`${this.constructor.name}: ${this.accessory.displayName} Using Debug Mode Logging: ${this.deviceLogging}`); + } else if (device.logging) { + this.deviceLogging = this.accessory.context.logging = device.logging; + this.debugLog(`${this.constructor.name}: ${this.accessory.displayName} Using Device Config Logging: ${this.deviceLogging}`); + } else if (this.platform.config.options?.logging) { + this.deviceLogging = this.accessory.context.logging = this.platform.config.options?.logging; + this.debugLog(`${this.constructor.name}: ${this.accessory.displayName} Using Platform Config Logging: ${this.deviceLogging}`); + } else { + this.deviceLogging = this.accessory.context.logging = 'standard'; + this.debugLog(`${this.constructor.name}: ${this.accessory.displayName} Logging Not Set, Using: ${this.deviceLogging}`); + } + } + + refreshRate(device: DevicesConfig) { + if (device.refreshRate) { + this.deviceRefreshRate = this.accessory.context.refreshRate = device.refreshRate; + this.debugLog(`${this.constructor.name}: ${this.accessory.displayName} Using Device Config refreshRate: ${this.deviceRefreshRate}`); + } else if (this.platform.config.options!.refreshRate) { + this.deviceRefreshRate = this.accessory.context.refreshRate = this.platform.config.options!.refreshRate; + this.debugLog(`${this.constructor.name}: ${this.accessory.displayName} Using Platform Config refreshRate: ${this.deviceRefreshRate}`); + } + } + + /** + * Logging for Device + */ + infoLog(...log: any[]) { + if (this.enablingDeviceLogging()) { + this.platform.log.info(String(...log)); + } + } + + warnLog(...log: any[]) { + if (this.enablingDeviceLogging()) { + this.platform.log.warn(String(...log)); + } + } + + errorLog(...log: any[]) { + if (this.enablingDeviceLogging()) { + this.platform.log.error(String(...log)); + } + } + + debugLog(...log: any[]) { + if (this.enablingDeviceLogging()) { + if (this.deviceLogging === 'debug') { + this.platform.log.info('[DEBUG]', String(...log)); + } else { + this.platform.log.debug(String(...log)); + } + } + } + + enablingDeviceLogging(): boolean { + return this.deviceLogging.includes('debug') || this.deviceLogging === 'standard'; + } +} \ No newline at end of file diff --git a/src/devices/IrrigationSystem.ts b/src/devices/IrrigationSystem.ts index a782c3b..f229f5d 100644 --- a/src/devices/IrrigationSystem.ts +++ b/src/devices/IrrigationSystem.ts @@ -4,13 +4,14 @@ import { RainBirdService } from '../RainBird/RainBirdService'; import { Subject, fromEvent, interval } from 'rxjs'; import { debounceTime, skipWhile, tap } from 'rxjs/operators'; import { DevicesConfig } from '../settings'; +import { DeviceBase } from './DeviceBase'; /** * Platform Accessory * An instance of this class is created for each accessory your platform registers * Each accessory may expose multiple services of different service types. */ -export class IrrigationSystem { +export class IrrigationSystem extends DeviceBase { private irrigation!: { service: Service; Active: CharacteristicValue; @@ -23,28 +24,22 @@ export class IrrigationSystem { service: Service; Active: CharacteristicValue; InUse: CharacteristicValue; - SetDuration: number; - IsConfigured: CharacteristicValue; } > = new Map(); - // Config - deviceRefreshRate!: number; - deviceLogging!: string; - // Irrigation System Updates private irrigationSystemUpdateInProgress!: boolean; private doIrrigationSystemUpdate: Subject; constructor( - private readonly platform: RainbirdPlatform, - private accessory: PlatformAccessory, - public device: DevicesConfig, - public rainbird: RainBirdService, + readonly platform: RainbirdPlatform, + accessory: PlatformAccessory, + device: DevicesConfig, + rainbird: RainBirdService, ) { - this.logs(device); - this.refreshRate(device); + super(platform, accessory, device, rainbird); this.config(device); + // this is subject we use to track when we need to send changes to Rainbird Client this.doIrrigationSystemUpdate = new Subject(); this.irrigationSystemUpdateInProgress = false; @@ -56,16 +51,6 @@ export class IrrigationSystem { accessory.context.duration = {}; } - // Set accessory information - accessory - .getService(this.platform.Service.AccessoryInformation)! - .setCharacteristic(this.platform.Characteristic.Manufacturer, 'RainBird') - .setCharacteristic(this.platform.Characteristic.Model, accessory.context.model ?? rainbird!.model) - .setCharacteristic(this.platform.Characteristic.SerialNumber, accessory.context.deviceID ?? rainbird!.serialNumber) - .setCharacteristic(this.platform.Characteristic.FirmwareRevision, accessory.context.FirmwareRevision ?? rainbird!.version) - .getCharacteristic(this.platform.Characteristic.FirmwareRevision) - .updateValue(accessory.context.FirmwareRevision); - // Irrigation Service this.debugLog('Configure Irrigation Service'); this.irrigation = { @@ -114,12 +99,18 @@ export class IrrigationSystem { for (const zone of rainbird!.zones) { const name = `Zone ${zone}`; this.debugLog(`Load Valve Service for ${name}`); + + if (this.accessory.context.configured[zone] === undefined) { + this.accessory.context.configured[zone] = this.platform.Characteristic.IsConfigured.CONFIGURED; + } + if (this.accessory.context.duration[zone] === undefined) { + this.accessory.context.duration[zone] = 300; + } + this.valves.set(zone, { service: this.accessory.getService(name) ?? this.accessory.addService(this.platform.Service.Valve, name, zone), Active: this.platform.Characteristic.Active.INACTIVE as CharacteristicValue, InUse: this.platform.Characteristic.InUse.NOT_IN_USE as CharacteristicValue, - SetDuration: this.accessory.context.duration[zone] ?? 300, - IsConfigured: this.accessory.context.configured[zone] ?? this.platform.Characteristic.IsConfigured.CONFIGURED, }); // Add Valve Service's Characteristics @@ -129,9 +120,9 @@ export class IrrigationSystem { .setCharacteristic(this.platform.Characteristic.Active, this.valves.get(zone)!.Active) .setCharacteristic(this.platform.Characteristic.InUse, this.valves.get(zone)!.InUse) .setCharacteristic(this.platform.Characteristic.ValveType, this.platform.Characteristic.ValveType.IRRIGATION) - .setCharacteristic(this.platform.Characteristic.SetDuration, this.valves.get(zone)!.SetDuration) + .setCharacteristic(this.platform.Characteristic.SetDuration, this.accessory.context.duration[zone]) .setCharacteristic(this.platform.Characteristic.RemainingDuration, 0) - .setCharacteristic(this.platform.Characteristic.IsConfigured, this.valves.get(zone)!.IsConfigured) + .setCharacteristic(this.platform.Characteristic.IsConfigured, this.accessory.context.configured[zone]) .setCharacteristic(this.platform.Characteristic.ServiceLabelIndex, zone) .setCharacteristic(this.platform.Characteristic.StatusFault, this.platform.Characteristic.StatusFault.NO_FAULT); @@ -183,7 +174,7 @@ export class IrrigationSystem { .get(zone)! .service.getCharacteristic(this.platform.Characteristic.SetDuration) .onGet(() => { - return Number(this.valves.get(zone)!.SetDuration); + return Number(this.accessory.context.duration[zone]); }) .onSet(this.setValveSetDuration.bind(this, zone)); @@ -226,9 +217,9 @@ export class IrrigationSystem { try { await this.pushChanges(zone); } catch (e: any) { - this.debugLog(`Irrigation System ${this.accessory.displayName} - ${JSON.stringify(e.messsage)}`); + this.debugLog(`${this.constructor.name} ${this.accessory.displayName} - ${JSON.stringify(e.messsage)}`); if (this.deviceLogging.includes('debug')) { - this.debugLog(`Irrigation System ${this.accessory.displayName} - ${JSON.stringify(e)}`); + this.debugLog(`${this.constructor.name} ${this.accessory.displayName} - ${JSON.stringify(e)}`); } } this.irrigationSystemUpdateInProgress = false; @@ -243,7 +234,7 @@ export class IrrigationSystem { this.irrigation.Active = this.rainbird!.isActive() ? this.platform.Characteristic.Active.ACTIVE : this.platform.Characteristic.Active.INACTIVE; this.irrigation.InUse = this.rainbird!.isInUse() ? this.platform.Characteristic.InUse.IN_USE : this.platform.Characteristic.InUse.NOT_IN_USE; - this.debugLog(`Irrigation System: ${this.accessory.displayName}, Active: ${this.irrigation.Active}, InUse: ${this.irrigation.InUse}`); + this.debugLog(`${this.constructor.name}: ${this.accessory.displayName}, Active: ${this.irrigation.Active}, InUse: ${this.irrigation.InUse}`); // Valves for (const [zone, valve] of this.valves.entries()) { @@ -251,7 +242,7 @@ export class IrrigationSystem { valve.InUse = this.rainbird!.isInUse(zone) ? this.platform.Characteristic.InUse.IN_USE : this.platform.Characteristic.InUse.NOT_IN_USE; - this.debugLog(`Valve: ${zone}, Active: ${valve.Active}, InUse: ${valve.InUse}`); + this.debugLog(`${this.constructor.name} Valve: ${zone}, Active: ${valve.Active}, InUse: ${valve.InUse}`); } } @@ -261,55 +252,56 @@ export class IrrigationSystem { updateHomeKitCharacteristics() { // Irrigation System if (this.irrigation.Active === undefined) { - this.debugLog(`Irrigation ${this.accessory.displayName} Active: ${this.irrigation.Active}`); + this.debugLog(`${this.constructor.name} ${this.accessory.displayName} Active: ${this.irrigation.Active}`); } else { this.irrigation.service.updateCharacteristic(this.platform.Characteristic.Active, this.irrigation.Active); - this.debugLog(`Irrigation ${this.accessory.displayName} updateCharacteristic Active: ${this.irrigation.Active}`); + this.debugLog(`${this.constructor.name} ${this.accessory.displayName} updateCharacteristic Active: ${this.irrigation.Active}`); } if (this.irrigation.InUse === undefined) { - this.debugLog(`Irrigation ${this.accessory.displayName} InUse: ${this.irrigation.InUse}`); + this.debugLog(`${this.constructor.name} ${this.accessory.displayName} InUse: ${this.irrigation.InUse}`); } else { this.irrigation.service.updateCharacteristic(this.platform.Characteristic.InUse, this.irrigation.InUse); - this.debugLog(`Irrigation ${this.accessory.displayName} updateCharacteristic InUse: ${this.irrigation.InUse}`); + this.debugLog(`${this.constructor.name} ${this.accessory.displayName} updateCharacteristic InUse: ${this.irrigation.InUse}`); } if (this.rainbird!.RemainingDuration() === undefined) { - this.debugLog(`Irrigation ${this.accessory.displayName} RemainingDuration: ${this.rainbird!.RemainingDuration()}`); + this.debugLog(`${this.constructor.name} ${this.accessory.displayName} RemainingDuration: ${this.rainbird!.RemainingDuration()}`); } else { this.irrigation.service.updateCharacteristic(this.platform.Characteristic.RemainingDuration, this.rainbird!.RemainingDuration()); - this.debugLog(`Irrigation ${this.accessory.displayName} updateCharacteristic RemainingDuration: ${this.rainbird!.RemainingDuration()}`); + this.debugLog( + `${this.constructor.name} ${this.accessory.displayName} updateCharacteristic RemainingDuration: ${this.rainbird!.RemainingDuration()}`); } // Valves for (const [zone, valve] of this.valves.entries()) { if (valve.Active === undefined) { - this.debugLog(`Valve ${this.accessory.displayName} Active: ${valve.Active}`); + this.debugLog(`${this.constructor.name} Valve ${zone} Active: ${valve.Active}`); } else { valve.service.updateCharacteristic(this.platform.Characteristic.Active, valve.Active); - this.debugLog(`Valve ${this.accessory.displayName} updateCharacteristic Active: ${valve.Active}`); + this.debugLog(`${this.constructor.name} Valve ${zone} updateCharacteristic Active: ${valve.Active}`); } if (valve.InUse === undefined) { - this.debugLog(`Valve ${this.accessory.displayName} InUse: ${valve.InUse}`); + this.debugLog(`${this.constructor.name} Valve ${zone} InUse: ${valve.InUse}`); } else { valve.service.updateCharacteristic(this.platform.Characteristic.InUse, valve.InUse); - this.debugLog(`Valve ${this.accessory.displayName} updateCharacteristic InUse: ${valve.InUse}`); + this.debugLog(`${this.constructor.name} Valve ${zone} updateCharacteristic InUse: ${valve.InUse}`); } - if (valve.SetDuration === undefined) { - this.debugLog(`Valve ${this.accessory.displayName} SetDuration: ${valve.InUse}`); + if (this.accessory.context.duration[zone] === undefined) { + this.debugLog(`${this.constructor.name} Valve ${zone} SetDuration: ${this.accessory.context.duration[zone]}`); } else { - valve.service.updateCharacteristic(this.platform.Characteristic.SetDuration, valve.SetDuration); - this.debugLog(`Valve ${this.accessory.displayName} updateCharacteristic SetDuration: ${valve.SetDuration}`); + valve.service.updateCharacteristic(this.platform.Characteristic.SetDuration, this.accessory.context.duration[zone]); + this.debugLog(`${this.constructor.name} Valve ${zone} updateCharacteristic SetDuration: ${this.accessory.context.duration[zone]}`); } - if (valve.IsConfigured === undefined) { - this.debugLog(`Valve ${this.accessory.displayName} IsConfigured: ${valve.IsConfigured}`); + if (this.accessory.context.configured[zone] === undefined) { + this.debugLog(`${this.constructor.name} Valve ${zone} IsConfigured: ${this.accessory.context.configured[zone]}`); } else { - valve.service.updateCharacteristic(this.platform.Characteristic.IsConfigured, valve.IsConfigured); - this.debugLog(`Valve ${this.accessory.displayName} updateCharacteristic IsConfigured: ${valve.IsConfigured}`); + valve.service.updateCharacteristic(this.platform.Characteristic.IsConfigured, this.accessory.context.configured[zone]); + this.debugLog(`${this.constructor.name} Valve ${zone} updateCharacteristic IsConfigured: ${this.accessory.context.configured[zone]}`); } if (this.rainbird!.RemainingDuration(zone) === undefined) { - this.debugLog(`Valve ${this.accessory.displayName} RemainingDuration: ${this.rainbird!.RemainingDuration(zone)}`); + this.debugLog(`${this.constructor.name} Valve ${zone} RemainingDuration: ${this.rainbird!.RemainingDuration(zone)}`); } else { valve.service.updateCharacteristic(this.platform.Characteristic.RemainingDuration, this.rainbird!.RemainingDuration(zone)); - this.debugLog(`Valve ${this.accessory.displayName} updateCharacteristic RemainingDuration: ${this.rainbird!.RemainingDuration(zone)}`); + this.debugLog(`${this.constructor.name} Valve ${zone} updateCharacteristic RemainingDuration: ${this.rainbird!.RemainingDuration(zone)}`); } } } @@ -319,106 +311,43 @@ export class IrrigationSystem { */ async pushChanges(zone: number): Promise { if (this.valves.get(zone)!.Active === this.platform.Characteristic.Active.ACTIVE) { - this.rainbird!.activateZone(zone, this.valves.get(zone)!.SetDuration); + this.rainbird!.activateZone(zone, this.accessory.context.duration[zone]); } else { await this.rainbird!.deactivateZone(zone); } this.debugLog( - `Irrigation System ${this.accessory.displayName}, pushChanges: [Valve: ${zone},` + - ` Active: ${this.valves.get(zone)!.Active}, SetDuration: ${this.valves.get(zone)!.SetDuration}]`, + `${this.constructor.name} ${this.accessory.displayName}, pushChanges: [Valve: ${zone},` + + ` Active: ${this.valves.get(zone)!.Active}, SetDuration: ${this.accessory.context.duration[zone]}]`, ); } private setActive(value: CharacteristicValue) { - this.debugLog(`Irrigation System ${this.accessory.displayName}, Set Active: ${value}`); + this.debugLog(`${this.constructor.name} ${this.accessory.displayName}, Set Active: ${value}`); this.irrigation.Active = value; } private setValveActive(zone: number, value: CharacteristicValue) { - this.debugLog(`Irrigation System ${this.accessory.displayName}, Valve: ${zone}, Set Active: ${value}`); + this.debugLog(`${this.constructor.name} ${this.accessory.displayName}, Valve: ${zone}, Set Active: ${value}`); this.valves.get(zone)!.Active = value; this.doIrrigationSystemUpdate.next(zone); } private setValveIsConfigured(zone: number, value: CharacteristicValue) { - this.debugLog(`Irrigation System ${this.accessory.displayName}, Valve: ${zone}, Set IsConfigured: ${value}`); - this.valves.get(zone)!.IsConfigured = value; + this.debugLog(`${this.constructor.name} ${this.accessory.displayName}, Valve: ${zone}, Set IsConfigured: ${value}`); this.accessory.context.configured[zone] = value; this.rainbird!.enableZone(zone, value === this.platform.Characteristic.IsConfigured.CONFIGURED); } private setValveSetDuration(zone: number, value: CharacteristicValue) { - this.debugLog(`Irrigation System ${this.accessory.displayName}, Valve: ${zone}, Set SetDuration: ${value}`); - this.valves.get(zone)!.SetDuration = value as number; + this.debugLog(`${this.constructor.name} ${this.accessory.displayName}, Valve: ${zone}, Set SetDuration: ${value}`); this.accessory.context.duration[zone] = value; } config(device: DevicesConfig) { const config: DevicesConfig = device; if (Object.entries(config).length !== 0) { - this.warnLog(`Leak Sensor: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); - } - } - - refreshRate(device: DevicesConfig) { - if (device.refreshRate) { - this.deviceRefreshRate = this.accessory.context.refreshRate = device.refreshRate; - this.debugLog(`Thermostat: ${this.accessory.displayName} Using Device Config refreshRate: ${this.deviceRefreshRate}`); - } else if (this.platform.config.options!.refreshRate) { - this.deviceRefreshRate = this.accessory.context.refreshRate = this.platform.config.options!.refreshRate; - this.debugLog(`Thermostat: ${this.accessory.displayName} Using Platform Config refreshRate: ${this.deviceRefreshRate}`); - } - } - - logs(device: DevicesConfig) { - if (this.platform.debugMode) { - this.deviceLogging = this.accessory.context.logging = 'debugMode'; - this.debugLog(`Thermostat: ${this.accessory.displayName} Using Debug Mode Logging: ${this.deviceLogging}`); - } else if (device.logging) { - this.deviceLogging = this.accessory.context.logging = device.logging; - this.debugLog(`Thermostat: ${this.accessory.displayName} Using Device Config Logging: ${this.deviceLogging}`); - } else if (this.platform.config.options?.logging) { - this.deviceLogging = this.accessory.context.logging = this.platform.config.options?.logging; - this.debugLog(`Thermostat: ${this.accessory.displayName} Using Platform Config Logging: ${this.deviceLogging}`); - } else { - this.deviceLogging = this.accessory.context.logging = 'standard'; - this.debugLog(`Thermostat: ${this.accessory.displayName} Logging Not Set, Using: ${this.deviceLogging}`); - } - } - - /** - * Logging for Device - */ - infoLog(...log: any[]) { - if (this.enablingDeviceLogging()) { - this.platform.log.info(String(...log)); - } - } - - warnLog(...log: any[]) { - if (this.enablingDeviceLogging()) { - this.platform.log.warn(String(...log)); - } - } - - errorLog(...log: any[]) { - if (this.enablingDeviceLogging()) { - this.platform.log.error(String(...log)); - } - } - - debugLog(...log: any[]) { - if (this.enablingDeviceLogging()) { - if (this.deviceLogging === 'debug') { - this.platform.log.info('[DEBUG]', String(...log)); - } else { - this.platform.log.debug(String(...log)); - } + this.warnLog(`${this.constructor.name} ${this.accessory.displayName} Config: ${JSON.stringify(config)}`); } } - - enablingDeviceLogging(): boolean { - return this.deviceLogging.includes('debug') || this.deviceLogging === 'standard'; - } } diff --git a/src/devices/LeakSensor.ts b/src/devices/LeakSensor.ts index 243607e..535b667 100644 --- a/src/devices/LeakSensor.ts +++ b/src/devices/LeakSensor.ts @@ -3,38 +3,24 @@ import { RainbirdPlatform } from '../platform'; import { RainBirdService } from '../RainBird/RainBirdService'; import { fromEvent } from 'rxjs'; import { DevicesConfig } from '../settings'; +import { DeviceBase } from './DeviceBase'; -export class LeakSensor { +export class LeakSensor extends DeviceBase { private leakSensor!: { service: Service; LeakDetected: CharacteristicValue; }; - // Config - deviceRefreshRate!: number; - deviceLogging!: string; - constructor( - private readonly platform: RainbirdPlatform, - private accessory: PlatformAccessory, - public device: DevicesConfig, - public rainbird: RainBirdService, + readonly platform: RainbirdPlatform, + accessory: PlatformAccessory, + device: DevicesConfig, + rainbird: RainBirdService, ) { - this.logs(device); - this.refreshRate(device); + super(platform, accessory, device, rainbird); const model = 'WR2'; - // Set accessory information - accessory - .getService(this.platform.Service.AccessoryInformation)! - .setCharacteristic(this.platform.Characteristic.Manufacturer, 'RainBird') - .setCharacteristic(this.platform.Characteristic.Model, accessory.context.model ?? model) - .setCharacteristic(this.platform.Characteristic.SerialNumber, accessory.context.deviceID ?? rainbird!.serialNumber) - .setCharacteristic(this.platform.Characteristic.FirmwareRevision, accessory.context.FirmwareRevision ?? rainbird!.version) - .getCharacteristic(this.platform.Characteristic.FirmwareRevision) - .updateValue(accessory.context.FirmwareRevision); - // Leak Sensor Service this.debugLog('Configure Leak Sensor Service'); this.leakSensor = { @@ -74,71 +60,10 @@ export class LeakSensor { updateHomeKitCharacteristics() { if (this.leakSensor.LeakDetected === undefined) { - this.debugLog(`Leak Sensor ${this.accessory.displayName} LeakDetected: ${this.leakSensor.LeakDetected}`); + this.debugLog(`${this.constructor.name}: ${this.accessory.displayName} LeakDetected: ${this.leakSensor.LeakDetected}`); } else { this.leakSensor.service.updateCharacteristic(this.platform.Characteristic.LeakDetected, this.leakSensor.LeakDetected); - this.debugLog(`Leak Sensor ${this.accessory.displayName} updateCharacteristic LeakDetected: ${this.leakSensor.LeakDetected}`); - } - } - - refreshRate(device: DevicesConfig) { - if (device.refreshRate) { - this.deviceRefreshRate = this.accessory.context.refreshRate = device.refreshRate; - this.debugLog(`Thermostat: ${this.accessory.displayName} Using Device Config refreshRate: ${this.deviceRefreshRate}`); - } else if (this.platform.config.options!.refreshRate) { - this.deviceRefreshRate = this.accessory.context.refreshRate = this.platform.config.options!.refreshRate; - this.debugLog(`Thermostat: ${this.accessory.displayName} Using Platform Config refreshRate: ${this.deviceRefreshRate}`); - } - } - - logs(device: DevicesConfig) { - if (this.platform.debugMode) { - this.deviceLogging = this.accessory.context.logging = 'debugMode'; - this.debugLog(`Thermostat: ${this.accessory.displayName} Using Debug Mode Logging: ${this.deviceLogging}`); - } else if (device.logging) { - this.deviceLogging = this.accessory.context.logging = device.logging; - this.debugLog(`Thermostat: ${this.accessory.displayName} Using Device Config Logging: ${this.deviceLogging}`); - } else if (this.platform.config.options?.logging) { - this.deviceLogging = this.accessory.context.logging = this.platform.config.options?.logging; - this.debugLog(`Thermostat: ${this.accessory.displayName} Using Platform Config Logging: ${this.deviceLogging}`); - } else { - this.deviceLogging = this.accessory.context.logging = 'standard'; - this.debugLog(`Thermostat: ${this.accessory.displayName} Logging Not Set, Using: ${this.deviceLogging}`); - } - } - - /** - * Logging for Device - */ - infoLog(...log: any[]) { - if (this.enablingDeviceLogging()) { - this.platform.log.info(String(...log)); + this.debugLog(`${this.constructor.name}: ${this.accessory.displayName} updateCharacteristic LeakDetected: ${this.leakSensor.LeakDetected}`); } } - - warnLog(...log: any[]) { - if (this.enablingDeviceLogging()) { - this.platform.log.warn(String(...log)); - } - } - - errorLog(...log: any[]) { - if (this.enablingDeviceLogging()) { - this.platform.log.error(String(...log)); - } - } - - debugLog(...log: any[]) { - if (this.enablingDeviceLogging()) { - if (this.deviceLogging === 'debug') { - this.platform.log.info('[DEBUG]', String(...log)); - } else { - this.platform.log.debug(String(...log)); - } - } - } - - enablingDeviceLogging(): boolean { - return this.deviceLogging.includes('debug') || this.deviceLogging === 'standard'; - } } diff --git a/src/devices/ProgramSwitch.ts b/src/devices/ProgramSwitch.ts index 4803297..20e12e3 100644 --- a/src/devices/ProgramSwitch.ts +++ b/src/devices/ProgramSwitch.ts @@ -3,34 +3,21 @@ import { RainbirdPlatform } from '../platform'; import { RainBirdService } from '../RainBird/RainBirdService'; import { fromEvent } from 'rxjs'; import { DevicesConfig } from '../settings'; +import { DeviceBase } from './DeviceBase'; -export class ProgramSwitch { +export class ProgramSwitch extends DeviceBase { private programSwitch!: { service: Service; state: CharacteristicValue; }; - // Config - deviceRefreshRate!: number; - deviceLogging!: string; - constructor( - private readonly platform: RainbirdPlatform, - private accessory: PlatformAccessory, - public device: DevicesConfig, - public rainbird: RainBirdService, + readonly platform: RainbirdPlatform, + accessory: PlatformAccessory, + device: DevicesConfig, + rainbird: RainBirdService, ) { - this.logs(device); - this.refreshRate(device); - // Set accessory information - accessory - .getService(this.platform.Service.AccessoryInformation)! - .setCharacteristic(this.platform.Characteristic.Manufacturer, 'RainBird') - .setCharacteristic(this.platform.Characteristic.Model, accessory.context.model ?? rainbird!.model) - .setCharacteristic(this.platform.Characteristic.SerialNumber, accessory.context.deviceID ?? rainbird!.serialNumber) - .setCharacteristic(this.platform.Characteristic.FirmwareRevision, accessory.context.FirmwareRevision ?? rainbird!.version) - .getCharacteristic(this.platform.Characteristic.FirmwareRevision) - .updateValue(accessory.context.FirmwareRevision); + super(platform, accessory, device, rainbird); // Program Switch Service const name = `Program ${accessory.context.programId}`; @@ -65,7 +52,7 @@ export class ProgramSwitch { } private async setOn(value: CharacteristicValue) { - this.debugLog(`Program Switch: ${this.accessory.displayName}, Set On: ${value}`); + this.debugLog(`${this.constructor.name}: ${this.accessory.displayName}, Set On: ${value}`); this.programSwitch.state = value; if (value) { await this.rainbird!.startProgram(this.accessory.context.programId); @@ -86,7 +73,7 @@ export class ProgramSwitch { this.programSwitch.state = false; } } - this.debugLog(`Program Switch: ${this.accessory.displayName} On: ${this.programSwitch.state}`); + this.debugLog(`${this.constructor.name}: ${this.accessory.displayName} On: ${this.programSwitch.state}`); } /** @@ -94,71 +81,10 @@ export class ProgramSwitch { */ updateHomeKitCharacteristics() { if (this.programSwitch.state === undefined) { - this.debugLog(`Program Switch: ${this.accessory.displayName} On: ${this.programSwitch.state}`); + this.debugLog(`${this.constructor.name}: ${this.accessory.displayName} On: ${this.programSwitch.state}`); } else { this.programSwitch.service.updateCharacteristic(this.platform.Characteristic.On, this.programSwitch.state); - this.debugLog(`Program Switch: ${this.accessory.displayName} On: ${this.programSwitch.state}`); - } - } - - refreshRate(device: DevicesConfig) { - if (device.refreshRate) { - this.deviceRefreshRate = this.accessory.context.refreshRate = device.refreshRate; - this.debugLog(`Program Switch: ${this.accessory.displayName} Using Device Config refreshRate: ${this.deviceRefreshRate}`); - } else if (this.platform.config.options!.refreshRate) { - this.deviceRefreshRate = this.accessory.context.refreshRate = this.platform.config.options!.refreshRate; - this.debugLog(`Program Switch: ${this.accessory.displayName} Using Platform Config refreshRate: ${this.deviceRefreshRate}`); - } - } - - logs(device: DevicesConfig) { - if (this.platform.debugMode) { - this.deviceLogging = this.accessory.context.logging = 'debugMode'; - this.debugLog(`Program Switch: ${this.accessory.displayName} Using Debug Mode Logging: ${this.deviceLogging}`); - } else if (device.logging) { - this.deviceLogging = this.accessory.context.logging = device.logging; - this.debugLog(`Program Switch: ${this.accessory.displayName} Using Device Config Logging: ${this.deviceLogging}`); - } else if (this.platform.config.options?.logging) { - this.deviceLogging = this.accessory.context.logging = this.platform.config.options?.logging; - this.debugLog(`Program Switch: ${this.accessory.displayName} Using Platform Config Logging: ${this.deviceLogging}`); - } else { - this.deviceLogging = this.accessory.context.logging = 'standard'; - this.debugLog(`Program Switch: ${this.accessory.displayName} Logging Not Set, Using: ${this.deviceLogging}`); - } - } - - /** - * Logging for Device - */ - infoLog(...log: any[]) { - if (this.enablingDeviceLogging()) { - this.platform.log.info(String(...log)); + this.debugLog(`${this.constructor.name}: ${this.accessory.displayName} updateCharacteristic On: ${this.programSwitch.state}`); } } - - warnLog(...log: any[]) { - if (this.enablingDeviceLogging()) { - this.platform.log.warn(String(...log)); - } - } - - errorLog(...log: any[]) { - if (this.enablingDeviceLogging()) { - this.platform.log.error(String(...log)); - } - } - - debugLog(...log: any[]) { - if (this.enablingDeviceLogging()) { - if (this.deviceLogging === 'debug') { - this.platform.log.info('[DEBUG]', String(...log)); - } else { - this.platform.log.debug(String(...log)); - } - } - } - - enablingDeviceLogging(): boolean { - return this.deviceLogging.includes('debug') || this.deviceLogging === 'standard'; - } } diff --git a/src/devices/StopIrrigationSwitch.ts b/src/devices/StopIrrigationSwitch.ts index e6ad7a5..2342b30 100644 --- a/src/devices/StopIrrigationSwitch.ts +++ b/src/devices/StopIrrigationSwitch.ts @@ -3,34 +3,21 @@ import { RainbirdPlatform } from '../platform'; import { RainBirdService } from '../RainBird/RainBirdService'; import { fromEvent } from 'rxjs'; import { DevicesConfig } from '../settings'; +import { DeviceBase } from './DeviceBase'; -export class StopIrrigationSwitch { +export class StopIrrigationSwitch extends DeviceBase { private stopIrrigationSwitch!: { service: Service; state: CharacteristicValue; }; - // Config - deviceRefreshRate!: number; - deviceLogging!: string; - constructor( - private readonly platform: RainbirdPlatform, - private accessory: PlatformAccessory, - public device: DevicesConfig, - public rainbird: RainBirdService, + readonly platform: RainbirdPlatform, + accessory: PlatformAccessory, + device: DevicesConfig, + rainbird: RainBirdService, ) { - this.logs(device); - this.refreshRate(device); - // Set accessory information - accessory - .getService(this.platform.Service.AccessoryInformation)! - .setCharacteristic(this.platform.Characteristic.Manufacturer, 'RainBird') - .setCharacteristic(this.platform.Characteristic.Model, accessory.context.model ?? rainbird!.model) - .setCharacteristic(this.platform.Characteristic.SerialNumber, accessory.context.deviceID ?? rainbird!.serialNumber) - .setCharacteristic(this.platform.Characteristic.FirmwareRevision, accessory.context.FirmwareRevision ?? rainbird!.version) - .getCharacteristic(this.platform.Characteristic.FirmwareRevision) - .updateValue(accessory.context.FirmwareRevision); + super(platform, accessory, device, rainbird); // Stop Irrigation Switch Service const name = 'Stop Irrigation'; @@ -67,7 +54,7 @@ export class StopIrrigationSwitch { } private async setOn(value: CharacteristicValue) { - this.debugLog(`Stop Irrigation Switch: ${this.accessory.displayName}, Set On: ${value}`); + this.debugLog(`${this.constructor.name}: ${this.accessory.displayName}, Set On: ${value}`); if (value) { this.rainbird!.deactivateAllZones(); await this.rainbird!.stopIrrigation(); @@ -81,7 +68,7 @@ export class StopIrrigationSwitch { * Parse the device status from the RainbirdClient */ parseStatus() { - this.debugLog(`Stop Irrigation Switch: ${this.accessory.displayName} On: ${this.stopIrrigationSwitch.state}`); + this.debugLog(`${this.constructor.name}: ${this.accessory.displayName} On: ${this.stopIrrigationSwitch.state}`); } /** @@ -89,71 +76,10 @@ export class StopIrrigationSwitch { */ updateHomeKitCharacteristics() { if (this.stopIrrigationSwitch.state === undefined) { - this.debugLog(`Stop Irrigation Switch: ${this.accessory.displayName} On: ${this.stopIrrigationSwitch.state}`); + this.debugLog(`${this.constructor.name}: ${this.accessory.displayName} On: ${this.stopIrrigationSwitch.state}`); } else { this.stopIrrigationSwitch.service.updateCharacteristic(this.platform.Characteristic.On, this.stopIrrigationSwitch.state); - this.debugLog(`Stop Irrigation Switch: ${this.accessory.displayName} On: ${this.stopIrrigationSwitch.state}`); - } - } - - refreshRate(device: DevicesConfig) { - if (device.refreshRate) { - this.deviceRefreshRate = this.accessory.context.refreshRate = device.refreshRate; - this.debugLog(`Stop Irrigation Switch: ${this.accessory.displayName} Using Device Config refreshRate: ${this.deviceRefreshRate}`); - } else if (this.platform.config.options!.refreshRate) { - this.deviceRefreshRate = this.accessory.context.refreshRate = this.platform.config.options!.refreshRate; - this.debugLog(`Stop Irrigation Switch: ${this.accessory.displayName} Using Platform Config refreshRate: ${this.deviceRefreshRate}`); - } - } - - logs(device: DevicesConfig) { - if (this.platform.debugMode) { - this.deviceLogging = this.accessory.context.logging = 'debugMode'; - this.debugLog(`Stop Irrigation Switch: ${this.accessory.displayName} Using Debug Mode Logging: ${this.deviceLogging}`); - } else if (device.logging) { - this.deviceLogging = this.accessory.context.logging = device.logging; - this.debugLog(`Stop Irrigation Switch: ${this.accessory.displayName} Using Device Config Logging: ${this.deviceLogging}`); - } else if (this.platform.config.options?.logging) { - this.deviceLogging = this.accessory.context.logging = this.platform.config.options?.logging; - this.debugLog(`Stop Irrigation Switch: ${this.accessory.displayName} Using Platform Config Logging: ${this.deviceLogging}`); - } else { - this.deviceLogging = this.accessory.context.logging = 'standard'; - this.debugLog(`Stop Irrigation Switch: ${this.accessory.displayName} Logging Not Set, Using: ${this.deviceLogging}`); - } - } - - /** - * Logging for Device - */ - infoLog(...log: any[]) { - if (this.enablingDeviceLogging()) { - this.platform.log.info(String(...log)); - } - } - - warnLog(...log: any[]) { - if (this.enablingDeviceLogging()) { - this.platform.log.warn(String(...log)); - } - } - - errorLog(...log: any[]) { - if (this.enablingDeviceLogging()) { - this.platform.log.error(String(...log)); - } - } - - debugLog(...log: any[]) { - if (this.enablingDeviceLogging()) { - if (this.deviceLogging === 'debug') { - this.platform.log.info('[DEBUG]', String(...log)); - } else { - this.platform.log.debug(String(...log)); - } + this.debugLog(`${this.constructor.name}: ${this.accessory.displayName} updateCharacteristic On: ${this.stopIrrigationSwitch.state}`); } } - - enablingDeviceLogging(): boolean { - return this.deviceLogging.includes('debug') || this.deviceLogging === 'standard'; - } } diff --git a/src/devices/ZoneValve.ts b/src/devices/ZoneValve.ts new file mode 100644 index 0000000..05b5465 --- /dev/null +++ b/src/devices/ZoneValve.ts @@ -0,0 +1,208 @@ +import { Service, PlatformAccessory, CharacteristicValue, UnknownContext } from 'homebridge'; +import { RainbirdPlatform } from '../platform'; +import { RainBirdService } from '../RainBird/RainBirdService'; +import { fromEvent, interval, Subject } from 'rxjs'; +import { debounceTime, skipWhile, tap } from 'rxjs/operators'; +import { DevicesConfig } from '../settings'; +import { DeviceBase } from './DeviceBase'; + +export class ZoneValve extends DeviceBase { + private zoneId: number; + private zoneValve!: { + service: Service; + Active: CharacteristicValue; + InUse: CharacteristicValue; + }; + + // Zone Valve Updates + private zoneUpdateInProgress!: boolean; + private doZoneUpdate: Subject; + + constructor( + readonly platform: RainbirdPlatform, + accessory: PlatformAccessory, + device: DevicesConfig, + rainbird: RainBirdService, + private irrigationContext: UnknownContext, + ) { + super(platform, accessory, device, rainbird); + this.zoneId = this.accessory.context.zoneId; + + // this is subject we use to track when we need to send changes to Rainbird Client + this.doZoneUpdate = new Subject(); + this.zoneUpdateInProgress = false; + + if (irrigationContext.duration[this.zoneId] === undefined) { + irrigationContext.duration[this.zoneId] = 300; + } + + // Zone Valve Service + const name = `Zone ${accessory.context.zoneId}`; + this.debugLog(`Load Valve Service for ${name}`); + this.zoneValve = { + service: this.accessory.getService(this.platform.Service.Valve) ?? this.accessory.addService(this.platform.Service.Valve), + Active: this.platform.Characteristic.Active.INACTIVE, + InUse: this.platform.Characteristic.InUse.NOT_IN_USE, + }; + + // Add Valve's Characteristics + this.zoneValve.service + .setCharacteristic(this.platform.Characteristic.Active, this.zoneValve.Active) + .setCharacteristic(this.platform.Characteristic.InUse, this.zoneValve.InUse) + .setCharacteristic(this.platform.Characteristic.ValveType, this.platform.Characteristic.ValveType.IRRIGATION) + .setCharacteristic(this.platform.Characteristic.Name, name) + .setCharacteristic(this.platform.Characteristic.RemainingDuration, 0) + .setCharacteristic(this.platform.Characteristic.SetDuration, irrigationContext.duration[this.zoneId]) + .setCharacteristic(this.platform.Characteristic.StatusFault, this.platform.Characteristic.StatusFault.NO_FAULT); + + this.zoneValve.service + .getCharacteristic(this.platform.Characteristic.Active) + .onGet(() => { + this.rainbird!.refreshStatus(); + return this.zoneValve.Active; + }) + .onSet(this.setActive.bind(this)); + + this.zoneValve.service + .getCharacteristic(this.platform.Characteristic.InUse) + .onGet(() => { + this.rainbird!.refreshStatus(); + return this.zoneValve.InUse; + }); + + this.zoneValve.service + .getCharacteristic(this.platform.Characteristic.ValveType) + .onGet(() => { + return this.zoneValve.service.getCharacteristic(this.platform.Characteristic.ValveType).value; + }); + + this.zoneValve.service + .getCharacteristic(this.platform.Characteristic.RemainingDuration) + .onGet(() => { + this.rainbird!.refreshStatus(); + return this.rainbird!.RemainingDuration(this.zoneId); + }); + + this.zoneValve.service + .getCharacteristic(this.platform.Characteristic.SetDuration) + .onGet(() => { + return Number(irrigationContext.duration[this.zoneId]); + }) + .onSet(this.setSetDuration.bind(this)); + + this.zoneValve.service + .getCharacteristic(this.platform.Characteristic.StatusFault) + .onGet(() => { + return this.zoneValve.service.getCharacteristic(this.platform.Characteristic.StatusFault).value; + }); + + // Initial Device Parse + this.parseStatus(); + this.updateHomeKitCharacteristics(); + + // Device Parse when status event emitted + fromEvent(rainbird!, 'status').subscribe({ + next: () => { + this.parseStatus(); + this.updateHomeKitCharacteristics(); + }, + }); + + // Start an update interval + interval(this.platform.config.options!.refreshRate! * 1000) + .pipe(skipWhile(() => this.zoneUpdateInProgress)) + .subscribe(() => { + this.rainbird!.refreshStatus(); + }); + + this.doZoneUpdate + .pipe( + tap(() => { + this.zoneUpdateInProgress = true; + }), + debounceTime(this.platform.config.options!.pushRate! * 1000), + ) + .subscribe(async (zone: number) => { + try { + await this.pushChanges(zone); + } catch (e: any) { + this.debugLog(`${this.constructor.name}: ${this.accessory.displayName} - ${JSON.stringify(e.messsage)}`); + if (this.deviceLogging.includes('debug')) { + this.debugLog(`${this.constructor.name}: ${this.accessory.displayName} - ${JSON.stringify(e)}`); + } + } + this.zoneUpdateInProgress = false; + }); + } + + async pushChanges(zone: number): Promise { + if (this.zoneValve.Active === this.platform.Characteristic.Active.ACTIVE) { + this.rainbird!.activateZone(zone, this.irrigationContext.duration[this.zoneId]); + } else { + await this.rainbird!.deactivateZone(zone); + } + + this.debugLog( + `${this.constructor.name}: ${this.accessory.displayName}, pushChanges: [Valve: ${zone},` + + ` Active: ${this.zoneValve.Active}, SetDuration: ${this.irrigationContext.duration[this.zoneId]}]`, + ); + } + + private async setActive(value: CharacteristicValue) { + this.debugLog(`${this.constructor.name}: ${this.accessory.displayName}, Set Active: ${value}`); + this.zoneValve.Active = value; + this.doZoneUpdate.next(this.zoneId); + } + + private async setSetDuration(value: CharacteristicValue) { + this.debugLog(`${this.constructor.name}: ${this.accessory.displayName}, Set SetDuration: ${value}`); + this.irrigationContext.duration[this.zoneId] = value; + } + + /** + * Parse the device status from the RainbirdClient + */ + parseStatus() { + this.zoneValve.Active = this.rainbird!.isActive(this.zoneId) + ? this.platform.Characteristic.Active.ACTIVE + : this.platform.Characteristic.Active.INACTIVE; + + this.zoneValve.InUse = this.rainbird!.isInUse(this.zoneId) + ? this.platform.Characteristic.InUse.IN_USE + : this.platform.Characteristic.InUse.NOT_IN_USE; + + this.debugLog(`${this.constructor.name}: ${this.zoneId}, Active: ${this.zoneValve.Active}, InUse: ${this.zoneValve.InUse}`); + } + + /** + * Updates the status for each of the HomeKit Characteristics + */ + updateHomeKitCharacteristics() { + if (this.zoneValve.Active === undefined) { + this.debugLog(`${this.constructor.name}: ${this.accessory.displayName} Active: ${this.zoneValve.Active}`); + } else { + this.zoneValve.service.updateCharacteristic(this.platform.Characteristic.Active, this.zoneValve.Active); + this.debugLog(`${this.constructor.name}: ${this.accessory.displayName} updateCharacteristic Active: ${this.zoneValve.Active}`); + } + if (this.zoneValve.InUse === undefined) { + this.debugLog(`${this.constructor.name}: ${this.accessory.displayName} InUse: ${this.zoneValve.InUse}`); + } else { + this.zoneValve.service.updateCharacteristic(this.platform.Characteristic.InUse, this.zoneValve.InUse); + this.debugLog(`${this.constructor.name}: ${this.accessory.displayName} updateCharacteristic InUse: ${this.zoneValve.InUse}`); + } + const remainingDuration = this.rainbird!.RemainingDuration(this.zoneId); + if (remainingDuration === undefined) { + this.debugLog(`${this.constructor.name}: ${this.accessory.displayName} RemainingDuration: ${remainingDuration}`); + } else { + this.zoneValve.service.updateCharacteristic(this.platform.Characteristic.RemainingDuration, remainingDuration); + this.debugLog(`${this.constructor.name}: ${this.accessory.displayName} updateCharacteristic RemainingDuration: ${remainingDuration}`); + } + if (this.irrigationContext.duration[this.zoneId] === undefined) { + this.debugLog(`${this.constructor.name}: ${this.accessory.displayName} SetDuration: ${this.irrigationContext.duration[this.zoneId]}`); + } else { + this.zoneValve.service.updateCharacteristic(this.platform.Characteristic.SetDuration, this.irrigationContext.duration[this.zoneId]); + this.debugLog( + `${this.constructor.name}: ${this.accessory.displayName} updateCharacteristic SetDuration: ${this.irrigationContext.duration[this.zoneId]}`); + } + } +} diff --git a/src/platform.ts b/src/platform.ts index 3338169..a472c4c 100644 --- a/src/platform.ts +++ b/src/platform.ts @@ -6,6 +6,7 @@ import { ContactSensor } from './devices/ContactSensor'; import { LeakSensor } from './devices/LeakSensor'; import { ProgramSwitch } from './devices/ProgramSwitch'; import { StopIrrigationSwitch } from './devices/StopIrrigationSwitch'; +import { ZoneValve } from './devices/ZoneValve'; /** * HomebridgePlatform @@ -135,6 +136,7 @@ export class RainbirdPlatform implements DynamicPlatformPlugin { device.showProgramBSwitch = device.showProgramBSwitch ?? false; device.showProgramCSwitch = device.showProgramCSwitch ?? false; device.showStopIrrigationSwitch = device.showStopIrrigationSwitch ?? false; + device.showZoneValve = device.showZoneValve ?? false; device.showRequestResponse = device.showRequestResponse ?? false; } } @@ -164,6 +166,7 @@ export class RainbirdPlatform implements DynamicPlatformPlugin { for (const zoneId of metaData.zones) { const configured = irrigationAccessory!.context.configured[zoneId] ?? this.Characteristic.IsConfigured.CONFIGURED; if (configured === this.Characteristic.IsConfigured.CONFIGURED) { + this.createZoneValve(device, rainbird, zoneId); this.createContactSensor(device, rainbird, zoneId); } } @@ -176,14 +179,10 @@ export class RainbirdPlatform implements DynamicPlatformPlugin { rainbird.on('zone_enable', (zoneId, enabled) => { if (enabled) { this.createContactSensor(device, rainbird, zoneId); + this.createZoneValve(device, rainbird, zoneId); } else { - const model = `${rainbird!.model}-${zoneId}`; - const uuid = this.api.hap.uuid.generate(`${device.ipaddress}-${model}-${rainbird!.serialNumber}`); - const index = this.accessories.findIndex((accessory) => accessory.UUID === uuid); - if (index >= 0) { - this.unregisterPlatformAccessories(this.accessories[index]); - this.accessories.splice(index, 1); - } + this.removeContactSensor(device, rainbird, zoneId); + this.removeZoneValve(device, rainbird, zoneId); } }); } @@ -298,6 +297,75 @@ export class RainbirdPlatform implements DynamicPlatformPlugin { } } + createZoneValve(device: DevicesConfig, rainbird: RainBirdService, zoneId: number): void { + const model = `${rainbird!.model}-valve-${zoneId}`; + const uuid = this.api.hap.uuid.generate(`${device.ipaddress}-${model}-${rainbird!.serialNumber}`); + const name = `Zone ${zoneId}`; + // see if an accessory with the same uuid has already been registered and restored from + // the cached devices we stored in the `configureAccessory` method above + const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid); + + const irrigationUuid = this.api.hap.uuid.generate(`${device.ipaddress}-${rainbird!.model}-${rainbird!.serialNumber}`); + const irrigationAccessory = this.accessories.find((accessory) => accessory.UUID === irrigationUuid); + + if (existingAccessory) { + // the accessory already exists + if (!this.config.disablePlugin && device.showZoneValve) { + this.infoLog(`Restoring existing accessory from cache: ${existingAccessory.displayName}`); + + // if you need to update the accessory.context then you should run `api.updatePlatformAccessories`. eg.: + existingAccessory.context.device = device; + existingAccessory.context.deviceID = rainbird!.serialNumber; + existingAccessory.context.model = model; + existingAccessory.context.FirmwareRevision = rainbird!.version; + existingAccessory.context.zoneId = zoneId; + this.api.updatePlatformAccessories([existingAccessory]); + // create the accessory handler for the restored accessory + // this is imported from `platformAccessory.ts` + new ZoneValve(this, existingAccessory, device, rainbird, irrigationAccessory!.context); + this.debugLog(`Zone Valve uuid: ${device.ipaddress}-${model}-${rainbird!.serialNumber}, (${existingAccessory.UUID})`); + } else { + this.unregisterPlatformAccessories(existingAccessory); + } + } else if (!this.config.disablePlugin && device.showZoneValve) { + // the accessory does not yet exist, so we need to create it + this.infoLog(`Adding new accessory: ${model}`); + + // create a new accessory + const accessory = new this.api.platformAccessory(name, uuid); + + // store a copy of the device object in the `accessory.context` + // the `context` property can be used to store any data about the accessory you may need + accessory.context.device = device; + accessory.context.deviceID = rainbird!.serialNumber; + accessory.context.model = model; + accessory.context.FirmwareRevision = rainbird!.version; + accessory.context.zoneId = zoneId; + // create the accessory handler for the newly create accessory + // this is imported from `platformAccessory.ts` + new ZoneValve(this, accessory, device, rainbird, irrigationAccessory!.context); + this.debugLog(`Valve Zone uuid: ${device.ipaddress}-${model}-${rainbird!.serialNumber}, (${accessory.UUID})`); + + // link the accessory to your platform + this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]); + this.accessories.push(accessory); + } else { + if (this.platformLogging === 'debug' && device.showZoneValve) { + this.errorLog(`Unable to Register new device: ${model}`); + } + } + } + + removeZoneValve(device: DevicesConfig, rainbird: RainBirdService, zoneId: number): void { + const model = `${rainbird!.model}-valve-${zoneId}`; + const uuid = this.api.hap.uuid.generate(`${device.ipaddress}-${model}-${rainbird!.serialNumber}`); + const index = this.accessories.findIndex((accessory) => accessory.UUID === uuid); + if (index >= 0) { + this.unregisterPlatformAccessories(this.accessories[index]); + this.accessories.splice(index, 1); + } + } + createContactSensor(device: DevicesConfig, rainbird: RainBirdService, zoneId: number): void { const model = `${rainbird!.model}-${zoneId}`; const uuid = this.api.hap.uuid.generate(`${device.ipaddress}-${model}-${rainbird!.serialNumber}`); @@ -354,6 +422,16 @@ export class RainbirdPlatform implements DynamicPlatformPlugin { } } + removeContactSensor(device: DevicesConfig, rainbird: RainBirdService, zoneId: number): void { + const model = `${rainbird!.model}-${zoneId}`; + const uuid = this.api.hap.uuid.generate(`${device.ipaddress}-${model}-${rainbird!.serialNumber}`); + const index = this.accessories.findIndex((accessory) => accessory.UUID === uuid); + if (index >= 0) { + this.unregisterPlatformAccessories(this.accessories[index]); + this.accessories.splice(index, 1); + } + } + createProgramSwitch(device: DevicesConfig, rainbird: RainBirdService, programId: string): void { const model = `${rainbird!.model}-pgm-${programId}`; const uuid = this.api.hap.uuid.generate(`${device.ipaddress}-${model}-${rainbird!.serialNumber}`); diff --git a/src/settings.ts b/src/settings.ts index c3df8fc..4370eef 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -25,6 +25,7 @@ export type DevicesConfig = { showProgramBSwitch?: boolean; showProgramCSwitch?: boolean; showStopIrrigationSwitch?: boolean; + showZoneValve?: boolean; refreshRate?: number; showRequestResponse?: boolean; logging?: string;